Repository: berachain/beacon-kit Branch: main Commit: a70a4f306da0 Files: 804 Total size: 53.1 MB Directory structure: gitextract_6zu1j5o0/ ├── .dockerignore ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── berachain_release.asc │ ├── docker-nightly-preconf.yml │ ├── pipeline.yml │ ├── release.yaml │ └── vuln-and-dep-check.yml ├── .gitignore ├── .gitmodules ├── .golangci.yaml ├── .mockery.yaml ├── .vscode/ │ ├── launch.json │ └── tasks.json ├── CLAUDE.md ├── CODEOWNERS ├── Dockerfile ├── LICENSE ├── LICENSE.header ├── Makefile ├── README.md ├── beacon/ │ ├── blockchain/ │ │ ├── common.go │ │ ├── deposit.go │ │ ├── errors.go │ │ ├── execution_engine.go │ │ ├── finalize_block.go │ │ ├── init_chain.go │ │ ├── interfaces.go │ │ ├── metrics.go │ │ ├── mocks/ │ │ │ ├── genesis_state_processor.mock.go │ │ │ ├── local_builder.mock.go │ │ │ └── storage_backend.mock.go │ │ ├── payload.go │ │ ├── payload_test.go │ │ ├── process_proposal.go │ │ ├── pruning.go │ │ └── service.go │ ├── payload-time/ │ │ ├── time.go │ │ └── time_test.go │ └── validator/ │ ├── block_builder.go │ ├── config.go │ ├── errors.go │ ├── interfaces.go │ ├── metrics.go │ └── service.go ├── chain/ │ ├── chain_ids.go │ ├── data.go │ ├── errors.go │ ├── helpers.go │ ├── helpers_test.go │ ├── spec.go │ └── spec_test.go ├── cli/ │ ├── builder/ │ │ ├── builder.go │ │ ├── config.go │ │ └── options.go │ ├── commands/ │ │ ├── deposit/ │ │ │ ├── commands.go │ │ │ ├── commands_test.go │ │ │ ├── create.go │ │ │ ├── db_check.go │ │ │ ├── errors.go │ │ │ ├── interfaces.go │ │ │ ├── keys.go │ │ │ ├── utils.go │ │ │ └── validate.go │ │ ├── genesis/ │ │ │ ├── collect.go │ │ │ ├── deposit.go │ │ │ ├── deposit_test.go │ │ │ ├── genesis.go │ │ │ ├── interfaces.go │ │ │ ├── payload.go │ │ │ ├── root.go │ │ │ ├── storage.go │ │ │ ├── storage_test.go │ │ │ └── types/ │ │ │ ├── constants.go │ │ │ └── json.go │ │ ├── initialize/ │ │ │ └── initialize.go │ │ ├── jwt/ │ │ │ ├── errors.go │ │ │ ├── jwt.go │ │ │ └── jwt_test.go │ │ ├── root.go │ │ ├── server/ │ │ │ ├── cmd/ │ │ │ │ └── execute.go │ │ │ ├── pruning.go │ │ │ ├── rollback.go │ │ │ ├── start.go │ │ │ └── types/ │ │ │ └── types.go │ │ └── setup.go │ ├── components/ │ │ ├── client_context.go │ │ ├── defaults.go │ │ └── logger.go │ ├── config/ │ │ ├── app.go │ │ ├── client.go │ │ ├── comet.go │ │ ├── errors.go │ │ └── server.go │ ├── context/ │ │ ├── cmd.go │ │ └── keys.go │ ├── flags/ │ │ └── flags.go │ └── utils/ │ ├── genesis/ │ │ ├── interfaces.go │ │ ├── root.go │ │ └── root_test.go │ └── parser/ │ ├── errors.go │ └── validator.go ├── cmd/ │ └── beacond/ │ ├── defaults.go │ └── main.go ├── codecov.yml ├── config/ │ ├── config/ │ │ ├── config.go │ │ ├── config.toml.tpl │ │ └── toml.go │ ├── config.go │ ├── spec/ │ │ ├── creator.go │ │ ├── creator_test.go │ │ ├── defaults.go │ │ ├── defaults_test.go │ │ ├── devnet.go │ │ ├── mainnet.go │ │ └── testnet.go │ ├── template/ │ │ └── template.go │ └── viper/ │ └── parser.go ├── consensus/ │ ├── cometbft/ │ │ ├── cli/ │ │ │ └── commands.go │ │ └── service/ │ │ ├── abci.go │ │ ├── abci_utils.go │ │ ├── cache/ │ │ │ ├── cache.go │ │ │ ├── cache_test.go │ │ │ └── state.go │ │ ├── commit.go │ │ ├── configs.go │ │ ├── configs_test.go │ │ ├── delay/ │ │ │ ├── config.go │ │ │ ├── delay.go │ │ │ ├── delay_test.go │ │ │ └── errors.go │ │ ├── encoding/ │ │ │ ├── encoding.go │ │ │ ├── errors.go │ │ │ └── interfaces.go │ │ ├── finalize_block.go │ │ ├── genesis.go │ │ ├── init_chain.go │ │ ├── interfaces.go │ │ ├── log/ │ │ │ ├── cmt_logger.go │ │ │ └── sdk_logger.go │ │ ├── node_api_support.go │ │ ├── options.go │ │ ├── prepare_proposal.go │ │ ├── process_proposal.go │ │ ├── service.go │ │ └── state/ │ │ └── state.go │ └── types/ │ ├── common.go │ ├── consensus_block.go │ └── slot_data.go ├── consensus-types/ │ └── types/ │ ├── attestation_data.go │ ├── attestation_data_test.go │ ├── attester_slashings.go │ ├── attestions.go │ ├── block.go │ ├── block_test.go │ ├── bls_to_execution_changes.go │ ├── body.go │ ├── body_test.go │ ├── consolidation_request.go │ ├── consolidation_request_test.go │ ├── deposit.go │ ├── deposit_message.go │ ├── deposit_message_test.go │ ├── deposit_request.go │ ├── deposit_request_test.go │ ├── deposit_test.go │ ├── deposits.go │ ├── errors.go │ ├── eth1data.go │ ├── eth1data_test.go │ ├── execution_requests.go │ ├── execution_requests_test.go │ ├── fork.go │ ├── fork_data.go │ ├── fork_data_test.go │ ├── fork_test.go │ ├── genesis.go │ ├── genesis_test.go │ ├── header.go │ ├── header_test.go │ ├── interfaces.go │ ├── mocks/ │ │ ├── blobs_bundle.mock.go │ │ ├── built_execution_payload_env.mock.go │ │ ├── new_payload_request.mock.go │ │ ├── proposer_domain.mock.go │ │ └── unused_enforcer.mock.go │ ├── payload.go │ ├── payload_env.go │ ├── payload_header.go │ ├── payload_header_test.go │ ├── payload_requests.go │ ├── payload_requests_test.go │ ├── payload_test.go │ ├── pending_partial_withdrawal.go │ ├── pending_partial_withdrawal_test.go │ ├── proposer_slashings.go │ ├── signed_beacon_block.go │ ├── signed_beacon_block_header.go │ ├── signed_beacon_block_header_test.go │ ├── signed_beacon_block_test.go │ ├── signing_data.go │ ├── signing_data_test.go │ ├── slashing_info.go │ ├── slashing_info_test.go │ ├── state.go │ ├── state_test.go │ ├── sync_aggregate.go │ ├── validator.go │ ├── validator_test.go │ ├── validators.go │ ├── versionable.go │ ├── voluntary_exits.go │ ├── withdrawal_credentials.go │ ├── withdrawal_credentials_test.go │ ├── withdrawal_request.go │ └── withdrawals_request_test.go ├── contracts/ │ ├── .gas-snapshot │ ├── Makefile │ ├── README.md │ ├── foundry.toml │ ├── remappings.txt │ ├── slither.config.json │ ├── src/ │ │ ├── brip0004/ │ │ │ ├── MockPoL.sol │ │ │ ├── MockPoLGasEnforcer.sol │ │ │ ├── MockPoLReverting.sol │ │ │ └── MockValidatorRegistry.sol │ │ ├── eip4399/ │ │ │ └── RandaoTester.sol │ │ ├── eip4788/ │ │ │ ├── README.md │ │ │ ├── SSZ.sol │ │ │ └── deployment.json │ │ └── staking/ │ │ ├── DepositContract.sol │ │ ├── IDepositContract.sol │ │ └── IERC165.sol │ └── test/ │ └── staking/ │ └── DepositContract.t.sol ├── da/ │ ├── blob/ │ │ ├── factory.go │ │ ├── factory_metrics.go │ │ ├── factory_test.go │ │ ├── interfaces.go │ │ ├── processor.go │ │ ├── processor_metrics.go │ │ ├── verifier.go │ │ └── verifier_metrics.go │ ├── kzg/ │ │ ├── config.go │ │ ├── config_test.go │ │ ├── errors.go │ │ ├── gokzg/ │ │ │ ├── gokzg.go │ │ │ └── gokzg_test.go │ │ ├── noop/ │ │ │ ├── noop.go │ │ │ └── noop_test.go │ │ ├── proof.go │ │ ├── proof_test.go │ │ └── types/ │ │ └── args.go │ ├── store/ │ │ ├── errors.go │ │ ├── interfaces.go │ │ ├── store.go │ │ └── store_test.go │ └── types/ │ ├── errors.go │ ├── sidecar.go │ ├── sidecar_test.go │ ├── sidecars.go │ └── sidecars_test.go ├── docs/ │ └── .gitkeep ├── engine-primitives/ │ ├── engine-primitives/ │ │ ├── attributes.go │ │ ├── attributes_test.go │ │ ├── blobs_bundle.go │ │ ├── blobs_bundle_test.go │ │ ├── engine.go │ │ ├── engine_test.go │ │ ├── errors.go │ │ ├── mocks/ │ │ │ ├── blobs_bundle.mock.go │ │ │ └── payload_attributer.mock.go │ │ ├── transactions.go │ │ ├── transactions_test.go │ │ ├── withdrawal.go │ │ ├── withdrawal_ssz_test.go │ │ ├── withdrawal_test.go │ │ ├── withdrawals.go │ │ └── withdrawals_test.go │ └── errors/ │ └── errors.go ├── errors/ │ └── mod.go ├── execution/ │ ├── README.md │ ├── client/ │ │ ├── client.go │ │ ├── config.go │ │ ├── engine.go │ │ ├── errors.go │ │ ├── ethclient/ │ │ │ ├── constants.go │ │ │ ├── engine.go │ │ │ ├── engine_test.go │ │ │ ├── errors.go │ │ │ ├── eth.go │ │ │ ├── ethclient.go │ │ │ └── rpc/ │ │ │ ├── client.go │ │ │ ├── errors.go │ │ │ ├── header.go │ │ │ └── types.go │ │ ├── helpers.go │ │ ├── interfaces.go │ │ └── metrics.go │ ├── deposit/ │ │ ├── contract.go │ │ └── interfaces.go │ ├── engine/ │ │ ├── engine.go │ │ ├── errors.go │ │ ├── interfaces.go │ │ └── metrics.go │ └── requests/ │ ├── eip7002/ │ │ ├── interfaces.go │ │ ├── withdrawal.go │ │ └── withdrawal_test.go │ └── eip7251/ │ ├── consolidation.go │ └── interfaces.go ├── gethlib/ │ ├── deposit/ │ │ ├── contract.abigen.go │ │ └── contract.go │ ├── ethclient/ │ │ ├── ethclient.go │ │ └── ethclient_test.go │ ├── ssztest/ │ │ ├── contract.abigen.go │ │ └── contract.go │ └── types/ │ ├── block.go │ ├── config.go │ ├── genesis.go │ ├── header.go │ ├── pubkey.go │ ├── transaction.go │ ├── transaction_marshalling.go │ ├── tx_types.go │ └── utils.go ├── go.mod ├── go.sum ├── kurtosis/ │ ├── Makefile │ ├── README.md │ ├── beaconkit-cloud.yaml │ ├── beaconkit-local.yaml │ ├── kurtosis-params.yaml │ ├── kurtosis.yml │ ├── main.star │ └── src/ │ ├── constants.star │ ├── lib/ │ │ ├── bash.star │ │ ├── builtins.star │ │ ├── helpers.star │ │ ├── port_spec.star │ │ └── service_config.star │ ├── networks/ │ │ ├── kurtosis-devnet/ │ │ │ ├── README.md │ │ │ └── network-configs/ │ │ │ └── genesis.json.template │ │ ├── networks.star │ │ └── private-testnet-1/ │ │ └── .gitkeep │ ├── nodes/ │ │ ├── consensus/ │ │ │ ├── beacond/ │ │ │ │ ├── launcher.star │ │ │ │ ├── node.star │ │ │ │ └── scripts/ │ │ │ │ ├── modify-genesis-with-deposits.sh │ │ │ │ └── multiple-premined-deposits-cl.sh │ │ │ └── types.star │ │ ├── execution/ │ │ │ ├── config.star │ │ │ ├── execution.star │ │ │ └── reth/ │ │ │ ├── config.star │ │ │ └── reth-config.toml │ │ ├── jwt-secret.hex │ │ ├── kzg-trusted-setup.json │ │ └── nodes.star │ ├── observability/ │ │ ├── grafana/ │ │ │ ├── dashboard-providers.yml.tmpl │ │ │ ├── datasource.yml.tmpl │ │ │ └── grafana.star │ │ ├── prometheus/ │ │ │ └── prometheus.star │ │ └── pyroscope/ │ │ └── pyroscope.star │ └── services/ │ ├── blockscout/ │ │ └── launcher.star │ ├── service.star │ ├── spamoor/ │ │ └── launcher.star │ └── tx_fuzz/ │ └── launcher.star ├── log/ │ ├── mod.go │ ├── noop/ │ │ ├── noop.go │ │ └── noop_test.go │ └── phuslu/ │ ├── buffer.go │ ├── config.go │ ├── formatter.go │ ├── logger.go │ ├── style.go │ └── time.go ├── node-api/ │ ├── backend/ │ │ ├── backend.go │ │ ├── backend_test.go │ │ ├── getters.go │ │ ├── interface.go │ │ └── mocks/ │ │ └── genesis_state_processor.mock.go │ ├── handlers/ │ │ ├── beacon/ │ │ │ ├── backend.go │ │ │ ├── blob_test.go │ │ │ ├── blobs.go │ │ │ ├── block.go │ │ │ ├── genesis.go │ │ │ ├── genesis_test.go │ │ │ ├── handler.go │ │ │ ├── header.go │ │ │ ├── header_test.go │ │ │ ├── historical.go │ │ │ ├── mocks/ │ │ │ │ └── backend.mock.go │ │ │ ├── randao.go │ │ │ ├── randao_test.go │ │ │ ├── routes.go │ │ │ ├── types/ │ │ │ │ ├── conversions.go │ │ │ │ ├── request.go │ │ │ │ └── response.go │ │ │ ├── validators.go │ │ │ ├── validators_balances.go │ │ │ ├── validators_balances_test.go │ │ │ ├── validators_filters.go │ │ │ ├── validators_filters_test.go │ │ │ ├── validators_test.go │ │ │ ├── withdrawal.go │ │ │ └── withdrawal_test.go │ │ ├── builder/ │ │ │ ├── handler.go │ │ │ └── routes.go │ │ ├── cometbft/ │ │ │ ├── backend.go │ │ │ ├── block.go │ │ │ ├── cometbft_test.go │ │ │ ├── handler.go │ │ │ ├── mocks/ │ │ │ │ └── backend.mock.go │ │ │ ├── routes.go │ │ │ ├── signed_header.go │ │ │ └── types.go │ │ ├── config/ │ │ │ ├── handler.go │ │ │ ├── routes.go │ │ │ ├── spec.go │ │ │ └── types/ │ │ │ └── response.go │ │ ├── debug/ │ │ │ ├── backend.go │ │ │ ├── handler.go │ │ │ ├── routes.go │ │ │ └── state.go │ │ ├── error.go │ │ ├── events/ │ │ │ ├── handler.go │ │ │ └── routes.go │ │ ├── handlers.go │ │ ├── node/ │ │ │ ├── backend.go │ │ │ ├── handler.go │ │ │ ├── mocks/ │ │ │ │ └── backend.mock.go │ │ │ ├── node.go │ │ │ ├── node_test.go │ │ │ ├── routes.go │ │ │ └── types/ │ │ │ └── response.go │ │ ├── proof/ │ │ │ ├── backend.go │ │ │ ├── block_proposer.go │ │ │ ├── handler.go │ │ │ ├── merkle/ │ │ │ │ ├── beacon_state.go │ │ │ │ ├── beacon_state_test.go │ │ │ │ ├── generalized_indexes.go │ │ │ │ ├── generalized_indexes_test.go │ │ │ │ ├── merkle_test.go │ │ │ │ ├── mock/ │ │ │ │ │ └── beacon_state.go │ │ │ │ ├── proposer_index.go │ │ │ │ ├── proposer_index_test.go │ │ │ │ ├── testdata/ │ │ │ │ │ ├── empty_state_proof.json │ │ │ │ │ ├── many_validators_proposer_index_proof.json │ │ │ │ │ ├── many_validators_proposer_pubkey_proof_deneb.json │ │ │ │ │ ├── many_validators_proposer_pubkey_proof_electra.json │ │ │ │ │ ├── many_validators_validator_balance_proof.json │ │ │ │ │ ├── many_validators_validator_credentials_proof.json │ │ │ │ │ ├── non_empty_state_proof.json │ │ │ │ │ ├── one_validator_proposer_index_proof.json │ │ │ │ │ ├── one_validator_proposer_pubkey_proof_deneb.json │ │ │ │ │ ├── one_validator_proposer_pubkey_proof_electra.json │ │ │ │ │ ├── one_validator_validator_balance_proof.json │ │ │ │ │ └── one_validator_validator_credentials_proof.json │ │ │ │ ├── validator_balance.go │ │ │ │ ├── validator_balance_test.go │ │ │ │ ├── validator_credentials.go │ │ │ │ ├── validator_credentials_test.go │ │ │ │ ├── validator_pubkey.go │ │ │ │ └── validator_pubkey_test.go │ │ │ ├── routes.go │ │ │ ├── types/ │ │ │ │ ├── interfaces.go │ │ │ │ ├── request.go │ │ │ │ └── response.go │ │ │ ├── validator_balance.go │ │ │ ├── validator_credentials.go │ │ │ └── validator_pubkey.go │ │ ├── routes.go │ │ ├── types/ │ │ │ ├── errors.go │ │ │ └── request.go │ │ ├── utils/ │ │ │ ├── constants.go │ │ │ ├── context.go │ │ │ └── mappings.go │ │ └── validator/ │ │ ├── handler.go │ │ └── routes.go │ ├── middleware/ │ │ ├── middleware.go │ │ ├── request.go │ │ └── response.go │ └── server/ │ ├── config.go │ └── server.go ├── node-core/ │ ├── builder/ │ │ ├── baseapp_options.go │ │ ├── builder.go │ │ └── options.go │ ├── components/ │ │ ├── api.go │ │ ├── attributes_factory.go │ │ ├── availability_store.go │ │ ├── backend.go │ │ ├── blobs.go │ │ ├── block_store.go │ │ ├── chain_service.go │ │ ├── cometbft_service.go │ │ ├── config.go │ │ ├── config_server.go │ │ ├── deposit_contract.go │ │ ├── deposit_store.go │ │ ├── engine.go │ │ ├── interfaces.go │ │ ├── jwt_secret.go │ │ ├── metrics/ │ │ │ └── sink.go │ │ ├── node.go │ │ ├── payload_builder.go │ │ ├── reporting_service.go │ │ ├── service_registry.go │ │ ├── shutdown_service.go │ │ ├── sidecars.go │ │ ├── signer/ │ │ │ ├── errors.go │ │ │ ├── legacy.go │ │ │ └── signer.go │ │ ├── signer.go │ │ ├── state_processor.go │ │ ├── storage/ │ │ │ └── storage.go │ │ ├── store.go │ │ ├── telemetry_service.go │ │ ├── telemetry_sink.go │ │ ├── trusted_setup.go │ │ ├── types.go │ │ └── validator_service.go │ ├── node/ │ │ └── node.go │ ├── services/ │ │ ├── registry/ │ │ │ ├── errors.go │ │ │ ├── mocks/ │ │ │ │ ├── basic.mock.go │ │ │ │ ├── commit_multistore_accessor.mock.go │ │ │ │ ├── dispatcher.mock.go │ │ │ │ └── registry_option.mock.go │ │ │ ├── options.go │ │ │ ├── registry.go │ │ │ └── registry_test.go │ │ ├── shutdown/ │ │ │ └── service..go │ │ └── version/ │ │ ├── interfaces.go │ │ └── version.go │ └── types/ │ ├── mocks/ │ │ └── consensus_service.mock.go │ └── node.go ├── observability/ │ └── telemetry/ │ └── service.go ├── payload/ │ ├── README.md │ ├── attributes/ │ │ ├── factory.go │ │ └── interfaces.go │ ├── builder/ │ │ ├── builder.go │ │ ├── config.go │ │ ├── errors.go │ │ ├── interfaces.go │ │ ├── payload.go │ │ └── payload_test.go │ └── cache/ │ ├── payload_id.go │ ├── payload_id_fuzz_test.go │ └── payload_id_test.go ├── primitives/ │ ├── bytes/ │ │ ├── b.go │ │ ├── b20.go │ │ ├── b20_test.go │ │ ├── b256.go │ │ ├── b32.go │ │ ├── b32_test.go │ │ ├── b4.go │ │ ├── b48.go │ │ ├── b48_test.go │ │ ├── b4_test.go │ │ ├── b8.go │ │ ├── b8_test.go │ │ ├── b96.go │ │ ├── b96_test.go │ │ ├── b_test.go │ │ ├── buffer/ │ │ │ ├── buffer.go │ │ │ └── buffer_test.go │ │ └── utils.go │ ├── common/ │ │ ├── consensus.go │ │ ├── consensus_test.go │ │ ├── execution.go │ │ ├── execution_test.go │ │ ├── interfaces.go │ │ ├── unused_type.go │ │ └── unused_type_test.go │ ├── constants/ │ │ ├── bls12_381.go │ │ ├── constants.go │ │ ├── eip4844.go │ │ ├── misc.go │ │ ├── operations_per_block.go │ │ ├── payload.go │ │ └── validator.go │ ├── constraints/ │ │ └── ssz.go │ ├── crypto/ │ │ ├── bls.go │ │ ├── mocks/ │ │ │ └── bls_signer.mock.go │ │ └── sha256/ │ │ └── sha256.go │ ├── eip4844/ │ │ ├── blob.go │ │ ├── blob_test.go │ │ ├── kzg_commitment.go │ │ ├── kzg_commitment_test.go │ │ └── kzg_proof.go │ ├── encoding/ │ │ ├── hex/ │ │ │ ├── bytes.go │ │ │ ├── bytes_test.go │ │ │ ├── const.go │ │ │ ├── errors.go │ │ │ ├── format.go │ │ │ ├── format_test.go │ │ │ ├── nibble.go │ │ │ ├── u64.go │ │ │ └── u64_test.go │ │ ├── json/ │ │ │ └── json.go │ │ └── ssz/ │ │ ├── schema/ │ │ │ ├── common.go │ │ │ ├── definitions.go │ │ │ ├── field.go │ │ │ └── id.go │ │ └── utils.go │ ├── math/ │ │ ├── errors.go │ │ ├── log/ │ │ │ ├── log.go │ │ │ └── log_test.go │ │ ├── pow/ │ │ │ ├── pow.go │ │ │ └── pow_test.go │ │ ├── u256.go │ │ ├── u64.go │ │ └── u64_test.go │ ├── merkle/ │ │ ├── errors.go │ │ ├── hasher.go │ │ ├── hasher_fuzz_test.go │ │ ├── hasher_test.go │ │ ├── index.go │ │ ├── index_test.go │ │ ├── object_path.go │ │ ├── object_path_test.go │ │ ├── proof.go │ │ ├── root_hasher.go │ │ ├── root_hasher_test.go │ │ ├── tree.go │ │ ├── tree_fuzz_test.go │ │ ├── tree_test.go │ │ ├── utils.go │ │ └── zero/ │ │ └── zero.go │ ├── net/ │ │ ├── http/ │ │ │ └── errors.go │ │ ├── json-rpc/ │ │ │ └── errors.go │ │ ├── jwt/ │ │ │ ├── errors.go │ │ │ ├── jwt.go │ │ │ └── jwt_test.go │ │ └── url/ │ │ └── url.go │ ├── transition/ │ │ ├── context.go │ │ ├── validator_update.go │ │ └── validator_update_test.go │ └── version/ │ ├── comparable.go │ ├── comparable_test.go │ ├── name.go │ ├── supported.go │ └── versions.go ├── scripts/ │ ├── build/ │ │ ├── build.mk │ │ ├── codegen.mk │ │ ├── constants.mk │ │ ├── devtools.mk │ │ ├── golines.sh │ │ ├── help.mk │ │ ├── linting.mk │ │ ├── proto_generate_pulsar.sh │ │ ├── protobuf.mk │ │ ├── release.mk │ │ └── testing.mk │ └── rollback_cl.sh ├── state-transition/ │ └── core/ │ ├── README.md │ ├── core_test.go │ ├── errors.go │ ├── interfaces.go │ ├── metrics.go │ ├── mocks/ │ │ └── execution_engine.mock.go │ ├── state/ │ │ ├── constants.go │ │ ├── interfaces.go │ │ ├── metrics.go │ │ ├── parent_proposer_pubkey.go │ │ ├── statedb.go │ │ └── statedb_test.go │ ├── state_processor.go │ ├── state_processor_exits.go │ ├── state_processor_fixes.go │ ├── state_processor_forks.go │ ├── state_processor_genesis.go │ ├── state_processor_genesis_test.go │ ├── state_processor_payload.go │ ├── state_processor_payload_test.go │ ├── state_processor_randao.go │ ├── state_processor_signature.go │ ├── state_processor_staking.go │ ├── state_processor_staking_test.go │ ├── state_processor_test.go │ ├── state_processor_validators.go │ ├── state_processor_withdrawals.go │ ├── state_processor_withdrawals_test.go │ ├── validation_deposits.go │ └── validation_deposits_test.go ├── storage/ │ ├── beacondb/ │ │ ├── eth1.go │ │ ├── fork.go │ │ ├── history.go │ │ ├── index/ │ │ │ ├── validator.go │ │ │ └── validator_test.go │ │ ├── keys/ │ │ │ └── keys.go │ │ ├── kvstore.go │ │ ├── randao.go │ │ ├── registry.go │ │ ├── registry_test.go │ │ ├── slashing.go │ │ ├── staking_test.go │ │ ├── versioning.go │ │ └── withdrawals.go │ ├── block/ │ │ ├── config.go │ │ ├── interfaces.go │ │ ├── store.go │ │ └── store_test.go │ ├── db/ │ │ └── db.go │ ├── deposit/ │ │ ├── common/ │ │ │ └── synced_db.go │ │ ├── store.go │ │ └── v1/ │ │ ├── provider.go │ │ ├── store.go │ │ └── store_test.go │ ├── encoding/ │ │ ├── ssz.go │ │ └── u64.go │ ├── errors.go │ ├── filedb/ │ │ ├── db.go │ │ ├── db_options.go │ │ ├── db_test.go │ │ ├── range_db.go │ │ └── range_db_test.go │ ├── interfaces/ │ │ ├── db.go │ │ └── mocks/ │ │ └── db.mock.go │ └── kv_store_service.go └── testing/ ├── benchmarks/ │ └── logger_benchmark_test.go ├── e2e/ │ ├── .gitignore │ ├── README.md │ ├── config/ │ │ ├── config.go │ │ └── defaults.go │ ├── standard/ │ │ ├── beacon_api_test.go │ │ ├── blob_test.go │ │ ├── comet_api_test.go │ │ ├── inflation_test.go │ │ ├── proofs_test.go │ │ ├── setup_test.go │ │ ├── staking_test.go │ │ └── withdrawal_test.go │ └── suite/ │ ├── constants.go │ ├── errors.go │ ├── options.go │ ├── setup.go │ ├── suite.go │ └── types/ │ ├── account.go │ ├── account_test.go │ ├── beacon_client.go │ ├── consensus_client.go │ ├── errors.go │ ├── execution_client.go │ └── tx/ │ └── eip4844.go ├── files/ │ ├── entrypoint.sh │ ├── eth-genesis.json │ ├── jwt.hex │ ├── kzg-trusted-setup.json │ ├── spec.toml │ ├── test_data.json │ ├── test_data_batch.json │ └── test_data_incorrect_proof.json ├── forge-script/ │ ├── Makefile │ ├── README.md │ ├── dependency/ │ │ └── dependency.sh │ ├── forge-config.yaml │ ├── kurtosis.yml │ └── main.star ├── networks/ │ ├── 80069/ │ │ ├── app.toml │ │ ├── cl-seeds.txt │ │ ├── client.toml │ │ ├── config.toml │ │ ├── el-bootnodes.txt │ │ ├── el-peers.txt │ │ ├── eth-genesis.json │ │ ├── genesis.json │ │ ├── kzg-trusted-setup.json │ │ └── spec.toml │ └── 80094/ │ ├── app.toml │ ├── client.toml │ ├── config.toml │ ├── el-bootnodes.txt │ ├── el-peers.txt │ ├── eth-genesis.json │ ├── genesis.json │ ├── kzg-trusted-setup.json │ └── spec.toml ├── quick/ │ ├── compare_test.go │ └── execution_payload_test.go ├── simulated/ │ ├── chaos_test.go │ ├── components.go │ ├── el-genesis-files/ │ │ ├── eth-genesis.json │ │ ├── pectra-eth-genesis.json │ │ └── pectra-fork-genesis.json │ ├── execution/ │ │ ├── execnode.go │ │ ├── geth.go │ │ ├── resource.go │ │ ├── reth.go │ │ └── simulation_client.go │ ├── homedir.go │ ├── malicious_consensus_test.go │ ├── malicious_proposer_test.go │ ├── orphaned_blobs_test.go │ ├── payload_cache_test.go │ ├── pectra_fork_test.go │ ├── pectra_genesis_test.go │ ├── pectra_withdrawal_test.go │ ├── rpc_errors_test.go │ ├── simcomet.go │ ├── simulated_test.go │ ├── testnode.go │ ├── transformers.go │ ├── utils.go │ └── valid_chain_test.go ├── state-transition/ │ ├── README.md │ └── state-transition.go └── utils/ ├── .gitkeep └── generate.go ================================================ FILE CONTENTS ================================================ ================================================ FILE: .dockerignore ================================================ assets/ build/ bin/ docs/ networks/ proto/ tools/ kurtosis/ testing/ .github/ .git/ .vscode/ *.md contracts/ docs/ scripts/ ================================================ FILE: .gitattributes ================================================ docs/** linguist-vendored ================================================ FILE: .github/workflows/berachain_release.asc ================================================ -----BEGIN PGP PUBLIC KEY BLOCK----- mDMEaIky1hYJKwYBBAHaRw8BAQdAnxP3mNWC+miF0OKvOg4+BzzswbrTWLbluSJU +NBib3q0H2NhbGJlcmEgPGNhbGJlcmFAYmVyYWNoYWluLmNvbT6ImQQTFgoAQQIb AwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgBYhBPzFjSePGuMIYGS4P/GUiPGD 4kvxBQJpr+YaBQkBnVpEAAoJEPGUiPGD4kvxil4A/jJqgaUlW7Yk1G4joQnAE7FS 1RotqI2olJa2f7Vt33VEAP99Bi4TkSUwQpx6pKHRggrJ0aBEJg2eZXQd7AeTPWmL ALg4BGiJMtYSCisGAQQBl1UBBQEBB0A6onCspxjhXI7X13LHlUYQxYVyzUDamgVP hXYTLZ1QEAMBCAeIfgQYFgoAJhYhBPzFjSePGuMIYGS4P/GUiPGD4kvxBQJoiTLW AhsMBQkAdqcAAAoJEPGUiPGD4kvxWOAA/0IedfbPuCJU/IWo+gxCZMl9Fb7oVA4L v9lMBtnspGsxAQDRX3fFP/Bv96wHlUWQHg01TSaWNyTQa5dTpjEcLxnXCQ== =EVlI -----END PGP PUBLIC KEY BLOCK----- ================================================ FILE: .github/workflows/docker-nightly-preconf.yml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. name: Docker Nightly Preconf on: schedule: - cron: "0 1 * * *" workflow_dispatch: env: GHCR_REGISTRY: ghcr.io VERSION: nightly-preconf jobs: build-and-push: runs-on: labels: ubuntu-24.04-beacon-kit permissions: id-token: write contents: read packages: write attestations: write steps: - name: Checkout repository uses: actions/checkout@v4 with: ref: preconf-dev - name: Build Docker image run: | make build-docker VERSION=${{ env.VERSION }} - name: Authenticate to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.GHCR_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Push Docker image run: | make push-docker-github VERSION=${{ env.VERSION }} ================================================ FILE: .github/workflows/pipeline.yml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. name: pipeline on: push: branches: - main - preconf-dev tags: - "v*" pull_request: merge_group: concurrency: group: ci-${{ github.ref }}-tests # We don't want to cancel in progress on main. This is to allow # us to debug main if a bad commit is pushed. # Case 1: The base branch is main and the event triggered via merge group => we DO NOT want to cancel in progress # Case 2: The reference branch is not main => we want to cancel in progress cancel-in-progress: ${{ !(github.base_ref == 'refs/heads/main' && github.event_name == 'merge_group') || github.ref != 'refs/heads/main' }} env: GHCR_REGISTRY: ghcr.io PUSH_DOCKER_IMAGE: ${{ (github.base_ref == github.head_ref && github.event_name == 'push') || github.ref == 'refs/tags/v*'}} VERSION: ${{ github.ref_name }} jobs: # -------------------------------------------------------------------------- # # Main Pipeline # # -------------------------------------------------------------------------- # ci: strategy: matrix: args: - "build" - "lint" - "slither" - "gosec" - "nilaway" - "vulncheck" - "markdownlint" - "generate-check" - "tidy-sync-check" - "test-unit-cover" - "test-unit-bench" - "test-unit-fuzz" - "test-forge-cover" - "test-forge-fuzz" os: - ubuntu-24.04-beacon-kit name: ${{ matrix.args }} runs-on: labels: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v4 with: submodules: recursive - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 with: version: v1.3.1 if: ${{ matrix.args == 'lint' || matrix.args == 'generate-check' || matrix.args == 'test-forge-cover' || matrix.args == 'test-forge-fuzz' }} - name: Setup Golang uses: actions/setup-go@v5 with: go-version-file: go.mod check-latest: true cache-dependency-path: "**/*.sum" if: ${{ !(matrix.args == 'test-forge-cover' || matrix.args == 'test-forge-fuzz') }} - name: Run ${{ matrix.args }} run: | make ${{ matrix.args }} env: GOPATH: /home/runner/go # If running unit test coverage, merge the two coverage files - name: Merge Coverage Reports for Unit Tests if: ${{ matrix.args == 'test-unit-cover' }} run: | # Install gocovmerge go install github.com/wadey/gocovmerge@latest # Merge the two coverage files gocovmerge test-unit-cover.txt test-simulated.txt > coverage-merged.txt # Upload merged coverage for unit tests - name: Upload Unit Test Coverage to Codecov if: ${{ matrix.args == 'test-unit-cover' }} uses: codecov/codecov-action@v2 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage-merged.txt # -------------------------------------------------------------------------- # # E2E Testing # # -------------------------------------------------------------------------- # ci-e2e: strategy: fail-fast: false matrix: args: - "test-e2e-standard" os: - ubuntu-24.04-e2e name: ${{ matrix.args }} runs-on: labels: ${{ matrix.os }} steps: - name: Checkout uses: actions/checkout@v4 with: submodules: recursive - name: Check if Docker Hub credentials exist id: check-docker-credentials run: | if [ "${{ secrets.DOCKERHUB_USERNAME }}" != "" ] && [ "${{ secrets.DOCKERHUB_TOKEN }}" != "" ]; then echo "has_credentials=true" >> $GITHUB_OUTPUT fi shell: bash - name: Login to Docker Hub uses: docker/login-action@v3.4.0 if: steps.check-docker-credentials.outputs.has_credentials == 'true' with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GHCR uses: docker/login-action@v3.4.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Setup Golang uses: actions/setup-go@v5 with: go-version-file: go.mod check-latest: true cache-dependency-path: "**/*.sum" - name: Set up QEMU uses: docker/setup-qemu-action@v1 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Install Kurtosis run: | KURTOSIS_VERSION=$(go list -m -f '{{.Version}}' github.com/kurtosis-tech/kurtosis/api/golang | sed 's/^v//') echo "Installing kurtosis-cli ${KURTOSIS_VERSION}" curl -sL "https://github.com/kurtosis-tech/kurtosis-cli-release-artifacts/releases/download/${KURTOSIS_VERSION}/kurtosis-cli_${KURTOSIS_VERSION}_linux_amd64.tar.gz" | tar xz -C /tmp sudo mv /tmp/kurtosis /usr/local/bin/kurtosis kurtosis version docker info for img in kurtosistech/engine:1.4.3 timberio/vector:0.31.0-debian traefik:2.10.6 alpine:3.17; do docker pull $img done kurtosis engine start - name: Run ${{ matrix.args }} run: | make ${{ matrix.args }} env: GOPATH: /home/runner/go # -------------------------------------------------------------------------- # # Docker Container Build and Push # # -------------------------------------------------------------------------- # build-and-push-container: runs-on: labels: ubuntu-24.04-beacon-kit permissions: id-token: write contents: read packages: write attestations: write steps: - name: Checkout repository uses: actions/checkout@v4 - name: Echo GitHub Context Variables env: GITHUB_ACTOR: ${{ github.actor }} GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_EVENT_NAME: ${{ github.event_name }} GITHUB_SHA: ${{ github.sha }} GITHUB_REF: ${{ github.ref }} GITHUB_WORKFLOW: ${{ github.workflow }} GITHUB_ACTION: ${{ github.action }} GITHUB_RUN_ID: ${{ github.run_id }} GITHUB_RUN_NUMBER: ${{ github.run_number }} GITHUB_JOB: ${{ github.job }} GITHUB_SERVER_URL: ${{ github.server_url }} GITHUB_API_URL: ${{ github.api_url }} GITHUB_GRAPHQL_URL: ${{ github.graphql_url }} GITHUB_HEAD_REF: ${{ github.head_ref }} GITHUB_BASE_REF: ${{ github.base_ref }} PUSH_DOCKER_IMAGE: ${{ env.PUSH_DOCKER_IMAGE }} VERSION: ${{ env.VERSION }} run: | echo "GitHub Actor: \"$GITHUB_ACTOR\"" echo "GitHub Repository: \"$GITHUB_REPOSITORY\"" echo "GitHub Event Name: \"$GITHUB_EVENT_NAME\"" echo "GitHub SHA: \"$GITHUB_SHA\"" echo "GitHub Ref: \"$GITHUB_REF\"" echo "GitHub Workflow: \"$GITHUB_WORKFLOW\"" echo "GitHub Action: \"$GITHUB_ACTION\"" echo "GitHub Run ID: \"$GITHUB_RUN_ID\"" echo "GitHub Run Number: \"$GITHUB_RUN_NUMBER\"" echo "GitHub Job: \"$GITHUB_JOB\"" echo "GitHub Server URL: \"$GITHUB_SERVER_URL\"" echo "GitHub API URL: \"$GITHUB_API_URL\"" echo "GitHub GraphQL URL: \"$GITHUB_GRAPHQL_URL\"" echo "GitHub Head Ref: \"$GITHUB_HEAD_REF\"" echo "GitHub Base Ref: \"$GITHUB_BASE_REF\"" echo "PUSH_DOCKER_IMAGE: \"$PUSH_DOCKER_IMAGE\"" echo "VERSION: \"$VERSION\"" - name: Build Docker image run: | make build-docker - if: ${{ env.PUSH_DOCKER_IMAGE == 'true' }} name: Authenticate to GitHub Container Registry uses: docker/login-action@v3 with: registry: ${{ env.GHCR_REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - if: ${{ env.PUSH_DOCKER_IMAGE == 'true' }} name: Push Docker image run: | make push-docker-github ================================================ FILE: .github/workflows/release.yaml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. name: release on: push: tags: - "v*" env: REPO_NAME: ${{ github.repository }} IMAGE_NAME: ${{ github.repository }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: # Job to extract version extract-version: name: extract version runs-on: ubuntu-latest steps: - name: Extract version run: echo "VERSION=$(echo ${GITHUB_REF#refs/tags/})" >> $GITHUB_OUTPUT id: extract_version outputs: VERSION: ${{ steps.extract_version.outputs.VERSION }} # Job to build release build: name: build release needs: extract-version strategy: matrix: configs: - arch: arm64 target-os: linux runs-on: ubuntu-24.04-arm - arch: amd64 target-os: linux runs-on: ubuntu-latest - arch: arm64 target-os: darwin runs-on: macos-14 build: - binary: beacond runs-on: ${{ matrix.configs.runs-on }} steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: go-version-file: go.mod env: GOOS: ${{ matrix.configs.target-os }} GOARCH: ${{ matrix.configs.arch }} - name: Import GPG key run: | mkdir -p ~/.gnupg chmod 700 ~/.gnupg echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf echo "$GPG_KEY" | gpg --batch --import gpg-connect-agent reloadagent /bye || true env: GPG_KEY: ${{ secrets.GPG_KEY }} - name: Build ${{ matrix.build.binary }} run: | make build-${{ matrix.configs.target-os }}-${{ matrix.configs.arch }}-${{ needs.extract-version.outputs.VERSION }} tar -czvf ${{ matrix.build.binary }}-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target-os }}-${{ matrix.configs.arch }}.tar.gz -C build/bin . - name: Sign binary archive run: gpg --batch --yes --pinentry-mode=loopback --passphrase "$GPG_KEY_PASSPHRASE" --detach-sign ${{ matrix.build.binary }}-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target-os }}-${{ matrix.configs.arch }}.tar.gz env: GPG_KEY_PASSPHRASE: ${{ secrets.GPG_KEY_PASSPHRASE }} # Upload archives and signatures - name: Upload archive uses: actions/upload-artifact@v4 with: name: ${{ matrix.build.binary }}-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target-os }}-${{ matrix.configs.arch }}.tar.gz path: | ${{ matrix.build.binary }}-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target-os }}-${{ matrix.configs.arch }}.tar.gz - name: Upload archive signature uses: actions/upload-artifact@v4 with: name: ${{ matrix.build.binary }}-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target-os }}-${{ matrix.configs.arch }}.tar.gz.sig path: | ${{ matrix.build.binary }}-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target-os }}-${{ matrix.configs.arch }}.tar.gz.sig # Job to draft release draft-release: name: draft release needs: [build, extract-version] runs-on: ubuntu-latest env: VERSION: ${{ needs.extract-version.outputs.VERSION }} permissions: contents: write # Required to post the release steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # This is necessary for generating the changelog. It has to come before "Download Artifacts" or else it deletes the artifacts. - name: Download artifacts uses: actions/download-artifact@v4 - name: Generate full changelog id: changelog run: | echo "CHANGELOG<> $GITHUB_OUTPUT echo "$(git log --pretty=format:"- %s" $(git describe --tags --abbrev=0 ${{ env.VERSION }}^)..${{ env.VERSION }})" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Create release draft env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # The formatting here is borrowed from Reth (which is borrowed from Lighthouse (which is borrowed from OpenEthereum)): # https://github.com/openethereum/openethereum/blob/6c2d392d867b058ff867c4373e40850ca3f96969/.github/workflows/build.yml run: | body=$(cat <<- "ENDBODY" ![image](https://res.cloudinary.com/duv0g402y/image/upload/v1718034312/BeaconKitBanner.png) ## Testing Checklist (DELETE ME) - [ ] Run on testnet for 1-3 days. - [ ] Resync a mainnet node. - [ ] Ensure all CI checks pass. ## Release Checklist (DELETE ME) - [ ] Ensure all crates have had their versions bumped. - [ ] Write the summary. - [ ] Fill out the update priority. - [ ] Ensure all binaries have been added. - [ ] Prepare release posts (Twitter, ...). ## Summary Add a summary, including: - Critical bug fixes - New features - Any breaking changes (and what to expect) ## Update Priority This table provides priorities for which classes of users should update particular components. | User Class | Priority | |----------------------|-----------------| | Payload Builders | | | Non-Payload Builders | | ## All Changes ${{ steps.changelog.outputs.CHANGELOG }} ## Binaries | System | Architecture | Binary | PGP Signature | |:---:|:---:|:---:|:---| | | amd64 | [beacond-${{ env.VERSION }}-linux-amd64](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/beacond-${{ env.VERSION }}-linux-amd64.tar.gz) | [Signature](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/beacond-${{ env.VERSION }}-linux-amd64.tar.gz.sig) | | | arm64 | [beacond-${{ env.VERSION }}-linux-arm64](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/beacond-${{ env.VERSION }}-linux-arm64.tar.gz) | [Signature](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/beacond-${{ env.VERSION }}-linux-arm64.tar.gz.sig) | | | arm64 | [beacond-${{ env.VERSION }}-darwin-arm64](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/beacond-${{ env.VERSION }}-darwin-arm64.tar.gz) | [Signature](https://github.com/${{ env.REPO_NAME }}/releases/download/${{ env.VERSION }}/beacond-${{ env.VERSION }}-darwin-arm64.tar.gz.sig) | | **System** | **Option** | - | **Resource** | | | Docker | | [${{ env.IMAGE_NAME }}](https://ghcr.io/berachain/beacon-kit) | ### Verifying signatures Use gpg to verify the signature on these binary archives. This is important to make sure that the content you\'ve downloaded is legitimate. gpg can be installed with most package managers. For example: - `brew install gpg` on mac - `apt install gpg` on Ubuntu/Debian Once gpg is installed, import our public key into its database and verify: - [Download signing public key from here](https://raw.githubusercontent.com/${{ github.repository }}/${{ github.ref_name }}/.github/workflows/berachain_release.asc). - Run `gpg --import berachain_release.asc` - Verify with `gpg --verify {signature}.sig {binary}.tar.gz` - This message is expected: `WARNING: This key is not certified with a trusted signature!` - To resolve the warning, trust the key by signing with your own keypair. `gpg --lsign-key ` ENDBODY ) assets=() for asset in ./*beacond-*.tar.gz*; do assets+=("$asset/$asset") done tag_name="${{ env.VERSION }}" echo "$body" | gh release create --draft -t "BeaconKit $tag_name" -F "-" "$tag_name" "${assets[@]}" ================================================ FILE: .github/workflows/vuln-and-dep-check.yml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. name: deps on: schedule: - cron: '0 8 * * *' # daily at 08:00 UTC workflow_dispatch: # Cancel any in-progress run if a new one starts on the same branch. concurrency: group: vuln-and-dep-check-${{ github.ref }} cancel-in-progress: true permissions: contents: read jobs: # Catch newly published vulnerabilities in dependencies via symbol-level analysis. govulncheck: runs-on: labels: ubuntu-24.04-beacon-kit steps: - uses: actions/checkout@v4 with: submodules: recursive - uses: actions/setup-go@v5 with: go-version-file: go.mod check-latest: true cache-dependency-path: "**/*.sum" - run: make vulncheck # Run tests with locked and latest deps to catch breakage from both. test-deps: runs-on: labels: ubuntu-24.04-beacon-kit strategy: fail-fast: false # Always run both variants so one failure doesn't hide the other. matrix: deps: [locked, latest] name: test-${{ matrix.deps }}-deps steps: - uses: actions/checkout@v4 with: submodules: recursive - uses: actions/setup-go@v5 with: go-version-file: go.mod check-latest: true cache-dependency-path: "**/*.sum" - if: matrix.deps == 'latest' name: Update dependencies to latest (skip replace-pinned modules) run: | go list -m -f '{{if not .Indirect}}{{.Path}}{{end}}' all \ | grep -vE 'berachain/beacon-kit|cosmossdk\.io/|cosmos/cosmos-sdk|cometbft/|karalabe/ssz|kurtosis-tech/' \ | xargs go get -u -t go mod tidy - run: make test-unit env: GOPATH: /home/runner/go ================================================ FILE: .gitignore ================================================ ########### # Project # ########### # Outputs bin/ ./out/ data/ site/ contracts/cache contracts/out tmp/ cscope.files ########## # Golang # ########## # Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib *.info # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) go.work.sum ########## # Linux # ########## *~ # temporary files which can be created if a process still has a handle open of a deleted file .fuse_hidden* # KDE directory preferences .directory # Linux trash folder which might appear on any partition or disk .Trash-* # .nfs files are created when an open file is removed but is still being accessed .nfs* # Version files created during code generation v*.*.* ########### # Windows # ########### # Windows thumbnail cache files Thumbs.db Thumbs.db:encryptable ehthumbs.db ehthumbs_vista.db # Dump file *.stackdump # Folder config file [Dd]esktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ # Windows Installer files *.cab *.msi *.msix *.msm *.msp # Windows shortcuts *.lnk ######### # macOS # ######### # General .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ########## # VSCODE # ########## .vscode/* !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json *.code-workspace # Local History for Visual Studio Code .history/ ############# # JetBrains # ############# .idea # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # AWS User-specific .idea/**/aws.xml # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Mongo Explorer plugin .idea/**/mongoSettings.xml # File-based project format *.iws # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Editor-based Rest Client .idea/httpRequests # general vue/node_modules vue/dist release/ .idea/ data/ .DS_Store *.pyc .vscode/*.log # upgrades pkg/**/.*.yaml */**/.tmp/ .tmp/ /tmp # forge */**/solidity-files-cache.json contracts/out/ */**/broadcast contracts/out/**/*.bin # e2e e2e/**/*.txt # hive !e2e/hive/**/*.json # geth *.rlp # cosmos .testnets/ *.dot *.log # xml *.xml #next node_modules .next next-env.d.ts .env out # docker test **/temp/ # testing coverage coverage-test-unit-cover.txt coverage-merged.txt test-simulated.txt test-unit-cover.txt temp-test-simulated.txt temp-test-unit-cover.txt .vercel # server dev env for Air .air.toml ================================================ FILE: .gitmodules ================================================ [submodule "contracts/lib/solady"] path = contracts/lib/solady url = https://github.com/Vectorized/solady [submodule "contracts/lib/forge-std"] path = contracts/lib/forge-std url = https://github.com/foundry-rs/forge-std ================================================ FILE: .golangci.yaml ================================================ # This code is licensed under the terms of the MIT license https://opensource.org/license/mit # Copyright (c) 2021 Marat Reymers ## Golden config for golangci-lint v1.58.2 # # This is the best config for golangci-lint based on my experience and opinion. # It is very strict, but not extremely strict. # Feel free to adapt and change it for your needs. run: # Timeout for analysis, e.g. 30s, 5m. # Default: 1m timeout: 3m build-tags: ["test"] # This file contains only configs which differ from defaults. # All possible options can be found here https://github.com/golangci/golangci-lint/blob/master/.golangci.reference.yml linters-settings: cyclop: # The maximal code complexity to report. # Default: 10 max-complexity: 30 # The maximal average package complexity. # If it's higher than 0.0 (float) the check is enabled # Default: 0.0 package-average: 10.0 errcheck: # Report about not checking of errors in type assertions: `a := b.(MyStruct)`. # Such cases aren't reported by default. # Default: false check-type-assertions: true paralleltest: # Ignore missing calls to `t.Parallel()` and only report incorrect uses of it. # Default: false ignore-missing: false # Ignore missing calls to `t.Parallel()` in subtests. Top-level tests are # still required to have `t.Parallel`, but subtests are allowed to skip it. # Default: false ignore-missing-subtests: true exhaustive: # Program elements to check for exhaustiveness. # Default: [ switch ] check: - switch - map # Presence of "default" case in switch statements satisfies exhaustiveness, # even if all enum members are not listed. # Default: false default-signifies-exhaustive: true exhaustruct: # List of regular expressions to exclude struct packages and their names from checks. # Regular expressions must match complete canonical struct package/name/structname. # Default: [] exclude: # std libs - "^net/http.Client$" - "^net/http.Cookie$" - "^net/http.Request$" - "^net/http.Response$" - "^net/http.Server$" - "^net/http.Transport$" - "^net/url.URL$" - "^os/exec.Cmd$" - "^reflect.StructField$" # public libs - "^github.com/Shopify/sarama.Config$" - "^github.com/Shopify/sarama.ProducerMessage$" - "^github.com/mitchellh/mapstructure.DecoderConfig$" - "^github.com/prometheus/client_golang/.+Opts$" - "^github.com/spf13/cobra.Command$" - "^github.com/spf13/cobra.CompletionOptions$" - "^github.com/stretchr/testify/mock.Mock$" - "^github.com/testcontainers/testcontainers-go.+Request$" - "^github.com/testcontainers/testcontainers-go.FromDockerfile$" - "^golang.org/x/tools/go/analysis.Analyzer$" - "^google.golang.org/protobuf/.+Options$" - "^gopkg.in/yaml.v3.Node$" funlen: # Checks the number of lines in a function. # If lower than 0, disable the check. # Default: 60 lines: 100 # Checks the number of statements in a function. # If lower than 0, disable the check. # Default: 40 statements: 50 # Ignore comments when counting lines. # Default false ignore-comments: true gocognit: # Minimal code complexity to report. # Default: 30 (but we recommend 10-20) min-complexity: 20 gocritic: # Settings passed to gocritic. # The settings key is the name of a supported gocritic checker. # The list of supported checkers can be find in https://go-critic.github.io/overview. settings: captLocal: # Whether to restrict checker to params only. # Default: true paramsOnly: false underef: # Whether to skip (*x).method() calls where x is a pointer receiver. # Default: true skipRecvDeref: false gomodguard: blocked: # List of blocked modules. # Default: [] modules: - github.com/golang/protobuf: recommendations: - google.golang.org/protobuf reason: "see https://developers.google.com/protocol-buffers/docs/reference/go/faq#modules" - github.com/satori/go.uuid: recommendations: - github.com/google/uuid reason: "satori's package is not maintained" - github.com/gofrs/uuid: recommendations: - github.com/gofrs/uuid/v5 reason: "gofrs' package was not go module before v5" govet: # Enable all analyzers. # Default: false enable-all: true # Disable analyzers by name. # Run `go tool vet help` to see all analyzers. # Default: [] disable: - fieldalignment # too strict # Settings per analyzer. settings: shadow: # Whether to be strict about shadowing; can be noisy. # Default: false strict: true inamedparam: # Skips check for interface methods with only a single parameter. # Default: false skip-single-param: true lll: # Max line length, lines longer will be reported. # '\t' is counted as 1 character by default, and can be changed with the tab-width option. # Default: 120. line-length: 140 # Tab width in spaces. # Default: 1 tab-width: 1 mnd: # List of function patterns to exclude from analysis. # Values always ignored: `time.Date`, # `strconv.FormatInt`, `strconv.FormatUint`, `strconv.FormatFloat`, # `strconv.ParseInt`, `strconv.ParseUint`, `strconv.ParseFloat`. # Default: [] ignored-functions: - args.Error - flag.Arg - flag.Duration.* - flag.Float.* - flag.Int.* - flag.Uint.* - os.Chmod - os.Mkdir.* - os.OpenFile - os.WriteFile - prometheus.ExponentialBuckets.* - prometheus.LinearBuckets nakedret: # Make an issue if func has more lines of code than this setting, and it has naked returns. # Default: 30 max-func-lines: 0 nolintlint: # Exclude following linters from requiring an explanation. # Default: [] allow-no-explanation: [ funlen, gocognit, lll ] # Enable to require an explanation of nonzero length after each nolint directive. # Default: false require-explanation: true # Enable to require nolint directives to mention the specific linter being suppressed. # Default: false require-specific: true perfsprint: # Optimizes into strings concatenation. # Default: true strconcat: true rowserrcheck: # database/sql is always checked # Default: [] packages: - github.com/jmoiron/sqlx sloglint: # Enforce not using global loggers. # Values: # - "": disabled # - "all": report all global loggers # - "default": report only the default slog logger # Default: "" no-global: "all" # Enforce using methods that accept a context. # Values: # - "": disabled # - "all": report all contextless calls # - "scope": report only if a context exists in the scope of the outermost function # Default: "" context: "scope" tenv: # The option `all` will run against whole test files (`_test.go`) regardless of method/function signatures. # Otherwise, only methods that take `*testing.T`, `*testing.B`, and `testing.TB` as arguments are checked. # Default: false all: true linters: disable-all: true enable: ## enabled by default - errcheck # checking for unchecked errors, these unchecked errors can be critical bugs in some cases - gosimple # specializes in simplifying a code - govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string - ineffassign # detects when assignments to existing variables are not used - staticcheck # is a go vet on steroids, applying a ton of static analysis checks - typecheck # like the front-end of a Go compiler, parses and type-checks Go code - unused # checks for unused constants, variables, functions and types ## disabled by default - asasalint # checks for pass []any as any in variadic func(...any) - asciicheck # checks that your code does not contain non-ASCII identifiers - bidichk # checks for dangerous unicode character sequences - bodyclose # checks whether HTTP response body is closed successfully - canonicalheader # checks whether net/http.Header uses canonical header - cyclop # checks function and package cyclomatic complexity - dupl # tool for code clone detection - durationcheck # checks for two durations multiplied together - errname # checks that sentinel errors are prefixed with the Err and error types are suffixed with the Error - errorlint # finds code that will cause problems with the error wrapping scheme introduced in Go 1.13 - exhaustive # checks exhaustiveness of enum switch statements - fatcontext # detects nested contexts in loops - forbidigo # forbids identifiers - funlen # tool for detection of long functions - gocheckcompilerdirectives # validates go compiler directive comments (//go:) - gochecknoglobals # checks that no global variables exist - gochecknoinits # checks that no init functions are present in Go code - gochecksumtype # checks exhaustiveness on Go "sum types" - gocognit # computes and checks the cognitive complexity of functions - goconst # finds repeated strings that could be replaced by a constant - gocritic # provides diagnostics that check for bugs, performance and style issues - gocyclo # computes and checks the cyclomatic complexity of functions - goimports # in addition to fixing imports, goimports also formats your code in the same style as gofmt # - gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod - gomodguard # allow and block lists linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations - goprintffuncname # checks that printf-like functions are named with f at the end - gosec # inspects source code for security problems - intrange # finds places where for loops could make use of an integer range - lll # reports long lines - loggercheck # checks key value pairs for common logger libraries (kitlog,klog,logr,zap) - makezero # finds slice declarations with non-zero initial length - mirror # reports wrong mirror patterns of bytes/strings usage - mnd # detects magic numbers - musttag # enforces field tags in (un)marshaled structs - nakedret # finds naked returns in functions greater than a specified function length - nestif # reports deeply nested if statements - nilerr # finds the code that returns nil even if it checks that the error is not nil - nilnil # checks that there is no simultaneous return of nil error and an invalid value - noctx # finds sending http request without context.Context - nolintlint # reports ill-formed or insufficient nolint directives - nonamedreturns # reports all named returns - nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL - perfsprint # checks that fmt.Sprintf can be replaced with a faster alternative - predeclared # finds code that shadows one of Go's predeclared identifiers - promlinter # checks Prometheus metrics naming via promlint - protogetter # reports direct reads from proto message fields when getters should be used - reassign # checks that package variables are not reassigned - revive # fast, configurable, extensible, flexible, and beautiful linter for Go, drop-in replacement of golint - rowserrcheck # checks whether Err of rows is checked successfully - sloglint # ensure consistent code style when using log/slog - spancheck # checks for mistakes with OpenTelemetry/Census spans - sqlclosecheck # checks that sql.Rows and sql.Stmt are closed - stylecheck # is a replacement for golint - testableexamples # checks if examples are testable (have an expected output) - usetesting # detects using os.Setenv instead of t.Setenv since Go1.17 (replaces deprecated tenv) - testifylint # checks usage of github.com/stretchr/testify - testpackage # makes you use a separate _test package # - tparallel # detects inappropriate usage of t.Parallel() method in your Go test codes. Replaced with paralleltest - unconvert # removes unnecessary type conversions - unparam # reports unused function parameters - usestdlibvars # detects the possibility to use variables/constants from the Go standard library - wastedassign # finds wasted assignment statements - whitespace # detects leading and trailing whitespace ## you may want to enable - decorder # checks declaration order and count of types, constants, variables and functions #- exhaustruct # [highly recommend to enable] checks if all structure fields are initialized - gci # controls golang package import order and makes it always deterministic #- ginkgolinter # [if you use ginkgo/gomega] enforces standards of using ginkgo and gomega #- godox # detects FIXME, TODO and other comment keywords - goheader # checks is file header matches to pattern #- inamedparam # [great idea, but too strict, need to ignore a lot of cases by default] reports interfaces with unnamed method parameters #- interfacebloat # checks the number of methods inside an interface #- ireturn # accept interfaces, return concrete types - prealloc # [premature optimization, but can be used in some cases] finds slice declarations that could potentially be preallocated #- tagalign # checks that struct tags are well aligned #- varnamelen # [great idea, but too many false positives] checks that the length of a variable's name matches its scope #- wrapcheck # checks that errors returned from external packages are wrapped - zerologlint # detects the wrong usage of zerolog that a user forgets to dispatch zerolog.Event ## disabled #- containedctx # detects struct contained context.Context field - contextcheck # [too many false positives] checks the function whether use a non-inherited context #- depguard # [replaced by gomodguard] checks if package imports are in a list of acceptable packages - dogsled # checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) #- dupword # [useless without config] checks for duplicate words in the source code #- err113 # [too strict] checks the errors handling expressions #- errchkjson # [don't see profit + I'm against of omitting errors like in the first example https://github.com/breml/errchkjson] checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted #- execinquery # [deprecated] checks query string in Query function which reads your Go src files and warning it finds #- forcetypeassert # [replaced by errcheck] finds forced type assertions #- gofmt # [replaced by goimports] checks whether code was gofmt-ed #- gofumpt # [replaced by goimports, gofumports is not available yet] checks whether code was gofumpt-ed - gosmopolitan # reports certain i18n/l10n anti-patterns in your Go codebase - grouper # analyzes expression groups - importas # enforces consistent import aliases - maintidx # measures the maintainability index of each function - misspell # [useless] finds commonly misspelled English words in comments #- nlreturn # [too strict and mostly code is not more readable] checks for a new line before return and branch statements to increase code clarity - paralleltest # detects missing usage of t.Parallel() method in your Go test # - tagliatelle # checks the struct tags - thelper # detects golang test helpers without t.Helper() call and checks the consistency of test helpers #- wsl # [too strict and mostly code is not more readable] whitespace linter forces you to use empty lines issues: # Maximum count of issues with the same text. # Set to 0 to disable. # Default: 3 max-same-issues: 50 exclude-rules: - source: "//noinspection" linters: [ gocritic ] - path: "_test\\.go" linters: - bodyclose - dupl - funlen - goconst - gosec - noctx - wrapcheck - gochecknoglobals # We exclude thelper for consensus types due to the usage of runForAllSupportedVersions where thelper falsely misses the usage of t.Helper() - path: "^consensus-types/types/.*\\.go$" linters: - thelper exclude-files: - "pkg/cometbft/cli/.*\\.go" - "pkg/cometbft/service/server/.*\\.go" # Copied/adapted from go-ethereum (geth); not worth linting. - "geth-primitives/types/.*\\.go" ================================================ FILE: .mockery.yaml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. dir: "{{.InterfaceDir}}/mocks" mockname: "{{.InterfaceNameCamel}}" filename: "{{.InterfaceNameSnake}}.mock.go" outpkg: "mocks" resolve-type-alias: False # see https://vektra.github.io/mockery/latest/deprecations/#resolve-type-alias issue-845-fix: True # see https://vektra.github.io/mockery/latest/deprecations/#issue-845-fix packages: github.com/berachain/beacon-kit/execution/client/ethclient: config: recursive: True with-expecter: true include-regex: GethRPCClient github.com/berachain/beacon-kit/node-core/services/registry: config: recursive: True with-expecter: true all: True github.com/berachain/beacon-kit/storage/interfaces: config: recursive: False with-expecter: true all: True github.com/berachain/beacon-kit/consensus-types/types: config: recursive: False with-expecter: true all: True github.com/berachain/beacon-kit/storage/pruner: config: recursive: False with-expecter: true all: True github.com/berachain/beacon-kit/primitives/crypto: config: recursive: False with-expecter: true all: True github.com/berachain/beacon-kit/engine-primitives/engine-primitives: config: recursive: False with-expecter: true all: True github.com/berachain/beacon-kit/state-transition/core: config: recursive: False with-expecter: true include-regex: ExecutionEngine github.com/berachain/beacon-kit/beacon/blockchain: config: recursive: False with-expecter: true include-regex: LocalBuilder|StorageBackend github.com/berachain/beacon-kit/node-api/handlers/beacon: config: recursive: False with-expecter: true include-regex: ^Backend$ github.com/berachain/beacon-kit/node-api/handlers/node: config: recursive: False with-expecter: true include-regex: ^Backend$ github.com/berachain/beacon-kit/node-api/backend: config: recursive: False with-expecter: true include-regex: GenesisStateProcessor github.com/berachain/beacon-kit/node-core/types: config: recursive: False with-expecter: true include-regex: ConsensusService ================================================ FILE: .vscode/launch.json ================================================ { "version": "0.2.0", "configurations": [ { "name": "Init local devnet", "type": "go", "request": "launch", "preLaunchTask": "build", "mode": "exec", "program": "${workspaceFolder}/build/bin/beacond", "args": [ "init", "localtestnet", "--beacon-kit.chain-spec=devnet", "--chain-id=beacond-2061", "--home=${workspaceFolder}/.tmp/beacond", ], "internalConsoleOptions": "openOnSessionStart", "presentation": { "group": "initialize", "order": 1 }, }, { "name": "Add premined deposit", "type": "go", "request": "launch", "mode": "exec", "program": "${workspaceFolder}/build/bin/beacond", "preLaunchTask": "build", "args": [ "genesis", "add-premined-deposit", "32000000000", "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4", "--beacon-kit.chain-spec=devnet", "--home=${workspaceFolder}/.tmp/beacond", ], "internalConsoleOptions": "openOnSessionStart", "presentation": { "group": "initialize", "order": 2 }, }, { "name": "Collect premined deposit", "type": "go", "request": "launch", "preLaunchTask": "build", "mode": "exec", "program": "${workspaceFolder}/build/bin/beacond", "args": [ "genesis", "collect-premined-deposits", "--beacon-kit.chain-spec=devnet", "--home=${workspaceFolder}/.tmp/beacond", ], "internalConsoleOptions": "openOnSessionStart", "presentation": { "group": "initialize", "order": 3 }, }, { "name": "Set deposit storage", "type": "go", "request": "launch", "preLaunchTask": "build", "mode": "exec", "program": "${workspaceFolder}/build/bin/beacond", "args": [ "genesis", "set-deposit-storage", "${workspaceFolder}/testing/files/eth-genesis.json", "--beacon-kit.chain-spec=devnet", "--home=${workspaceFolder}/.tmp/beacond", ], "internalConsoleOptions": "openOnSessionStart", "presentation": { "group": "initialize", "order": 4 }, }, { "name": "Genesis execution payload", "type": "go", "request": "launch", "preLaunchTask": "build", "mode": "exec", "program": "${workspaceFolder}/build/bin/beacond", "args": [ "genesis", "execution-payload", "${workspaceFolder}/.tmp/beacond/eth-genesis.json", "--beacon-kit.chain-spec=devnet", "--home=${workspaceFolder}/.tmp/beacond", ], "internalConsoleOptions": "openOnSessionStart", "presentation": { "group": "initialize", "order": 5 }, }, { "name": "Start beacond (mainnet)", "type": "go", "request": "launch", "preLaunchTask": "build", "mode": "exec", "program": "${workspaceFolder}/build/bin/beacond", "args": [ "start", "--pruning=nothing", "--beacon-kit.chain-spec=mainnet", "--beacon-kit.logger.log-level=info", "--home=${workspaceFolder}/.tmp/beacond", "--beacon-kit.engine.jwt-secret-path=${workspaceFolder}/testing/files/jwt.hex", "--beacon-kit.node-api.enabled", "--beacon-kit.node-api.logging", ], "internalConsoleOptions": "openOnSessionStart", "presentation": { "group": "run", "order": 1 }, "suppressMultipleSessionWarning": true, }, { "name": "Start beacond (devnet)", "type": "go", "request": "launch", "preLaunchTask": "build", "mode": "exec", "program": "${workspaceFolder}/build/bin/beacond", "args": [ "start", "--pruning=nothing", "--beacon-kit.chain-spec=devnet", "--beacon-kit.logger.log-level=info", "--home=${workspaceFolder}/.tmp/beacond", "--beacon-kit.engine.jwt-secret-path=${workspaceFolder}/testing/files/jwt.hex", "--beacon-kit.node-api.enabled", "--beacon-kit.node-api.logging", ], "internalConsoleOptions": "openOnSessionStart", "presentation": { "group": "run", "order": 2 }, "suppressMultipleSessionWarning": true, } ] } ================================================ FILE: .vscode/tasks.json ================================================ { "version": "2.0.0", "tasks": [ { "label": "build", "type": "shell", "command": "make build COSMOS_BUILD_OPTIONS=nostrip", "presentation": { "close": true } } ] } ================================================ FILE: CLAUDE.md ================================================ # CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Introduction & Overview BeaconKit is a modular consensus client implementation that uses a modified CometBFT (Tendermint) for consensus instead of the standard Ethereum beacon chain consensus. It implements the Ethereum consensus layer specification while supporting all major Ethereum execution clients through the Engine API. ### Key Differences from Standard Ethereum - **Consensus**: Uses CometBFT's Tendermint consensus instead of Ethereum's LMD-GHOST + Casper FFG - **Block Timing**: No fixed 12-second slots; uses timeout-based rounds - **Validator Set**: Custom validator set cap implementation - **Block Heights**: Sequential without gaps (CometBFT height = beacon slot) - **No Missed Slots**: Every height produces a block eventually through round-based consensus ## Project Structure ### Key Directories - `/beacon/` - Core beacon chain logic (blockchain service, validator service, payload coordination) - `/chain/` - Chain specifications and helpers (spec interfaces, network configs, genesis generation) - `/cli/` - CLI commands and configuration (all beacond commands, flag definitions) - `/config/` - Configuration management (TOML templates, default configs) - `/consensus-types/` - Consensus layer types (blocks, states, validators, SSZ serialization) - `/contracts/` - Solidity contracts (deposit contract, staking, Go bindings) - `/da/` - Data availability layer (blob management, KZG commitments, proofs) - `/engine-primitives/` - Execution engine types (Engine API types, payloads, withdrawals) - `/execution/` - Execution client integration (Engine API client, deposit syncing) - `/node-api/` - REST API implementation (beacon API handlers, server setup) - `/node-core/` - Core node infrastructure (DI components, service registry, node builder) - `/primitives/` - Basic types and constants (Slot, Gwei, ValidatorIndex, crypto primitives) - `/state-transition/` - State transition logic (state machine, fork transitions, operations) - `/storage/` - Database and storage backends (beacon DB, block store, blob store, pruning) - `/testing/` - Test utilities and networks (e2e tests, simulations, test fixtures) ### Configuration Files - Home directory: `~/.beacond` (or `.tmp/beacond` for local testing) - Config files: `config.toml`, `app.toml`, `client.toml`, `genesis.json` - Configuration sections in `config.toml`: - `beacon-kit.engine` - Execution client settings - `beacon-kit.logger` - Logging configuration - `beacon-kit.kzg` - KZG trusted setup - `beacon-kit.payload-builder` - Block building - `beacon-kit.validator` - Validator settings - `beacon-kit.block-store-service` - Block storage - `beacon-kit.node-api` - API server settings ## Development Commands ### Building ```bash make build # Build beacond binary to build/bin/beacond make build-docker # Build Docker image make install # Install beacond to $GOPATH/bin ``` ### Running ```bash make start # Start ephemeral devnet node (chain ID: 80087) make start-custom # Start with custom chain spec TOML file make start- # Start execution client (reth/geth/nethermind/besu/erigon/ethereumjs) ``` Note: Always start the beacon node before the execution client, as it generates the required genesis configuration. ### Testing ```bash make test # Run all tests (unit + forge) make test-unit # Run unit tests with coverage make test-unit-no-coverage # Run unit tests without coverage make test-unit-bench # Run benchmarks make test-unit-fuzz # Run Go fuzz tests make test-simulated # Run simulation tests (chaos, forks) make test-e2e # Run e2e tests (builds Docker first) make test-forge-cover # Run Solidity tests with coverage ``` ### Linting & Formatting ```bash make lint # Run all linters make format # Run all formatters make golangci-fix # Auto-fix linting issues make gosec # Run security scanner make nilaway # Run nil pointer checker ``` ### Code Generation ```bash make generate # Run all code generation make proto # Generate protobuf code make generate-check # Verify generated code is up to date ``` ## Environment Variables BeaconKit uses Viper for configuration management, which supports environment variables with automatic binding. ### Environment Variable Configuration - **Prefix**: Configured per application (e.g., `BEACOND_` for the main beacon daemon) - **Key Mapping**: Configuration keys are transformed for environment variables: - Dots (`.`) are replaced with underscores (`_`) - Hyphens (`-`) are replaced with underscores (`_`) - All keys are uppercased - **Auto-binding**: Environment variables are automatically bound using `viper.AutomaticEnv()` ### Configuration Precedence The configuration system follows this precedence order (highest to lowest): 1. **CLI flags** - Command-line arguments override everything 2. **Environment variables** - Override config file values 3. **Config file** - Values from `config.toml`, `app.toml`, etc. 4. **Default values** - Hardcoded defaults in the application ### Implementation Details The environment variable system is initialized in `cli/commands/server/cmd/execute.go`: ```go viper.SetEnvPrefix(envPrefix) viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) viper.AutomaticEnv() ``` This setup ensures that: - All environment variables with the configured prefix are automatically recognized - Configuration keys are properly mapped to environment variable names - Values from environment variables override configuration file values ## CLI Usage ### beacond Commands ```bash beacond init # Initialize a new node beacond start # Start the beacon node beacond rollback # Rollback blockchain state beacond genesis add-premined-deposit # Add premined deposits to genesis beacond genesis collect-premined-deposits # Collect premined deposits beacond genesis set-deposit-storage # Set deposit contract storage beacond genesis execution-payload # Generate execution payload beacond deposit create-validator # Create validator deposit ``` ### Key Flags ```bash --beacon-kit.chain-spec # Chain spec: devnet/testnet/mainnet --beacon-kit.chain-spec-file # Custom chain spec TOML file --beacon-kit.engine.jwt-secret-path # JWT secret for EL auth --beacon-kit.engine.rpc-dial-url # Execution client RPC URL --beacon-kit.kzg.trusted-setup-path # KZG trusted setup file --beacon-kit.node-api.enabled # Enable REST API --home # Node home directory (default: ~/.beacond) ``` ## Network Specifications ### Supported Networks - **Devnet** - Chain ID: 80087 (local development) - **Testnet/Bepolia** - Chain ID: 80069 (public testnet) - **Mainnet** - Chain ID: 80094 (production) Network configurations are in `testing/networks//` ## Architecture Overview BeaconKit implements a modular EVM consensus client using a modified CometBFT for consensus and supporting all major Ethereum execution clients through the Engine API. ### System Architecture ``` ┌───────────────────────────────────────────────────────────────┐ │ Service Registry │ │ (Lifecycle orchestrator for all services) │ │ Startup Order: │ │ 1. ShutdownService → 2. ValidatorService → 3. NodeAPIServer │ │ 4. ReportingService → 5. TelemetryService → 6. EngineClient │ │ 7. ChainService → 8. CometBFTService │ └──────────────────────────────┬────────────────────────────────┘ │ manages lifecycle ▼ ┌─────────────────────────────────────┐ │ CometBFT Service │ │ (Consensus orchestrator via P2P) │ │ ┌─────────────────────────────┐ │ │ │ ABCI++ Interface: │ │ │ │ • Info │ │ │ │ • InitChain │ │ │ │ • PrepareProposal │ │ │ │ • ProcessProposal │ │ │ │ • FinalizeBlock │ │ │ │ • Commit │ │ │ └─────────────────────────────┘ │ └───────────────┬─────────────────────┘ │ PrepareProposal │ ProcessProposal/FinalizeBlock ┌───────────┴─────────┐ ▼ ▼ ┌─────────────────────┐ ┌────────────────────┐ │ Validator Service │ │ Blockchain Service │ │ (Block builder) │ │ (Block processor) │ │ ┌─────────────────┐ │ │ ┌────────────────┐ │ │ │ • StateProcessor│ │ │ │• StateProcessor│ │ │ │ • BlobFactory │ │ │ │• BlobProcessor │ │ │ │ • PayloadBuilder│ │ │ │• LocalBuilder │ │ │ │ • Signer │ │ │ │• DepositFetcher│ │ │ └─────────────────┘ │ │ └────────────────┘ │ └──────────┬──────────┘ └────────┬───────────┘ │ │ │ both use │ both use ▼ ▼ ┌────────────────────────────────────────┐ │ Execution Engine │ │ (Engine API client wrapper) │ │ • forkchoiceUpdate │ │ • newPayload / getPayload │ └──────────────┬─────────────────────────┘ │ communicates with ▼ External EL Client (Geth/Reth/etc.) ┌───────────────────────────────────────────────────────────────┐ │ Storage Backend │ │ (Shared data layer - DI injected) │ │ ┌────────────┐ ┌───────────┐ ┌─────────────────┐ ┌────────┐ │ │ │ BlockStore │ │ BeaconDB │ │AvailabilityStore│ │Deposit │ │ │ │ │ │ (StateDB) │ │ (Blob storage) │ │Store │ │ │ └────────────┘ └───────────┘ └─────────────────┘ └────────┘ │ └────────────────────────┬──────────────────────────────────────┘ │ accessed by ┌───────────────────┼───────────────────┐ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────────┐ ┌───────────────┐ │ Node API │ │ Validator │ │ Blockchain │ │ Server │ │ Service │ │ Service │ │(REST/HTTP) │ │ │ │ │ └─────────────┘ └─────────────────┘ └───────────────┘ Async Background Process: ┌────────────────────────────────────────────────────┐ │ Deposit Monitoring Flow │ │ Execution Layer → Deposit Contract → DepositStore │ └────────────────────────────────────────────────────┘ ``` **System Flow:** 1. **Service Registry** manages the lifecycle of all services in dependency order 2. **CometBFT Service** drives the entire system through ABCI callbacks 3. **Block Building**: CometBFT → PrepareProposal → Validator Service 4. **Block Processing**: CometBFT → ProcessProposal/FinalizeBlock → Blockchain Service 5. **State Updates**: Blockchain Service → State Processor → Storage Backend 6. **External Queries**: Node API → Storage Backend (independent of consensus flow) **Key Facts:** - Service Registry orchestrates startup/shutdown in correct order - CometBFT is the consensus driver, not a middle layer - Storage Backend is a passive resource, not an active service - Node API runs independently, only queries storage - Execution Engine communicates with external EL clients - Services must wait for dependencies (e.g., EngineClient blocks until EL is ready) ### Core Components **beacon/** - Consensus layer implementation - `blockchain/`: Core service handling block processing, state transitions, fork choice - Integrates with execution engine via Engine API - Manages block and blob storage - Handles deposit processing from execution layer - `validator/`: Block building and validation - Payload building coordination with execution client - Blob sidecar creation and bundling - Block proposal generation for CometBFT **state-transition/** - Beacon chain state transitions - Core state machine implementing Ethereum consensus specs - Handles validator lifecycle: activation, exits, slashing - Processes operations: deposits, withdrawals, attestations - Fork transition logic (Deneb → Electra) - Custom modifications: validator set cap, churn rules **node-core/** - Infrastructure and dependency injection - `components/`: All service providers for DI - Each component has a `Provide*` function - Dependencies declared via struct tags - `services/registry/`: Service lifecycle management - Start/stop ordering based on dependencies - Graceful shutdown handling - `builder/`: Node assembly and configuration **execution/** - Execution client integration - `client/`: Engine API implementation - JWT authenticated HTTP client - Retry logic with exponential backoff - Error classification (fatal vs retryable) - `deposit/`: Deposit contract monitoring - Syncs deposits from execution layer - Manages deposit Merkle tree - Supports all major EL clients via standard Engine API **storage/** - Multi-layered persistence - `beacondb/`: State storage with context management - Fork-aware state queries - Validator and balance lookups - `blockstore/`: KV store for beacon blocks - Indexed by slot number - Range query support - `availabilitystore/`: Blob sidecar storage - TTL-based pruning (availability window) - Indexed by block root and index - `depositstore/`: Deposit event tracking - Synced from execution layer logs **consensus-types/** - Core type definitions - Beacon chain types: blocks, states, validators - Fork-specific types with version handling - SSZ serialization for all consensus types - Generic interfaces for fork compatibility **da/** - Data availability layer - `blob/`: Blob and sidecar management - KZG commitment verification - Blob to sidecar transformation - `kzg/`: KZG ceremony integration - Trusted setup loading - Proof generation and verification ### Data Flow Patterns #### Block Production Flow 1. CometBFT calls `PrepareProposal` when node is proposer 2. Validator service initiates payload building: - Checks for cached FCU response first - If no cache: sends FCU with payload attributes to execution engine - Receives payload ID for tracking 3. Block assembly: - Waits briefly then calls `getPayload` to retrieve execution payload - Creates blob sidecars from blob transactions - Assembles beacon block with payload 4. Returns complete block to CometBFT for proposal #### Block Processing Flow 1. CometBFT calls `ProcessProposal` with new block 2. Blockchain service validates block structure 3. Blob processor verifies: - KZG proofs for all blobs - Blob count within limits 4. State processor performs validation 5. Execution engine validates via `newPayload` 6. Vote to accept/reject returned to CometBFT #### State Finalization Flow 1. CometBFT calls `FinalizeBlock` after consensus 2. State processor executes full state transition: - Process slots up to block slot - Apply block operations - Update validator balances 3. Storage backends persist: - Updated beacon state - Block and sidecars - State root mappings 4. Post-block FCU updates execution engine head ### Critical Paths **Block Production (must complete in ~1s):** 1. Initiate payload building immediately 2. Parallel assembly of beacon block components 3. Timeout handling for slow execution clients **Block Validation (must complete quickly):** 1. Structural validation first (fail fast) 2. Parallel blob verification 3. Execution payload validation last **State Transitions (deterministic execution):** 1. Slot processing (RANDAO, proposer selection) 2. Block processing (operations in order) 3. Epoch processing (validator updates) ## Key Types and Interfaces ### Core Interfaces - `ChainSpec` - Chain specification interface - `BeaconState` - Beacon chain state - `ExecutionPayload` - Execution layer payload - `AvailabilityStore` - Blob storage interface - `DepositStore` - Deposit storage interface - `BlockStore` - Block storage interface - `StateProcessor` - State transition processor ### Important Types - `types.BeaconBlock` - Beacon block structure - `types.Validator` - Validator information - `types.Deposit` - Deposit data - `engine.ExecutionEngine` - Execution engine client - `payload.PayloadBuilder` - Local payload builder ### Key Abstractions **StorageBackend Interface:** ```go type StorageBackend interface { AvailabilityStore() AvailabilityStore BlockStore() BlockStore DepositStore() DepositStore StateFromContext(ctx context.Context) BeaconState } ``` **StateProcessor Interface:** ```go type StateProcessor interface { ProcessSlot(BeaconState) (TransitionResult, error) ProcessBlock(BeaconState, BeaconBlock) (BeaconState, error) ProcessEpoch(BeaconState) (TransitionResult, error) } ``` **ExecutionEngine Interface:** ```go type ExecutionEngine interface { NewPayload(ctx, payload, versionedHashes) (PayloadStatus, error) ForkchoiceUpdate(ctx, state, attrs) (ForkchoiceResponse, error) GetPayload(ctx, payloadID) (ExecutionPayload, error) } ``` ## Integration Patterns ### CometBFT Integration (ABCI++) BeaconKit integrates with CometBFT through ABCI++ hooks: ```go // Key integration points in beacon/blockchain/service.go PrepareProposal(ctx, req) (*ProposalResponse, error) // Build blocks ProcessProposal(ctx, req) (*ProcessResponse, error) // Validate blocks FinalizeBlock(ctx, req) (*BlockResponse, error) // Execute state transition ``` **Important:** BeaconKit maps 1 beacon slot = 1 CometBFT height (no missed slots) ### Execution Engine Integration Communication with execution clients via Engine API: ```go // Engine API flow for block production 1. forkchoiceUpdate(head, safe, finalized, payloadAttributes) → payloadId 2. getPayload(payloadId) → executionPayload + blobsBundle 3. newPayload(executionPayload) → status 4. forkchoiceUpdate(newHead, safe, finalized) → status ``` **Key Files:** - `execution/client/client.go` - Main Engine API client - `execution/client/errors.go` - Error handling and retries - `execution/pkg/engine/helpers.go` - Request/response helpers ### State Management Integration State transitions follow a specific pattern: ```go // State transition pipeline ctx := state.Context() state = processSlots(state, targetSlot) if isEpochEnd(slot) { state = processEpoch(state) } state = processBlock(state, block) // Changes are cached and only flushed to disk on Finalize/Commit storage.SetState(ctx, state) ``` **Context Usage:** All state queries use context for fork-awareness ### Storage Layer Integration Multi-backend storage with clear interfaces: ```go // Storage access pattern backend := node.StorageBackend() state := backend.StateFromContext(ctx) block := backend.BlockStore().GetBySlot(slot) blobs := backend.AvailabilityStore().Get(blockRoot) deposits := backend.DepositStore().GetAll() ``` ### Service Lifecycle Integration Services follow a strict lifecycle pattern: ```go type Service interface { Start(context.Context) error Stop() error Name() string } ``` **Startup Order:** 1. Storage backends initialized 2. Core services created via DI 3. Services started in dependency order 4. CometBFT node started last **Shutdown:** Reverse order with graceful termination ### Configuration Integration Configuration flows through the system: ```toml # config.toml structure [beacon-kit] [beacon-kit.engine] jwt-secret-path = "path/to/jwt.hex" rpc-dial-url = "http://localhost:8551" [beacon-kit.payload-builder] enabled = true ``` **Environment Overrides:** CLI flags > env vars > config file > defaults ## Block Height Lifecycle This section describes how BeaconKit processes blocks using CometBFT's Tendermint consensus algorithm. ### Key Differences from Ethereum - **Timeout-Based Timing**: No fixed slot duration; block time depends on consensus timeouts and network conditions - **Sequential Heights**: CometBFT maintains sequential block heights without gaps (unlike Ethereum's slot system) - **Round-Based Consensus**: Multiple proposers per height if rounds fail - **Height = Slot**: CometBFT height maps 1:1 to beacon slot number ### Consensus Timing Configuration BeaconKit configures timeout values for CometBFT consensus: - **TimeoutCommit**: 500ms minimum - Post-commit wait time (enforced minimum) - **TimeoutPropose**: 2000ms maximum - Initial proposal timeout (enforced maximum) - **TimeoutPrevote**: 2000ms maximum - Prevote collection timeout (enforced maximum) - **TimeoutPrecommit**: 2000ms maximum - Precommit collection timeout (enforced maximum) **Note**: Only TimeoutCommit has an enforced minimum. The other timeouts have enforced maximums. Actual block times depend on: - Network latency and message propagation - Number of consensus rounds needed (failed rounds extend time) - Execution client response times - Validator participation and vote collection speed ### CometBFT Round-Based Consensus **Key Concept**: CometBFT uses rounds within each height. If consensus fails, it increments the round (not the height) and selects a new proposer. ``` Height N, Round 0: Proposer A fails/times out Height N, Round 1: Proposer B tries Height N, Round 2: Proposer C succeeds → Height N+1 ``` ### ABCI Method Flow #### 1. Block Proposal (PrepareProposal) **When**: Node is selected as proposer for current height/round **Called on**: Proposer node only **Can be called**: Multiple times per height (once per round if timeouts occur) **Steps**: 1. CometBFT calls `PrepareProposal` with height and round info 2. State is reset if this is a subsequent round (handles timeouts) 3. `ValidatorService.BuildBlockAndSidecars()` executes: - Sends `forkchoiceUpdate` with attributes to execution client - Receives payload ID - Calls `getPayload()` to retrieve execution payload - `BlobFactory` creates blob sidecars 4. Returns proposed block to CometBFT #### 2. Block Validation (ProcessProposal) **When**: Any node (including proposer) receives a proposed block **Called on**: ALL nodes **Purpose**: Validate proposal before voting **Steps**: 1. CometBFT calls `ProcessProposal` with proposed block 2. Resets `finalizeBlockState` in preparation 3. Blockchain Service validates: - Block structure and signatures - `BlobProcessor` verifies KZG proofs - Execution engine validates via `newPayload` (but doesn't commit) 4. Returns ACCEPT or REJECT to CometBFT #### 3. Consensus Voting Rounds **After ProcessProposal returns ACCEPT**: 1. **Prevote Phase**: - Validators broadcast prevotes for the proposal - Wait up to TimeoutPrevote for 2/3+ prevotes 2. **Precommit Phase**: - If 2/3+ prevotes received, broadcast precommit - Wait up to TimeoutPrecommit for 2/3+ precommits 3. **Commit Decision**: - If 2/3+ precommits received, block is decided - Wait TimeoutCommit before moving to next height If any phase fails/times out → new round at same height #### 4. Block Finalization (FinalizeBlock) **When**: After consensus achieved (2/3+ precommits) **Called on**: ALL nodes **Called**: Exactly once per height (not per round) **Steps**: 1. CometBFT calls `FinalizeBlock` with decided block 2. State Processor executes state transition: - Applies all block operations - Updates validator balances and registry - Processes epoch transitions if applicable 3. Commits to storage: - Beacon state → BeaconDB - Block → BlockStore - Blob sidecars → AvailabilityStore 4. Sends post-finalization `forkchoiceUpdate` to execution client 5. CometBFT advances to next height ### Important Characteristics **Height Progression**: - Heights only increment after successful FinalizeBlock - Multiple rounds can occur at the same height - Each round gets a new proposer (deterministic selection) **State Management**: - ProcessProposal validates but doesn't commit - FinalizeBlock performs actual state mutations - State can be reset between rounds at same height **Sequential Block Heights**: - BeaconKit's `ProcessSlots` called for every sequential height - No gaps in block heights (unlike Ethereum's slot system) - Failed proposals trigger new rounds at same height, not height skips ### Failure Scenarios - **Proposer Timeout**: New round with different proposer at same height - **Invalid Proposal**: Rejected in ProcessProposal, new round begins - **Insufficient Votes**: Timeout triggers new round - **Network Partition**: Consensus halts until 2/3+ validators connected - **Execution Client Issues**: Proposal fails, new round attempted This architecture ensures continuous block production through CometBFT's robust round-based consensus, maintaining Byzantine fault tolerance with up to 1/3 malicious validators. ### Critical Integration Points 1. **Block Production Timing:** - Must complete within slot duration - Timeout handling for slow execution clients - Parallel preparation of components 2. **State Consistency:** - CometBFT app hash = beacon state root - Execution payload state root verification - Fork choice alignment with execution client 3. **Deposit Bridge:** - Monitors execution layer deposit events - Maintains deposit Merkle tree - Synchronizes with beacon state 4. **Blob Handling:** - KZG verification in consensus layer - Blob propagation separate from blocks - Pruning after availability window ### Component Dependencies The system uses `cosmossdk.io/depinject` for dependency injection: ```go // Example component provider func ProvideBlockchainService( in struct { depinject.In ChainSpec chain.ChainSpec ExecutionEngine ExecutionEngine LocalBuilder LocalBuilder StateProcessor StateProcessor StorageBackend StorageBackend TelemetrySink TelemetrySink }, ) *Service { // Component initialization } ``` **Dependency Graph:** - Node → CometBFT Service → Blockchain Service - Blockchain → State Processor, Execution Engine, Storage - State Processor → Chain Spec, Execution Engine - All components → Logger, Metrics, Config ## Storage Architecture **Multi-Backend Approach:** 1. **CometBFT State**: Application state via IAVL trees 2. **BeaconDB**: Beacon state indexed by StateRoot 3. **BlockStore**: Blocks indexed by slot 4. **AvailabilityStore**: Blobs with pruning 5. **FileDB**: Generic KV store implementation **State Management:** - StateDB provides high-level API - Context-based forking for speculation - Lazy loading for performance - Cache layers for hot data ## Error Handling - Custom error wrapper in `errors/mod.go` - Fatal vs non-fatal errors with `IsFatal()` checks - Consistent error wrapping with context - Detailed error types for different failure modes ## Build Requirements ### Dependencies - Go - Docker (for running EL clients) - Foundry (for Solidity contracts) - Make (GNU Make) ### Build Tags - `bls12381` - BLS cryptography - `test` - Testing utilities - `e2e` - End-to-end tests - `simulated` - Simulation tests ### Key Constants - `RootLength = 32` - Hash tree root length - Default RPC timeout: 30s - Default shutdown timeout: 5 minutes - Block store availability window: configurable via chain spec ## Development Considerations ### Key Design Patterns 1. **Interface Segregation**: Small, focused interfaces for each concern 2. **Dependency Injection**: All wiring via DI container, no global state 3. **Context Propagation**: Request-scoped values and cancellation 4. **Error Wrapping**: Detailed context preservation with error chains 5. **Metrics-First**: Every operation instrumented with Prometheus 6. **Defensive Validation**: Validate early, validate often 7. **Fork Abstraction**: Generic types handle fork differences ### Testing Approach - Unit tests alongside code files (`*_test.go`) - Simulated tests for chaos/fork scenarios in `testing/` - E2E tests with real execution clients in `testing/e2e/` - Kurtosis for multi-node testing scenarios ================================================ FILE: CODEOWNERS ================================================ * @berachain/core-admin ================================================ FILE: Dockerfile ================================================ # syntax=docker/dockerfile:1 # # Copyright (C) 2022, Berachain Foundation. All rights reserved. # See the file LICENSE for licensing terms. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ####################################################### ### Stage 0 - Build Arguments ### ####################################################### ARG GO_VERSION ARG RUNNER_IMAGE=alpine:3.20 ARG BUILD_TAGS="netgo,muslc,blst,bls12381,pebbledb" ARG NAME=beacond ARG APP_NAME=beacond ARG DB_BACKEND=pebbledb ARG CMD_PATH=./cmd/beacond ####################################################### ### Stage 1 - Cache Go Modules ### ####################################################### FROM golang:${GO_VERSION}-alpine AS mod-cache WORKDIR /workdir RUN apk add --no-cache git # Download Go modules COPY ./go.mod ./go.sum ./ RUN --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/root/go/pkg/mod \ go mod download ####################################################### ### Stage 2 - Build the Application ### ####################################################### FROM golang:${GO_VERSION}-alpine AS builder ARG GIT_VERSION ARG GIT_COMMIT ARG BUILD_TAGS # Set the working directory WORKDIR /workdir # Consolidate RUN commands to reduce layers RUN apk add --no-cache --update \ ca-certificates \ build-base # Copy the dependencies from the cache stage COPY --from=mod-cache /go/pkg /go/pkg # Copy all the source code (this will ignore files/dirs in .dockerignore) COPY ./ ./ # Build args ARG NAME ARG APP_NAME ARG DB_BACKEND ARG CMD_PATH # Build beacond RUN --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/root/go/pkg/mod \ env NAME=${NAME} DB_BACKEND=${DB_BACKEND} APP_NAME=${APP_NAME} CGO_ENABLED=1 && \ go build \ -mod=readonly \ -tags ${BUILD_TAGS} \ -ldflags "-X github.com/cosmos/cosmos-sdk/version.Name=${NAME} \ -X github.com/cosmos/cosmos-sdk/version.AppName=${APP_NAME} \ -X github.com/cosmos/cosmos-sdk/version.Version=${GIT_VERSION} \ -X github.com/cosmos/cosmos-sdk/version.Commit=${GIT_COMMIT} \ -X github.com/cosmos/cosmos-sdk/version.BuildTags=${BUILD_TAGS} \ -X github.com/cosmos/cosmos-sdk/types.DBBackend=$DB_BACKEND \ -w -s -linkmode=external -extldflags '-Wl,-z,muldefs -static'" \ -trimpath \ -o /workdir/build/bin/beacond \ ${CMD_PATH} ####################################################### ### Stage 3 - Prepare the Final Image ### ####################################################### FROM ${RUNNER_IMAGE} # Build args ARG APP_NAME # Copy over built executable into a fresh container COPY --from=builder /workdir/build/bin/${APP_NAME} /usr/bin/${APP_NAME} # TODO: We should un hood this part, its very specific # to our kurtosis setup. RUN mkdir -p /root/jwt /root/kzg && \ apk add --no-cache bash sed curl jq EXPOSE 26656 EXPOSE 26657 ENTRYPOINT [ "beacond" ] ================================================ FILE: LICENSE ================================================ Business Source License 1.1 License text copyright © 2023 MariaDB plc, All Rights Reserved. “Business Source License” is a trademark of MariaDB plc. ----------------------------------------------------------------------------- Parameters Licensor: Berachain Foundation Licensed Work: BeaconKit The Licensed Work is (c) 2025 Berachain Foundation Additional Use Grant: Please contact founders@berachain.com Change Date: 2026-01-31 Change License: MIT License For information about alternative licensing arrangements for the Software, please contact Berachain: https://berachain.com ----------------------------------------------------------------------------- Terms The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use. Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate. If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work. All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor. You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work. Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work. This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License). TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE. MariaDB hereby grants you permission to use this License’s text to license your works, and to refer to it using the trademark “Business Source License”, as long as you comply with the Covenants of Licensor below. ----------------------------------------------------------------------------- Covenants of Licensor In consideration of the right to use this License’s text and the “Business Source License” name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor: 1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where “compatible” means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation. 2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text “None”. 3. To specify a Change Date. 4. Not to modify this License in any other way. ----------------------------------------------------------------------------- Notice The Business Source License (this document, or the “License”) is not an Open Source license. However, the Licensed Work will eventually be made available under an Open Source License, as stated in this License. For more information on the use of the Business Source License for MariaDB products, please visit the MariaDB Business Source License FAQ at https://mariadb.com/bsl-faq-mariadb. For more information on the use of the Business Source License generally, please visit the Adopting and Developing Business Source License FAQ at https://mariadb.com/bsl-faq-adopting. ================================================ FILE: LICENSE.header ================================================ SPDX-License-Identifier: BUSL-1.1 Copyright (C) 2025, Berachain Foundation. All rights reserved. Use of this software is governed by the Business Source License included in the LICENSE file of this repository and at www.mariadb.com/bsl11. ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER VERSIONS OF THE LICENSED WORK. THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE. ================================================ FILE: Makefile ================================================ #!/usr/bin/make -f include scripts/build/build.mk include scripts/build/codegen.mk include scripts/build/constants.mk include scripts/build/devtools.mk include scripts/build/linting.mk include scripts/build/protobuf.mk include scripts/build/release.mk include scripts/build/testing.mk include contracts/Makefile include kurtosis/Makefile include scripts/build/help.mk include testing/forge-script/Makefile # Specify the default target if none is provided .DEFAULT_GOAL := build ROOT_DIR := $(shell pwd) ############################################################################## ### Dependencies ### ############################################################################### .PHONY: clean format lint \ buf-install proto-clean \ test-unit test-unit-cover test-simulated test-forge-cover test-forge-fuzz \ forge-snapshot forge-snapshot-diff \ test-e2e test-e2e-no-build \ forge-lint-fix forge-lint golangci-install golangci golangci-fix \ license license-fix \ gosec vulncheck golines repo-rinse proto build ================================================ FILE: README.md ================================================

Berachain's Consensus Client

[![CI status](https://github.com/berachain/beacon-kit/workflows/pipeline/badge.svg)](https://github.com/berachain/beacon-kit/actions/workflows/pipeline.yml) [![Deps status](https://github.com/berachain/beacon-kit/workflows/deps/badge.svg)](https://github.com/berachain/beacon-kit/actions/workflows/vuln-and-dep-check.yml) [![CodeCov](https://codecov.io/gh/berachain/beacon-kit/graph/badge.svg?token=0l5iJ3ZbzV)](https://codecov.io/gh/berachain/beacon-kit) [![Telegram Chat](https://img.shields.io/endpoint?color=neon&logo=telegram&label=chat&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fbeacon_kit)](https://t.me/beacon_kit) [![X Follow](https://img.shields.io/twitter/follow/berachain)](https://x.com/berachain) [![Discord](https://img.shields.io/discord/924442927399313448?label=discord)](https://discord.gg/berachain)
## What is BeaconKit? BeaconKit is Berachain's consensus client. It implements the Ethereum consensus layer specification with Berachain-specific modifications, using a modified [CometBFT](https://github.com/berachain/cometbft) for consensus instead of Ethereum's standard beacon chain consensus. Berachain is a high-performance L1 blockchain powered by [Proof of Liquidity](https://docs.berachain.com/general/introduction/what-is-proof-of-liquidity) (PoL), an incentive mechanism that aligns validators, protocols, and users through its three-token system (BERA, BGT, HONEY). BeaconKit communicates with [Bera-Reth](https://github.com/berachain/bera-reth) (the execution client) via the standard [Engine API](https://github.com/ethereum/execution-apis/blob/main/src/engine), forming the two-client architecture used by Berachain nodes. ### Key Differences from Ethereum - **CometBFT Consensus** — Uses timeout-based rounds instead of fixed 12-second slots. If a proposer fails, a new round starts at the same height with a different proposer. - **Single-Slot Finality** — Blocks are finalized immediately when 2/3+ validators commit, unlike Ethereum's ~13-minute finalization through Casper FFG checkpoints. - **No Missed Slots** — Block heights are strictly sequential with no gaps. Every height eventually produces a block through round-based consensus. - **No Attestations or Committees** — Consensus is driven by CometBFT's validator voting (prevotes/precommits) rather than Ethereum's attestation committees and sync committees. - **Capped Validator Set** — The active validator set is capped (currently 69 validators) rather than being open-ended. - **EVM Inflation Withdrawal** — Every block includes a mandatory EVM inflation withdrawal as its first withdrawal, a Berachain-specific economic mechanism. ## Networks | Network | Chain ID | Description | |---------|----------|-------------| | **Mainnet** | 80094 | Production network | | **Bepolia** | 80069 | Public testnet | | **Devnet** | 80087 | Local development | Network configurations are stored in `testing/networks//`. ## Execution Client BeaconKit requires [**Bera-Reth**](https://github.com/berachain/bera-reth), a Berachain-specific fork of [Reth](https://github.com/paradigmxyz/reth). Communication happens over the Engine API with JWT authentication. ## Quick Start ### Prerequisites - [Docker](https://docs.docker.com/engine/install/) - [Golang](https://go.dev/doc/install) - [Foundry](https://book.getfoundry.sh/) Open two terminals side by side. **Terminal 1** — Start the consensus client: ```bash make start ``` **Terminal 2** — Start the execution client (after `beacond` is running, since `make start` generates the execution genesis file): ```bash make start-reth ``` The devnet runs with chain ID **80087**. The following dev account is preloaded with the native token: ``` Address: 0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4 Private Key: 0xfffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306 ``` ### Multinode Devnet (Kurtosis) For running a multinode local devnet using [Kurtosis](https://www.kurtosis.com/): ```bash make start-devnet ``` See the [Kurtosis README](kurtosis/README.md) for full details on configuration and usage. ## Project Structure ``` beacon/ Core beacon chain logic (blockchain service, validator service) chain/ Chain specifications and network configs cli/ CLI commands and configuration config/ Configuration templates (TOML) consensus-types/ Consensus layer types (blocks, states, validators, SSZ) contracts/ Solidity contracts (deposit contract, staking) da/ Data availability (blob management, KZG commitments) engine-primitives/ Execution engine types (Engine API types, payloads) execution/ Execution client integration (Engine API client, deposit syncing) kurtosis/ Kurtosis multinode devnet deployment node-api/ REST API implementation (beacon API handlers) node-core/ Core infrastructure (dependency injection, service registry) primitives/ Basic types and constants (Slot, Gwei, ValidatorIndex) state-transition/ State transition logic (state machine, fork transitions) storage/ Database backends (block store, blob store, beacon DB) testing/ Test utilities, network configs, e2e and simulation tests ``` ## Development ### Building ```bash make build # Build beacond binary to build/bin/beacond make install # Install beacond to $GOPATH/bin make build-docker # Build Docker image ``` ### Testing ```bash make test # Run all tests (unit + forge) make test-unit # Run unit tests with coverage make test-unit-bench # Run benchmarks make test-unit-fuzz # Run Go fuzz tests make test-simulated # Run simulation tests make test-e2e # Run e2e tests (builds Docker image first) make test-forge-cover # Run Solidity tests with coverage ``` ### Linting & Formatting ```bash make lint # Run all linters make format # Run all formatters make golangci-fix # Auto-fix Go linting issues make gosec # Run security scanner make nilaway # Run nil pointer checker make vulncheck # Run govulncheck vulnerability scanner ``` ### Code Generation ```bash make generate # Run all code generation make proto # Generate protobuf code make generate-check # Verify generated code is up to date ``` ## Documentation - [Berachain Docs](https://docs.berachain.com/) — Official documentation - [What is BeaconKit](https://docs.berachain.com/validators/beaconkit/overview) — Conceptual overview - [Node Quickstart](https://docs.berachain.com/validators/operations/quickstart) — Deploy a mainnet or testnet node - [Docker Devnet Guide](https://docs.berachain.com/validators/guides/local-devnet-docker) — Run a devnet with Docker - [Kurtosis Guide](https://docs.berachain.com/validators/guides/local-devnet-kurtosis) — Multinode deployment with Kurtosis - [Kurtosis README](kurtosis/README.md) — Local Kurtosis configuration and usage ## License BeaconKit is licensed under [BUSL-1.1](LICENSE). ================================================ FILE: beacon/blockchain/common.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/math" ) func (s *Service) ParseBeaconBlock(req encoding.ABCIRequest) ( *ctypes.SignedBeaconBlock, types.BlobSidecars, error, ) { if countTx := len(req.GetTxs()); countTx > MaxConsensusTxsCount { return nil, nil, fmt.Errorf("max expected %d, got %d: %w", MaxConsensusTxsCount, countTx, ErrTooManyConsensusTxs, ) } forkVersion := s.chainSpec.ActiveForkVersionForTimestamp(math.U64(req.GetTime().Unix())) //#nosec: G115 // Decode signed block and sidecars. signedBlk, sidecars, err := encoding.ExtractBlobsAndBlockFromRequest( req, BeaconBlockTxIndex, BlobSidecarsTxIndex, forkVersion, ) if err != nil { return nil, nil, err } if signedBlk == nil { s.logger.Warn( "Aborting block verification - beacon block not found in proposal", ) return nil, nil, ErrNilBlk } if sidecars == nil { s.logger.Warn( "Aborting block verification - blob sidecars not found in proposal", ) return nil, nil, ErrNilBlob } return signedBlk, sidecars, nil } ================================================ FILE: beacon/blockchain/deposit.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "context" "maps" "slices" "strconv" "time" "github.com/berachain/beacon-kit/primitives/math" ) // defaultRetryInterval processes a deposit event. const defaultRetryInterval = 20 * time.Second func (s *Service) depositFetcher( ctx context.Context, blockNum math.U64, ) { if blockNum <= s.eth1FollowDistance { s.logger.Info( "depositFetcher, nothing to fetch", "block num", blockNum, "eth1FollowDistance", s.eth1FollowDistance, ) return } s.fetchAndStoreDeposits(ctx, blockNum-s.eth1FollowDistance) } // fetchAndStoreDeposits processes all deposits at a particular EL block height. // TODO: This could be optimized to process a contiguous range of blocks simultaneously to minimize EL RPC calls. func (s *Service) fetchAndStoreDeposits( ctx context.Context, blockNum math.U64, ) { blockNumStr := strconv.FormatUint(blockNum.Unwrap(), 10) deposits, err := s.depositContract.ReadDeposits(ctx, blockNum, blockNum) if err != nil { s.logger.Error("Failed to read deposits", "error", err) s.metrics.sink.IncrementCounter( "beacon_kit.execution.deposit.failed_to_get_block_logs", "block_num", blockNumStr, ) s.failedBlocksMu.Lock() s.failedBlocks[blockNum] = struct{}{} s.failedBlocksMu.Unlock() return } if len(deposits) > 0 { s.logger.Info( "Found deposits on execution layer", "block", blockNum, "deposits", len(deposits), ) } if err = s.storageBackend.DepositStore().EnqueueDeposits(ctx, deposits); err != nil { s.logger.Error("Failed to store deposits", "error", err) s.metrics.sink.IncrementCounter( "beacon_kit.execution.deposit.failed_to_enqueue_deposits", "block_num", blockNumStr, ) s.failedBlocksMu.Lock() s.failedBlocks[blockNum] = struct{}{} s.failedBlocksMu.Unlock() return } s.failedBlocksMu.Lock() delete(s.failedBlocks, blockNum) s.failedBlocksMu.Unlock() } func (s *Service) depositCatchupFetcher(ctx context.Context) { ticker := time.NewTicker(defaultRetryInterval) defer ticker.Stop() for { select { case <-ctx.Done(): return case <-ticker.C: s.failedBlocksMu.RLock() failedBlks := slices.Collect(maps.Keys(s.failedBlocks)) s.failedBlocksMu.RUnlock() if len(failedBlks) == 0 { continue } s.logger.Warn( "Failed to get deposits from block(s), retrying...", "num_blocks", failedBlks, ) // Fetch deposits for blocks that failed to be processed. // TODO: This can be optimized to process all the blocks queried at once by utilizing log query ranges // for contiguous ranges of blocks for _, blockNum := range failedBlks { s.fetchAndStoreDeposits(ctx, blockNum) } } } } ================================================ FILE: beacon/blockchain/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import "github.com/berachain/beacon-kit/errors" var ( // ErrTooManyConsensusTxs is an error for consensus blocks having more than MaxConsensusTxsCount txs. ErrTooManyConsensusTxs = errors.New("too many consensus txs") // ErrUnexpectedBlockSlot is an error for consensus blocks with non consecutive slots. ErrUnexpectedBlockSlot = errors.New("unexpected block slot") // ErrNilBlk is an error for when the beacon block is nil. ErrNilBlk = errors.New("nil beacon block") // ErrNilBlob is an error for when the BlobSidecars is nil. ErrNilBlob = errors.New("nil blob") // ErrVersionMismatch is an error for when the fork for the block timestamp does not match the fork // for the ABCI timestamp. ErrVersionMismatch = errors.New("ABCI fork version mismatch") // ErrDataNotAvailable indicates that the required data is not available. ErrDataNotAvailable = errors.New("data not available") // ErrSidecarCommitmentMismatch indicates that the BeaconBlockBody commitments do not match the sidecars. ErrSidecarCommitmentMismatch = errors.New("sidecars commitments mismatch") // ErrSidecarSignatureMismatch indicates that the sidecar signature is invalid. ErrSidecarSignatureMismatch = errors.New("sidecar signature mismatch") ) ================================================ FILE: beacon/blockchain/execution_engine.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "context" "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" statedb "github.com/berachain/beacon-kit/state-transition/core/state" ) // sendPostBlockFCU sends a forkchoice update to the execution client after a // block is finalized. func (s *Service) sendPostBlockFCU( ctx context.Context, st *statedb.StateDB, ) error { lph, err := st.GetLatestExecutionPayloadHeader() if err != nil { return fmt.Errorf("failed getting latest payload: %w", err) } // Send a forkchoice update without payload attributes to notify EL of the new head. // Note that we are being conservative here as we don't mark the block we just finalized // (which is irreversible due to CometBFT SSF) as final. If we keep doing this, we can // spare the FCU update in case we have optimistic block building on, as we may have // already sent the very same FCU request after we verified the block. fcuData := &engineprimitives.ForkchoiceStateV1{ HeadBlockHash: lph.GetBlockHash(), SafeBlockHash: lph.GetParentHash(), FinalizedBlockHash: lph.GetParentHash(), } latestRequestedFCU := s.latestFcuReq.Load() s.latestFcuReq.Store(&engineprimitives.ForkchoiceStateV1{}) // reset and prepare for next block if latestRequestedFCU.Equals(fcuData) { // we already sent the same FCU, likely due to optimistic block building // being active. Avoid re-issuing the same request. return nil } req := ctypes.BuildForkchoiceUpdateRequestNoAttrs( fcuData, s.chainSpec.ActiveForkVersionForTimestamp(lph.GetTimestamp()), ) if _, err = s.executionEngine.NotifyForkchoiceUpdate(ctx, req); err != nil { return fmt.Errorf("failed forkchoice update, head %s: %w", lph.GetBlockHash().String(), err, ) } return nil } ================================================ FILE: beacon/blockchain/finalize_block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "context" "fmt" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/types" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" statedb "github.com/berachain/beacon-kit/state-transition/core/state" cmtabci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" ) func (s *Service) FinalizeBlock( ctx sdk.Context, req *cmtabci.FinalizeBlockRequest, ) (transition.ValidatorUpdates, error) { // STEP 1: Decode block and blobs. signedBlk, blobs, err := s.ParseBeaconBlock(req) if err != nil { s.logger.Error("Failed to decode block and blobs", "error", err) return nil, fmt.Errorf("failed to decode block and blobs: %w", err) } blk := signedBlk.GetBeaconBlock() st := s.storageBackend.StateFromContext(ctx) // Send an FCU to force the HEAD of the chain on the EL on startup. var finalizeErr error s.forceStartupSyncOnce.Do(func() { var parentProposerPubkey *crypto.BLSPubkey parentProposerPubkey, finalizeErr = st.ParentProposerPubkey(blk.GetTimestamp()) if finalizeErr != nil { finalizeErr = fmt.Errorf("force sync upon finalize: failed retrieving parent proposer pubkey: %w", finalizeErr) } else { finalizeErr = s.forceSyncUponFinalize(ctx, blk, parentProposerPubkey) } }) if finalizeErr != nil { return nil, finalizeErr } // STEP 2: Finalize sidecars first (block will check for sidecar availability). if err = s.FinalizeSidecars(ctx, req.SyncingToHeight, blk, blobs); err != nil { return nil, fmt.Errorf("failed finalizing sidecars: %w", err) } // STEP 3: Finalize the block. consensusBlk := types.NewConsensusBlock(blk, req.GetProposerAddress(), req.GetTime()) valUpdates, err := s.finalizeBeaconBlock(ctx, st, consensusBlk) if err != nil { s.logger.Error("Failed to process verified beacon block", "error", err, ) return nil, err } // STEP 4: Post Finalizations cleanups. return valUpdates, s.PostFinalizeBlockOps(ctx, blk) } func (s *Service) FinalizeSidecars( ctx sdk.Context, syncingToHeight int64, blk *ctypes.BeaconBlock, blobs datypes.BlobSidecars, ) error { // SyncingToHeight is always the tip of the chain both during sync and when // caught up. We don't need to process sidecars unless they are within DA period. // //#nosec: G115 // SyncingToHeight will never be negative. if s.chainSpec.WithinDAPeriod(blk.GetSlot(), math.Slot(syncingToHeight)) { err := s.blobProcessor.ProcessSidecars( s.storageBackend.AvailabilityStore(), blobs, ) if err != nil { s.logger.Error("Failed to process blob sidecars", "error", err) return fmt.Errorf("failed to process blob sidecars: %w", err) } // Ensure we can access the data using the commitments from the block. if !s.storageBackend.AvailabilityStore().IsDataAvailable( ctx, blk.GetSlot(), blk.GetBody(), ) { return ErrDataNotAvailable } return nil } // Here outside Data Availability window. Just log if needed if len(blobs) > 0 { s.logger.Info( "Skipping blob processing outside of Data Availability Period", "slot", blk.GetSlot().Base10(), "head", syncingToHeight, ) } return nil } func (s *Service) PostFinalizeBlockOps(ctx sdk.Context, blk *ctypes.BeaconBlock) error { // TODO: consider extracting LatestExecutionPayloadHeader instead of using state here st := s.storageBackend.StateFromContext(ctx) // Fetch and store the deposit for the block. blockNum := blk.GetBody().GetExecutionPayload().GetNumber() s.depositFetcher(ctx, blockNum) // Store the finalized block in the KVStore. slot := blk.GetSlot() if err := s.storageBackend.BlockStore().Set(blk); err != nil { s.logger.Error( "failed to store block", "slot", slot, "error", err, ) return err } // Prune the availability and deposit store. if err := s.processPruning(ctx, blk); err != nil { s.logger.Error("failed to processPruning", "error", err) } if err := s.sendPostBlockFCU(ctx, st); err != nil { return fmt.Errorf("sendPostBlockFCU failed: %w", err) } // reset latest verified payload in block builder to signal // that no payload is available to reuse for blk.Slot s.localBuilder.CacheLatestVerifiedPayload(blk.Slot, nil) return nil } // finalizeBeaconBlock receives an incoming beacon block, it first validates // and then processes the block. func (s *Service) finalizeBeaconBlock( ctx context.Context, st *statedb.StateDB, blk *types.ConsensusBlock, ) (transition.ValidatorUpdates, error) { beaconBlk := blk.GetBeaconBlock() // If the block is nil, exit early. if beaconBlk == nil { return nil, ErrNilBlk } valUpdates, err := s.executeStateTransition(ctx, st, blk) if err != nil { return nil, err } return valUpdates.CanonicalSort(), nil } // executeStateTransition runs the stf. func (s *Service) executeStateTransition( ctx context.Context, st *statedb.StateDB, blk *types.ConsensusBlock, ) (transition.ValidatorUpdates, error) { startTime := time.Now() defer s.metrics.measureStateTransitionDuration(startTime) // Notes about context attributes: // - VerifyPayload: set to true. When we are NOT synced to the tip, // process proposal does NOT get called and thus we must ensure that // NewPayload is called to get the execution client the payload. // When we are synced to the tip, we can skip the // NewPayload call since we already gave our execution client // the payload in process proposal. // In both cases the payload was already accepted by a majority // of validators in their process proposal call and thus // the "verification aspect" of this NewPayload call is // actually irrelevant at this point. // - VerifyRandao: set to false. We skip randao validation in FinalizeBlock // since either // 1. we validated it during ProcessProposal at the head of the chain OR // 2. we are bootstrapping and implicitly trust that the randao was validated by // the super majority during ProcessProposal of the given block height. txCtx := transition.NewTransitionCtx( ctx, blk.GetConsensusTime(), blk.GetProposerAddress(), ). WithVerifyPayload(true). WithVerifyRandao(false). WithVerifyResult(false). WithMeterGas(true) return s.stateProcessor.Transition( txCtx, st, blk.GetBeaconBlock(), ) } ================================================ FILE: beacon/blockchain/init_chain.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "context" "encoding/json" "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/primitives/version" ) // ProcessGenesisData processes the genesis state and initializes the beacon state. func (s *Service) ProcessGenesisData( ctx context.Context, bytes []byte, ) (transition.ValidatorUpdates, error) { genesisData := ctypes.Genesis{} if err := json.Unmarshal(bytes, &genesisData); err != nil { s.logger.Error("Failed to unmarshal genesis data", "error", err) return nil, err } // Ensure consistency of the genesis timestamp. execPayloadHeader := genesisData.GetExecutionPayloadHeader() if s.chainSpec.GenesisTime() != execPayloadHeader.GetTimestamp().Unwrap() { return nil, fmt.Errorf( "mismatch between chain spec genesis time (%d) and execution payload header time (%d)", s.chainSpec.GenesisTime(), execPayloadHeader.GetTimestamp().Unwrap(), ) } // Ensure consistency of the genesis fork version. genesisVersion := genesisData.GetForkVersion() if !version.Equals(genesisVersion, s.chainSpec.GenesisForkVersion()) { return nil, fmt.Errorf( "fork mismatch between CL genesis file version (%s) and chain spec genesis version (%s)", genesisVersion, s.chainSpec.GenesisForkVersion(), ) } // Initialize the beacon state from the genesis deposits. validatorUpdates, err := s.stateProcessor.InitializeBeaconStateFromEth1( s.storageBackend.StateFromContext(ctx), genesisData.GetDeposits(), execPayloadHeader, genesisVersion, ) if err != nil { return nil, err } // After deposits are validated, store the genesis deposits in the deposit store. if err = s.storageBackend.DepositStore().EnqueueDeposits( ctx, genesisData.GetDeposits(), ); err != nil { return nil, err } return validatorUpdates, nil } ================================================ FILE: beacon/blockchain/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "context" "time" "github.com/berachain/beacon-kit/chain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" dastore "github.com/berachain/beacon-kit/da/store" datypes "github.com/berachain/beacon-kit/da/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/state-transition/core" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage/block" "github.com/berachain/beacon-kit/storage/deposit" cmtabci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" ) // ExecutionEngine is the interface for the execution engine. type ExecutionEngine interface { // NotifyNewPayload notifies the execution client of new payload. NotifyNewPayload( ctx context.Context, req ctypes.NewPayloadRequest, retryOnSyncingStatus bool, ) error // NotifyForkchoiceUpdate notifies the execution client of a forkchoice // update. NotifyForkchoiceUpdate( ctx context.Context, req *ctypes.ForkchoiceUpdateRequest, ) (*engineprimitives.PayloadID, error) } // LocalBuilder is the interface for the builder service. type LocalBuilder interface { // Enabled returns true if the local builder is enabled. Enabled() bool // RequestPayloadAsync requests a new payload for the given slot. RequestPayloadAsync( ctx context.Context, r *builder.RequestPayloadData, ) (*engineprimitives.PayloadID, common.Version, error) CacheLatestVerifiedPayload( latestEnvelopeSlot math.Slot, latestEnvelope ctypes.BuiltExecutionPayloadEnv, ) } // StateProcessor defines the interface for processing various state transitions // in the beacon chain. type StateProcessor interface { // InitializeBeaconStateFromEth1 initializes the premined beacon // state from the eth1 deposits. InitializeBeaconStateFromEth1( *statedb.StateDB, ctypes.Deposits, *ctypes.ExecutionPayloadHeader, common.Version, ) (transition.ValidatorUpdates, error) // ProcessFork prepares the state for the fork version at the given timestamp. ProcessFork( st *statedb.StateDB, timestamp math.U64, logUpgrade bool, ) error // ProcessSlots processes the state transition for a range of slots. ProcessSlots( *statedb.StateDB, math.Slot, ) (transition.ValidatorUpdates, error) // Transition processes the state transition for a given block. Transition( core.ReadOnlyContext, *statedb.StateDB, *ctypes.BeaconBlock, ) (transition.ValidatorUpdates, error) GetSignatureVerifierFn(*statedb.StateDB) ( func( blk *ctypes.BeaconBlock, signature crypto.BLSSignature) error, error, ) } // StorageBackend defines an interface for accessing various storage components // required by the beacon node. type StorageBackend interface { // AvailabilityStore returns the availability store for the given context. AvailabilityStore() *dastore.Store // StateFromContext retrieves the beacon state from the given context. StateFromContext(context.Context) *statedb.StateDB // DepositStore retrieves the deposit store. DepositStore() deposit.StoreManager // BlockStore retrieves the block store. BlockStore() *block.KVStore[*ctypes.BeaconBlock] } // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { // IncrementCounter increments the counter identified by // the provided key. IncrementCounter(key string, args ...string) // MeasureSince measures the time since the provided start time, // identified by the provided keys. MeasureSince(key string, start time.Time, args ...string) } //nolint:revive // its ok type BlockchainI interface { ProcessGenesisData( context.Context, []byte, ) (transition.ValidatorUpdates, error) ParseBeaconBlock(req encoding.ABCIRequest) ( *ctypes.SignedBeaconBlock, datypes.BlobSidecars, error, ) ProcessProposal( sdk.Context, *cmtabci.ProcessProposalRequest, []byte, // this node address ) (transition.ValidatorUpdates, error) FinalizeSidecars( ctx sdk.Context, syncingToHeight int64, blk *ctypes.BeaconBlock, blobs datypes.BlobSidecars, ) error FinalizeBlock( sdk.Context, *cmtabci.FinalizeBlockRequest, ) (transition.ValidatorUpdates, error) PostFinalizeBlockOps( sdk.Context, *ctypes.BeaconBlock, ) error PruneOrphanedBlobs(lastBlockHeight int64) error } // BlobProcessor is the interface for the blobs processor. type BlobProcessor interface { // ProcessSidecars processes the blobs and ensures they match the local // state. ProcessSidecars( avs *dastore.Store, sidecars datypes.BlobSidecars, ) error // VerifySidecars verifies the blobs and ensures they match the local state. VerifySidecars( ctx context.Context, sidecars datypes.BlobSidecars, blkHeader *ctypes.BeaconBlockHeader, kzgCommitments eip4844.KZGCommitments[common.ExecutionHash], ) error } type PruningChainSpec interface { MinEpochsForBlobsSidecarsRequest() math.Epoch SlotsPerEpoch() uint64 } type ServiceChainSpec interface { PruningChainSpec chain.BlobSpec chain.ForkSpec chain.ForkVersionSpec delay.ConfigGetter EpochsPerHistoricalVector() uint64 SlotToEpoch(slot math.Slot) math.Epoch Eth1FollowDistance() uint64 } ================================================ FILE: beacon/blockchain/metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "time" "github.com/berachain/beacon-kit/primitives/math" ) // chainMetrics is a struct that contains metrics for the chain. type chainMetrics struct { // sink is the sink for the metrics. sink TelemetrySink } // newChainMetrics creates a new chainMetrics. func newChainMetrics( sink TelemetrySink, ) *chainMetrics { return &chainMetrics{ sink: sink, } } // measureStateTransitionDuration measures the time to process // the state transition for a block. func (cm *chainMetrics) measureStateTransitionDuration( start time.Time, ) { cm.sink.MeasureSince( "beacon_kit.beacon.blockchain.state_transition_duration", start, ) } // markRebuildPayloadForRejectedBlockSuccess increments the counter for the // number of times // the validator successfully rebuilt the payload for a rejected block. func (cm *chainMetrics) markRebuildPayloadForRejectedBlockSuccess( slot math.Slot, ) { cm.sink.IncrementCounter( "beacon_kit.blockchain.rebuild_payload_for_rejected_block_success", "slot", slot.Base10(), ) } // markRebuildPayloadForRejectedBlockFailure increments the counter for the // number of times the validator failed to build an optimistic payload // due to a failure. func (cm *chainMetrics) markRebuildPayloadForRejectedBlockFailure( slot math.Slot, err error, ) { cm.sink.IncrementCounter( "beacon_kit.blockchain.rebuild_payload_for_rejected_block_failure", "slot", slot.Base10(), "error", err.Error(), ) } // markOptimisticPayloadBuildSuccess increments the counter for the number of // times the validator successfully built an optimistic payload. func (cm *chainMetrics) markOptimisticPayloadBuildSuccess(slot math.Slot) { cm.sink.IncrementCounter( "beacon_kit.blockchain.optimistic_payload_build_success", "slot", slot.Base10(), ) } // markOptimisticPayloadBuildFailure increments the counter for the number of // times the validator failed to build an optimistic payload. func (cm *chainMetrics) markOptimisticPayloadBuildFailure( slot math.Slot, err error, ) { cm.sink.IncrementCounter( "beacon_kit.blockchain.optimistic_payload_build_failure", "slot", slot.Base10(), "error", err.Error(), ) } // TODO: remove once state caching is activated // measureStateRootVerificationTime measures the time taken to verify the state // root of a block. // It records the duration from the provided start time to the current time. func (cm *chainMetrics) measureStateRootVerificationTime(start time.Time) { cm.sink.MeasureSince( "beacon_kit.blockchain.state_root_verification_duration", start, ) } ================================================ FILE: beacon/blockchain/mocks/genesis_state_processor.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( common "github.com/berachain/beacon-kit/primitives/common" mock "github.com/stretchr/testify/mock" state "github.com/berachain/beacon-kit/state-transition/core/state" transition "github.com/berachain/beacon-kit/primitives/transition" types "github.com/berachain/beacon-kit/consensus-types/types" ) // GenesisStateProcessor is an autogenerated mock type for the GenesisStateProcessor type type GenesisStateProcessor struct { mock.Mock } type GenesisStateProcessor_Expecter struct { mock *mock.Mock } func (_m *GenesisStateProcessor) EXPECT() *GenesisStateProcessor_Expecter { return &GenesisStateProcessor_Expecter{mock: &_m.Mock} } // InitializeBeaconStateFromEth1 provides a mock function with given fields: st, deposits, execPayloadHeader, genesisVersion func (_m *GenesisStateProcessor) InitializeBeaconStateFromEth1(st *state.StateDB, deposits types.Deposits, execPayloadHeader *types.ExecutionPayloadHeader, genesisVersion common.Version) (transition.ValidatorUpdates, error) { ret := _m.Called(st, deposits, execPayloadHeader, genesisVersion) if len(ret) == 0 { panic("no return value specified for InitializeBeaconStateFromEth1") } var r0 transition.ValidatorUpdates var r1 error if rf, ok := ret.Get(0).(func(*state.StateDB, types.Deposits, *types.ExecutionPayloadHeader, common.Version) (transition.ValidatorUpdates, error)); ok { return rf(st, deposits, execPayloadHeader, genesisVersion) } if rf, ok := ret.Get(0).(func(*state.StateDB, types.Deposits, *types.ExecutionPayloadHeader, common.Version) transition.ValidatorUpdates); ok { r0 = rf(st, deposits, execPayloadHeader, genesisVersion) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(transition.ValidatorUpdates) } } if rf, ok := ret.Get(1).(func(*state.StateDB, types.Deposits, *types.ExecutionPayloadHeader, common.Version) error); ok { r1 = rf(st, deposits, execPayloadHeader, genesisVersion) } else { r1 = ret.Error(1) } return r0, r1 } // GenesisStateProcessor_InitializeBeaconStateFromEth1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InitializeBeaconStateFromEth1' type GenesisStateProcessor_InitializeBeaconStateFromEth1_Call struct { *mock.Call } // InitializeBeaconStateFromEth1 is a helper method to define mock.On call // - st *state.StateDB // - deposits types.Deposits // - execPayloadHeader *types.ExecutionPayloadHeader // - genesisVersion common.Version func (_e *GenesisStateProcessor_Expecter) InitializeBeaconStateFromEth1(st interface{}, deposits interface{}, execPayloadHeader interface{}, genesisVersion interface{}) *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call { return &GenesisStateProcessor_InitializeBeaconStateFromEth1_Call{Call: _e.mock.On("InitializeBeaconStateFromEth1", st, deposits, execPayloadHeader, genesisVersion)} } func (_c *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call) Run(run func(st *state.StateDB, deposits types.Deposits, execPayloadHeader *types.ExecutionPayloadHeader, genesisVersion common.Version)) *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(*state.StateDB), args[1].(types.Deposits), args[2].(*types.ExecutionPayloadHeader), args[3].(common.Version)) }) return _c } func (_c *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call) Return(_a0 transition.ValidatorUpdates, _a1 error) *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call) RunAndReturn(run func(*state.StateDB, types.Deposits, *types.ExecutionPayloadHeader, common.Version) (transition.ValidatorUpdates, error)) *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call { _c.Call.Return(run) return _c } // NewGenesisStateProcessor creates a new instance of GenesisStateProcessor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewGenesisStateProcessor(t interface { mock.TestingT Cleanup(func()) }) *GenesisStateProcessor { mock := &GenesisStateProcessor{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: beacon/blockchain/mocks/local_builder.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( context "context" types "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" builder "github.com/berachain/beacon-kit/payload/builder" common "github.com/berachain/beacon-kit/primitives/common" math "github.com/berachain/beacon-kit/primitives/math" mock "github.com/stretchr/testify/mock" ) // LocalBuilder is an autogenerated mock type for the LocalBuilder type type LocalBuilder struct { mock.Mock } type LocalBuilder_Expecter struct { mock *mock.Mock } func (_m *LocalBuilder) EXPECT() *LocalBuilder_Expecter { return &LocalBuilder_Expecter{mock: &_m.Mock} } // CacheLatestVerifiedPayload provides a mock function with given fields: latestEnvelopeSlot, latestEnvelope func (_m *LocalBuilder) CacheLatestVerifiedPayload(latestEnvelopeSlot math.Slot, latestEnvelope types.BuiltExecutionPayloadEnv) { _m.Called(latestEnvelopeSlot, latestEnvelope) } // LocalBuilder_CacheLatestVerifiedPayload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CacheLatestVerifiedPayload' type LocalBuilder_CacheLatestVerifiedPayload_Call struct { *mock.Call } // CacheLatestVerifiedPayload is a helper method to define mock.On call // - latestEnvelopeSlot math.Slot // - latestEnvelope types.BuiltExecutionPayloadEnv func (_e *LocalBuilder_Expecter) CacheLatestVerifiedPayload(latestEnvelopeSlot interface{}, latestEnvelope interface{}) *LocalBuilder_CacheLatestVerifiedPayload_Call { return &LocalBuilder_CacheLatestVerifiedPayload_Call{Call: _e.mock.On("CacheLatestVerifiedPayload", latestEnvelopeSlot, latestEnvelope)} } func (_c *LocalBuilder_CacheLatestVerifiedPayload_Call) Run(run func(latestEnvelopeSlot math.Slot, latestEnvelope types.BuiltExecutionPayloadEnv)) *LocalBuilder_CacheLatestVerifiedPayload_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(math.Slot), args[1].(types.BuiltExecutionPayloadEnv)) }) return _c } func (_c *LocalBuilder_CacheLatestVerifiedPayload_Call) Return() *LocalBuilder_CacheLatestVerifiedPayload_Call { _c.Call.Return() return _c } func (_c *LocalBuilder_CacheLatestVerifiedPayload_Call) RunAndReturn(run func(math.Slot, types.BuiltExecutionPayloadEnv)) *LocalBuilder_CacheLatestVerifiedPayload_Call { _c.Run(run) return _c } // Enabled provides a mock function with no fields func (_m *LocalBuilder) Enabled() bool { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for Enabled") } var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() } else { r0 = ret.Get(0).(bool) } return r0 } // LocalBuilder_Enabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Enabled' type LocalBuilder_Enabled_Call struct { *mock.Call } // Enabled is a helper method to define mock.On call func (_e *LocalBuilder_Expecter) Enabled() *LocalBuilder_Enabled_Call { return &LocalBuilder_Enabled_Call{Call: _e.mock.On("Enabled")} } func (_c *LocalBuilder_Enabled_Call) Run(run func()) *LocalBuilder_Enabled_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *LocalBuilder_Enabled_Call) Return(_a0 bool) *LocalBuilder_Enabled_Call { _c.Call.Return(_a0) return _c } func (_c *LocalBuilder_Enabled_Call) RunAndReturn(run func() bool) *LocalBuilder_Enabled_Call { _c.Call.Return(run) return _c } // RequestPayloadAsync provides a mock function with given fields: ctx, r func (_m *LocalBuilder) RequestPayloadAsync(ctx context.Context, r *builder.RequestPayloadData) (*engineprimitives.PayloadID, common.Version, error) { ret := _m.Called(ctx, r) if len(ret) == 0 { panic("no return value specified for RequestPayloadAsync") } var r0 *engineprimitives.PayloadID var r1 common.Version var r2 error if rf, ok := ret.Get(0).(func(context.Context, *builder.RequestPayloadData) (*engineprimitives.PayloadID, common.Version, error)); ok { return rf(ctx, r) } if rf, ok := ret.Get(0).(func(context.Context, *builder.RequestPayloadData) *engineprimitives.PayloadID); ok { r0 = rf(ctx, r) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*engineprimitives.PayloadID) } } if rf, ok := ret.Get(1).(func(context.Context, *builder.RequestPayloadData) common.Version); ok { r1 = rf(ctx, r) } else { if ret.Get(1) != nil { r1 = ret.Get(1).(common.Version) } } if rf, ok := ret.Get(2).(func(context.Context, *builder.RequestPayloadData) error); ok { r2 = rf(ctx, r) } else { r2 = ret.Error(2) } return r0, r1, r2 } // LocalBuilder_RequestPayloadAsync_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RequestPayloadAsync' type LocalBuilder_RequestPayloadAsync_Call struct { *mock.Call } // RequestPayloadAsync is a helper method to define mock.On call // - ctx context.Context // - r *builder.RequestPayloadData func (_e *LocalBuilder_Expecter) RequestPayloadAsync(ctx interface{}, r interface{}) *LocalBuilder_RequestPayloadAsync_Call { return &LocalBuilder_RequestPayloadAsync_Call{Call: _e.mock.On("RequestPayloadAsync", ctx, r)} } func (_c *LocalBuilder_RequestPayloadAsync_Call) Run(run func(ctx context.Context, r *builder.RequestPayloadData)) *LocalBuilder_RequestPayloadAsync_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(*builder.RequestPayloadData)) }) return _c } func (_c *LocalBuilder_RequestPayloadAsync_Call) Return(_a0 *engineprimitives.PayloadID, _a1 common.Version, _a2 error) *LocalBuilder_RequestPayloadAsync_Call { _c.Call.Return(_a0, _a1, _a2) return _c } func (_c *LocalBuilder_RequestPayloadAsync_Call) RunAndReturn(run func(context.Context, *builder.RequestPayloadData) (*engineprimitives.PayloadID, common.Version, error)) *LocalBuilder_RequestPayloadAsync_Call { _c.Call.Return(run) return _c } // NewLocalBuilder creates a new instance of LocalBuilder. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewLocalBuilder(t interface { mock.TestingT Cleanup(func()) }) *LocalBuilder { mock := &LocalBuilder{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: beacon/blockchain/mocks/storage_backend.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( block "github.com/berachain/beacon-kit/storage/block" context "context" types "github.com/berachain/beacon-kit/consensus-types/types" store "github.com/berachain/beacon-kit/da/store" state "github.com/berachain/beacon-kit/state-transition/core/state" deposit "github.com/berachain/beacon-kit/storage/deposit" mock "github.com/stretchr/testify/mock" ) // StorageBackend is an autogenerated mock type for the StorageBackend type type StorageBackend struct { mock.Mock } type StorageBackend_Expecter struct { mock *mock.Mock } func (_m *StorageBackend) EXPECT() *StorageBackend_Expecter { return &StorageBackend_Expecter{mock: &_m.Mock} } // AvailabilityStore provides a mock function with no fields func (_m *StorageBackend) AvailabilityStore() *store.Store { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for AvailabilityStore") } var r0 *store.Store if rf, ok := ret.Get(0).(func() *store.Store); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*store.Store) } } return r0 } // StorageBackend_AvailabilityStore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AvailabilityStore' type StorageBackend_AvailabilityStore_Call struct { *mock.Call } // AvailabilityStore is a helper method to define mock.On call func (_e *StorageBackend_Expecter) AvailabilityStore() *StorageBackend_AvailabilityStore_Call { return &StorageBackend_AvailabilityStore_Call{Call: _e.mock.On("AvailabilityStore")} } func (_c *StorageBackend_AvailabilityStore_Call) Run(run func()) *StorageBackend_AvailabilityStore_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *StorageBackend_AvailabilityStore_Call) Return(_a0 *store.Store) *StorageBackend_AvailabilityStore_Call { _c.Call.Return(_a0) return _c } func (_c *StorageBackend_AvailabilityStore_Call) RunAndReturn(run func() *store.Store) *StorageBackend_AvailabilityStore_Call { _c.Call.Return(run) return _c } // BlockStore provides a mock function with no fields func (_m *StorageBackend) BlockStore() *block.KVStore[*types.BeaconBlock] { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for BlockStore") } var r0 *block.KVStore[*types.BeaconBlock] if rf, ok := ret.Get(0).(func() *block.KVStore[*types.BeaconBlock]); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*block.KVStore[*types.BeaconBlock]) } } return r0 } // StorageBackend_BlockStore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BlockStore' type StorageBackend_BlockStore_Call struct { *mock.Call } // BlockStore is a helper method to define mock.On call func (_e *StorageBackend_Expecter) BlockStore() *StorageBackend_BlockStore_Call { return &StorageBackend_BlockStore_Call{Call: _e.mock.On("BlockStore")} } func (_c *StorageBackend_BlockStore_Call) Run(run func()) *StorageBackend_BlockStore_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *StorageBackend_BlockStore_Call) Return(_a0 *block.KVStore[*types.BeaconBlock]) *StorageBackend_BlockStore_Call { _c.Call.Return(_a0) return _c } func (_c *StorageBackend_BlockStore_Call) RunAndReturn(run func() *block.KVStore[*types.BeaconBlock]) *StorageBackend_BlockStore_Call { _c.Call.Return(run) return _c } // DepositStore provides a mock function with no fields func (_m *StorageBackend) DepositStore() deposit.StoreManager { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for DepositStore") } var r0 deposit.StoreManager if rf, ok := ret.Get(0).(func() deposit.StoreManager); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(deposit.StoreManager) } } return r0 } // StorageBackend_DepositStore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DepositStore' type StorageBackend_DepositStore_Call struct { *mock.Call } // DepositStore is a helper method to define mock.On call func (_e *StorageBackend_Expecter) DepositStore() *StorageBackend_DepositStore_Call { return &StorageBackend_DepositStore_Call{Call: _e.mock.On("DepositStore")} } func (_c *StorageBackend_DepositStore_Call) Run(run func()) *StorageBackend_DepositStore_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *StorageBackend_DepositStore_Call) Return(_a0 deposit.StoreManager) *StorageBackend_DepositStore_Call { _c.Call.Return(_a0) return _c } func (_c *StorageBackend_DepositStore_Call) RunAndReturn(run func() deposit.StoreManager) *StorageBackend_DepositStore_Call { _c.Call.Return(run) return _c } // StateFromContext provides a mock function with given fields: _a0 func (_m *StorageBackend) StateFromContext(_a0 context.Context) *state.StateDB { ret := _m.Called(_a0) if len(ret) == 0 { panic("no return value specified for StateFromContext") } var r0 *state.StateDB if rf, ok := ret.Get(0).(func(context.Context) *state.StateDB); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*state.StateDB) } } return r0 } // StorageBackend_StateFromContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StateFromContext' type StorageBackend_StateFromContext_Call struct { *mock.Call } // StateFromContext is a helper method to define mock.On call // - _a0 context.Context func (_e *StorageBackend_Expecter) StateFromContext(_a0 interface{}) *StorageBackend_StateFromContext_Call { return &StorageBackend_StateFromContext_Call{Call: _e.mock.On("StateFromContext", _a0)} } func (_c *StorageBackend_StateFromContext_Call) Run(run func(_a0 context.Context)) *StorageBackend_StateFromContext_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context)) }) return _c } func (_c *StorageBackend_StateFromContext_Call) Return(_a0 *state.StateDB) *StorageBackend_StateFromContext_Call { _c.Call.Return(_a0) return _c } func (_c *StorageBackend_StateFromContext_Call) RunAndReturn(run func(context.Context) *state.StateDB) *StorageBackend_StateFromContext_Call { _c.Call.Return(run) return _c } // NewStorageBackend creates a new instance of StorageBackend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewStorageBackend(t interface { mock.TestingT Cleanup(func()) }) *StorageBackend { mock := &StorageBackend{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: beacon/blockchain/payload.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "context" "fmt" payloadtime "github.com/berachain/beacon-kit/beacon/payload-time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" engineerrors "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" statedb "github.com/berachain/beacon-kit/state-transition/core/state" ) // forceSyncUponProcess sends a force head FCU to the execution client. func (s *Service) forceSyncUponProcess( ctx context.Context, st *statedb.StateDB, ) { lph, err := st.GetLatestExecutionPayloadHeader() if err != nil { s.logger.Error( "failed to get latest execution payload header", "error", err, ) return } s.logger.Info( "Sending startup forkchoice update to execution client", "head_eth1_hash", lph.GetBlockHash(), "safe_eth1_hash", lph.GetParentHash(), "finalized_eth1_hash", lph.GetParentHash(), "for_slot", lph.GetNumber(), ) // Submit the forkchoice update to the execution client. req := ctypes.BuildForkchoiceUpdateRequestNoAttrs( &engineprimitives.ForkchoiceStateV1{ HeadBlockHash: lph.GetBlockHash(), SafeBlockHash: lph.GetParentHash(), FinalizedBlockHash: lph.GetParentHash(), }, s.chainSpec.ActiveForkVersionForTimestamp(lph.GetTimestamp()), ) if _, err = s.executionEngine.NotifyForkchoiceUpdate(ctx, req); err != nil { s.logger.Error( "failed to send force head FCU", "error", err, ) } } // forceSyncUponFinalize sends a new payload and force startup FCU to the Execution // Layer client. This informs the EL client of the new head and forces a SYNC // if blocks are missing. This function should only be run once at startup. func (s *Service) forceSyncUponFinalize( ctx context.Context, beaconBlock *ctypes.BeaconBlock, parentProposerPubkey *crypto.BLSPubkey, ) error { // NewPayload call first to load payload into EL client. executionPayload := beaconBlock.GetBody().GetExecutionPayload() payloadReq, err := ctypes.BuildNewPayloadRequestFromFork(beaconBlock, parentProposerPubkey) if err != nil { return err } if err = payloadReq.HasValidVersionedAndBlockHashes(); err != nil { return err } // We set retryOnSyncingStatus to false here. We can ignore SYNCING status and proceed // to the FCU. err = s.executionEngine.NotifyNewPayload(ctx, payloadReq, false) if err != nil { return fmt.Errorf("startSyncUponFinalize NotifyNewPayload failed: %w", err) } // Submit the forkchoice update to the EL client. This will ensure that it is either synced or // starts up a sync. req := ctypes.BuildForkchoiceUpdateRequestNoAttrs( &engineprimitives.ForkchoiceStateV1{ HeadBlockHash: executionPayload.GetBlockHash(), SafeBlockHash: executionPayload.GetParentHash(), FinalizedBlockHash: executionPayload.GetParentHash(), }, s.chainSpec.ActiveForkVersionForTimestamp(executionPayload.GetTimestamp()), ) switch _, err = s.executionEngine.NotifyForkchoiceUpdate(ctx, req); { case err == nil: return nil case errors.IsAny(err, engineerrors.ErrSyncingPayloadStatus, engineerrors.ErrAcceptedPayloadStatus): s.logger.Warn( //nolint:lll // long message on one line for readability. `Your execution client is syncing. It should be downloading eth blocks from its peers. Restart the beacon node once the execution client is caught up.`, ) return err default: return fmt.Errorf("force startup NotifyForkchoiceUpdate failed: %w", err) } } // Once you provide the right state, we really need to carry out the very same operations // to extract the data necessary to build the next block, whether current block is // being rejected or accepted. This is way there can be (and so should be) // a single function doing these ops. preFetchBuildData is that function. func (s *Service) preFetchBuildData(st *statedb.StateDB, currentTime math.U64) ( *builder.RequestPayloadData, error, ) { lph, err := st.GetLatestExecutionPayloadHeader() if err != nil { return nil, fmt.Errorf("failed retrieving latest execution payload header: %w", err) } nextPayloadTimestamp := payloadtime.Next( currentTime, lph.GetTimestamp(), true, // buildOptimistically ) stateSlot, err := st.GetSlot() if err != nil { return nil, fmt.Errorf("failed retrieving slot from state: %w", err) } blkSlot := stateSlot + 1 // Carry out on the support state st all the operations needed to // process a new payload, namely ProcessSlots and ProcessFork if _, err = s.stateProcessor.ProcessSlots(st, blkSlot); err != nil { return nil, fmt.Errorf("failed processing block slot: %w", err) } if err = s.stateProcessor.ProcessFork(st, nextPayloadTimestamp, false); err != nil { return nil, fmt.Errorf("failed processing fork: %w", err) } // Once the state is ready, extract relevant data to build next payload payloadWithdrawals, _, err := st.ExpectedWithdrawals(nextPayloadTimestamp) if err != nil { return nil, fmt.Errorf("failed computing expected withdrawals: %w", err) } epoch := s.chainSpec.SlotToEpoch(blkSlot) prevRandao, err := st.GetRandaoMixAtIndex( epoch.Unwrap() % s.chainSpec.EpochsPerHistoricalVector(), ) if err != nil { return nil, fmt.Errorf("failed retrieving randao: %w", err) } latestHeader, err := st.GetLatestBlockHeader() if err != nil { return nil, err } parentProposerPubkey, err := st.ParentProposerPubkey(nextPayloadTimestamp) if err != nil { return nil, fmt.Errorf("failed retrieving previous proposer public key: %w", err) } return &builder.RequestPayloadData{ Slot: blkSlot, Timestamp: nextPayloadTimestamp, PayloadWithdrawals: payloadWithdrawals, PrevRandao: prevRandao, ParentBlockRoot: latestHeader.HashTreeRoot(), FCState: engineprimitives.ForkchoiceStateV1{ // We set the head of our chain to the latest verified block (whether it is final or not) HeadBlockHash: lph.GetBlockHash(), SafeBlockHash: lph.GetParentHash(), // Assuming consensus guarantees single slot finality, the parent // of the latest block we verified must be final already. FinalizedBlockHash: lph.GetParentHash(), }, ParentProposerPubkey: parentProposerPubkey, }, nil } // handleRebuildPayloadForRejectedBlock handles the case where the incoming // block was rejected and we need to rebuild the payload for the current slot. func (s *Service) handleRebuildPayloadForRejectedBlock( ctx context.Context, buildData *builder.RequestPayloadData, ) { s.logger.Info("Rebuilding payload for rejected block ⏳ ") nextBlkSlot := buildData.Slot if _, _, err := s.localBuilder.RequestPayloadAsync(ctx, buildData); err != nil { s.metrics.markRebuildPayloadForRejectedBlockFailure(nextBlkSlot, err) s.logger.Error( "failed to rebuild payload for nil block", "error", err, ) return } s.latestFcuReq.Store(&buildData.FCState) s.metrics.markRebuildPayloadForRejectedBlockSuccess(nextBlkSlot) } // handleOptimisticPayloadBuild handles optimistically // building for the next slot. func (s *Service) handleOptimisticPayloadBuild( ctx context.Context, buildData *builder.RequestPayloadData, ) { s.logger.Info( "Optimistically triggering payload build for next slot 🛩️ ", "next_slot", buildData.Slot.Base10(), ) if _, _, err := s.localBuilder.RequestPayloadAsync(ctx, buildData); err != nil { s.metrics.markOptimisticPayloadBuildFailure(buildData.Slot, err) s.logger.Error( "Failed to build optimistic payload", "for_slot", buildData.Slot.Base10(), "error", err, ) return } s.latestFcuReq.Store(&buildData.FCState) s.metrics.markOptimisticPayloadBuildSuccess(buildData.Slot) } ================================================ FILE: beacon/blockchain/payload_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain_test import ( "context" "encoding/json" "sync" "testing" "time" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" "github.com/berachain/beacon-kit/beacon/blockchain" bcmocks "github.com/berachain/beacon-kit/beacon/blockchain/mocks" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/errors" gethtypes "github.com/berachain/beacon-kit/gethlib/types" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/state-transition/core" stmocks "github.com/berachain/beacon-kit/state-transition/core/mocks" "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage/deposit" statetransition "github.com/berachain/beacon-kit/testing/state-transition" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) // When we reject a block and we have optimistic payload building enabled // we must make sure that a few beacon state quantities are duly pre-processed // before building the block. func TestOptimisticBlockBuildingRejectedBlockStateChecks(t *testing.T) { t.Parallel() cs, err := spec.MainnetChainSpec() require.NoError(t, err) chain, st, _, ctx, _, b, sb, eng, depStore := setupOptimisticPayloadTests(t, cs) sb.EXPECT().StateFromContext(mock.Anything).Return(st) sb.EXPECT().DepositStore().RunAndReturn(func() deposit.StoreManager { return depStore }) b.EXPECT().Enabled().Return(true) // Note: test avoid calling chain.Start since it only starts the deposits // goroutine which is not really relevant for this test // Before processing any block it is mandatory to handle genesis genesisData := testProcessGenesis(t, cs, chain, ctx) // Finally create a block that will be rejected and // verify the state on top of which is next payload built var ( consensusTime = time.Now() proposerAddress = []byte{'d', 'u', 'm', 'm', 'y'} // this will err on purpose ) // Since this is the first block called post genesis // forceSyncUponProcess will be called. dummyPayloadID := &engineprimitives.PayloadID{1, 2, 3} eng.EXPECT().NotifyForkchoiceUpdate(mock.Anything, mock.Anything).Return(dummyPayloadID, nil) // we set just enough data in invalid block to let it pass // the first validations in chain before state processor is invoked invalidBlk := &ctypes.BeaconBlock{ Slot: 1, // first block after genesis Body: &ctypes.BeaconBlockBody{ ExecutionPayload: &ctypes.ExecutionPayload{ Timestamp: math.U64(cs.GenesisTime() + 1), }, }, } // register async call to block building var wg sync.WaitGroup // useful to make test wait on async checks stateRoot := st.HashTreeRoot() // track state root before the changes done by optimistic build latestHeader, err := st.GetLatestBlockHeader() require.NoError(t, err) latestHeader.SetStateRoot(stateRoot) expectedParentBlockRoot := latestHeader.HashTreeRoot() b.EXPECT().RequestPayloadAsync(mock.Anything, mock.Anything).Run( func(_ context.Context, r *builder.RequestPayloadData) { defer wg.Done() genesisHeader := genesisData.ExecutionPayloadHeader genesisBlkHeader := core.GenesisBlockHeader(cs.GenesisForkVersion()) genesisBlkHeader.SetStateRoot(stateRoot) require.Equal(t, math.U64(consensusTime.Unix())+1, r.Timestamp) require.Equal(t, genesisHeader.GetBlockHash(), r.FCState.HeadBlockHash) require.Equal(t, expectedParentBlockRoot, r.ParentBlockRoot) require.Empty(t, r.FCState.FinalizedBlockHash) // this is first block post genesis require.Equal(t, constants.GenesisSlot+1, r.Slot) // rebuild block on top of genesis }, ).Return(nil, common.Version{0xff}, errors.New("does not matter")) // return values do not really matter in this test wg.Add(1) // check slot pre test slot, err := st.GetSlot() require.NoError(t, err) require.Equal(t, constants.GenesisSlot, slot) _, err = chain.VerifyIncomingBlock( ctx.ConsensusCtx(), types.NewConsensusBlock(invalidBlk, proposerAddress, consensusTime), true, // this block is next block proposer ) require.ErrorIs(t, err, core.ErrProposerMismatch) // wait for block building goroutine to carry out all the checks wg.Wait() // No checks on state st post block. The block is invalid so // its state will be dropped and its content does not matter } // When we verify successfully a block and we have optimistic payload building enabled // we must make sure that a few beacon state quantities are duly pre-processed // before building the block. func TestOptimisticBlockBuildingVerifiedBlockStateChecks(t *testing.T) { t.Parallel() cs, err := spec.MainnetChainSpec() require.NoError(t, err) chain, st, cms, ctx, sp, b, sb, eng, depStore := setupOptimisticPayloadTests(t, cs) sb.EXPECT().StateFromContext(mock.Anything).Return(st).Times(1) // only for genesis sb.EXPECT().DepositStore().RunAndReturn(func() deposit.StoreManager { return depStore }) b.EXPECT().Enabled().Return(true) // Before processing any block it is mandatory to handle genesis genesisData := testProcessGenesis(t, cs, chain, ctx) // write genesis changes to make them available for next block //nolint:errcheck // false positive as this has no return value ctx.ConsensusCtx().(sdk.Context).MultiStore().(storetypes.CacheMultiStore).Write() // Finally create a block that will be rejected and // verify the state on top of which is next payload built var ( consensusTime = time.Now() proposer = ctx.ProposerAddress() ) // Since this is the first block called post genesis // forceSyncUponProcess will be called. dummyPayloadID := &engineprimitives.PayloadID{1, 2, 3} eng.EXPECT().NotifyForkchoiceUpdate(mock.Anything, mock.Anything).Return(dummyPayloadID, nil) // BUILD A VALID BLOCK (without polluting state st) sdkCtx := sdk.NewContext(cms.CacheMultiStore(), true, log.NewNopLogger()) buildState := state.NewBeaconStateFromDB( st.KVStore.WithContext(sdkCtx), cs, sdkCtx.Logger(), metrics.NewNoOpTelemetrySink(), ) nextBlkTimestamp := math.U64(cs.GenesisTime() + 1) _, err = sp.ProcessSlots(buildState, constants.GenesisSlot+1) require.NoError(t, err) depositsRoot := ctypes.Deposits(genesisData.Deposits).HashTreeRoot() validBlk := buildNextBlock( t, cs, buildState, ctypes.NewEth1Data(depositsRoot), nextBlkTimestamp, ) stateRoot, err := computeStateRoot( // fix state root in block ctx.ConsensusCtx(), proposer, math.U64(consensusTime.Unix()), sp, buildState, validBlk, ) require.NoError(t, err) validBlk.SetStateRoot(stateRoot) // end of BUILD A VALID BLOCK // register async call to block building var wg sync.WaitGroup // useful to make test wait on async checks b.EXPECT().RequestPayloadAsync(mock.Anything, mock.Anything).Run( func(_ context.Context, r *builder.RequestPayloadData) { defer wg.Done() require.Equal(t, math.U64(consensusTime.Unix())+1, r.Timestamp) require.Equal( t, validBlk.GetBody().GetExecutionPayload().GetBlockHash(), r.FCState.HeadBlockHash, ) genesisHeader := genesisData.ExecutionPayloadHeader.GetBlockHash() require.Equal(t, genesisHeader, r.FCState.FinalizedBlockHash) require.Equal(t, validBlk.HashTreeRoot(), r.ParentBlockRoot) require.Equal(t, validBlk.Slot+1, r.Slot) }, ).Return(nil, common.Version{0xff}, errors.New("does not matter")) // return values do not really matter in this test wg.Add(1) // check slot pre test slot, err := st.GetSlot() require.NoError(t, err) require.Equal(t, constants.GenesisSlot, slot) eng.EXPECT().NotifyNewPayload(mock.Anything, mock.Anything, mock.Anything).Return(nil) sb.EXPECT().StateFromContext(mock.Anything).Return(st).Times(1) _, err = chain.VerifyIncomingBlock( ctx.ConsensusCtx(), types.NewConsensusBlock(validBlk, ctx.ProposerAddress(), consensusTime), true, // this block is next block proposer ) require.NoError(t, err) // wait for block building goroutine to carry out all the checks wg.Wait() // check slot post test slot, err = st.GetSlot() require.NoError(t, err) require.Equal(t, validBlk.GetSlot(), slot) } func setupOptimisticPayloadTests(t *testing.T, cs chain.Spec) ( *blockchain.Service, *statetransition.TestBeaconStateT, storetypes.CommitMultiStore, core.ReadOnlyContext, *statetransition.TestStateProcessorT, *bcmocks.LocalBuilder, *bcmocks.StorageBackend, *stmocks.ExecutionEngine, deposit.StoreManager, ) { t.Helper() sp, st, depStore, ctx, cms, eng := statetransition.SetupTestState(t, cs) logger := log.NewNopLogger() ts := metrics.NewNoOpTelemetrySink() sb := bcmocks.NewStorageBackend(t) b := bcmocks.NewLocalBuilder(t) chain := blockchain.NewService( sb, nil, // blockchain.BlobProcessor unused in this test nil, // deposit.Contract unused in this test logger, cs, eng, b, sp, ts, ) return chain, st, cms, ctx, sp, b, sb, eng, depStore } func testProcessGenesis( t *testing.T, cs chain.Spec, chain *blockchain.Service, ctx core.ReadOnlyContext, ) *ctypes.Genesis { t.Helper() // TODO: I had to manually align default genesis and cs specs // Check if this is correct/necessary genesisData := ctypes.DefaultGenesis(cs.GenesisForkVersion()) genesisData.ExecutionPayloadHeader.Timestamp = math.U64(cs.GenesisTime()) genesisData.Deposits = []*ctypes.Deposit{ { Pubkey: [48]byte{0x01}, Amount: cs.MaxEffectiveBalance(), Credentials: ctypes.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), Index: uint64(0), }, } genBytes, err := json.Marshal(genesisData) require.NoError(t, err) _, err = chain.ProcessGenesisData(ctx.ConsensusCtx(), genBytes) require.NoError(t, err) return genesisData } func buildNextBlock( t *testing.T, cs chain.Spec, st *state.StateDB, eth1Data *ctypes.Eth1Data, timestamp math.U64, ) *ctypes.BeaconBlock { t.Helper() require.NotNil(t, cs) parentBlkHeader, err := st.GetLatestBlockHeader() require.NoError(t, err) nextBlockSlot := parentBlkHeader.GetSlot() + 1 nextBlockEpoch := cs.SlotToEpoch(nextBlockSlot) randaoMix, err := st.GetRandaoMixAtIndex(nextBlockEpoch.Unwrap() % cs.EpochsPerHistoricalVector()) require.NoError(t, err) // build the block fv := cs.ActiveForkVersionForTimestamp(timestamp) versionable := ctypes.NewVersionable(fv) blk, err := ctypes.NewBeaconBlockWithVersion( nextBlockSlot, parentBlkHeader.GetProposerIndex(), parentBlkHeader.HashTreeRoot(), fv, ) require.NoError(t, err) // build the payload lph, err := st.GetLatestExecutionPayloadHeader() require.NoError(t, err) // Check chain canonicity payload := &ctypes.ExecutionPayload{ Versionable: versionable, Timestamp: timestamp, ParentHash: lph.GetBlockHash(), Random: randaoMix, ExtraData: []byte("testing"), Transactions: [][]byte{}, Withdrawals: []*engineprimitives.Withdrawal{st.EVMInflationWithdrawal(timestamp)}, BaseFeePerGas: math.NewU256(0), } parentBeaconBlockRoot := parentBlkHeader.HashTreeRoot() var ( ethBlk *gethtypes.Block noExecReq = &ctypes.ExecutionRequests{} ) if version.IsBefore(fv, version.Electra()) { ethBlk, _, err = ctypes.MakeEthBlock(payload, parentBeaconBlockRoot, nil, nil) require.NoError(t, err) } else { encodedER, erErr := ctypes.GetExecutionRequestsList(noExecReq) require.NoError(t, erErr) require.NotNil(t, encodedER) ethBlk, _, err = ctypes.MakeEthBlock(payload, parentBeaconBlockRoot, encodedER, nil) require.NoError(t, err) } payload.BlockHash = common.ExecutionHash(ethBlk.Hash()) require.NoError(t, err) blk.Body = &ctypes.BeaconBlockBody{ Versionable: versionable, ExecutionPayload: payload, Eth1Data: eth1Data, } if version.EqualsOrIsAfter(fv, version.Electra()) { err = blk.Body.SetExecutionRequests(noExecReq) require.NoError(t, err) } return blk } func computeStateRoot( ctx context.Context, proposerAddress []byte, consensusTime math.U64, sp *statetransition.TestStateProcessorT, st *state.StateDB, blk *ctypes.BeaconBlock, ) (common.Root, error) { txCtx := transition.NewTransitionCtx( ctx, consensusTime, proposerAddress, ). WithVerifyPayload(false). WithVerifyRandao(false). WithVerifyResult(false). WithMeterGas(false) //nolint:contextcheck // we need txCtx if _, err := sp.Transition(txCtx, st, blk); err != nil { return common.Root{}, err } return st.HashTreeRoot(), nil } ================================================ FILE: beacon/blockchain/process_proposal.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "bytes" "cmp" "context" "fmt" "slices" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/cache" "github.com/berachain/beacon-kit/consensus/types" datypes "github.com/berachain/beacon-kit/da/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/state-transition/core" statedb "github.com/berachain/beacon-kit/state-transition/core/state" cmtabci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" ) const ( // BeaconBlockTxIndex represents the index of the beacon block transaction. // It is the first transaction in the tx list. BeaconBlockTxIndex uint = iota // BlobSidecarsTxIndex represents the index of the blob sidecar transaction. // It follows the beacon block transaction in the tx list. BlobSidecarsTxIndex // A Consensus block has at most two transactions (block and blob). MaxConsensusTxsCount = 2 ) //nolint:funlen // abundantly commented func (s *Service) ProcessProposal( ctx sdk.Context, req *cmtabci.ProcessProposalRequest, thisNodeAddress []byte, ) (transition.ValidatorUpdates, error) { signedBlk, sidecars, err := s.ParseBeaconBlock(req) if err != nil { s.logger.Error("Failed to decode block and blobs", "error", err) return nil, fmt.Errorf("failed to decode block and blobs: %w", err) } blk := signedBlk.GetBeaconBlock() // Sort the sidecars by index for verification and processing. slices.SortFunc(sidecars, func(a, b *datypes.BlobSidecar) int { return cmp.Compare(a.GetIndex(), b.GetIndex()) }) // There are two different timestamps: // - The "consensus time" is determined by CometBFT consensus and can be retrieved with `req.GetTime()` // - The "block time" is determined by beacon-kit consensus and can be retrieved with `blk.GetTimestamp()` // The "consensus time" is what the network agrees the current time is based on CometBFT PBTS. // This "consensus time" is used to constrain the timestamp set as the "block time" by the // beacon-kit app, but they are not always equal in value. The "block time" is used by the // beacon-kit consensus and execution layers to determine the active fork version. // // When unmarshaling the BeaconBlock, we do not yet have access to the "block time", so we // must rely on the "consensus time" as our best estimation of the "block time" needed to // determine the current fork version. Since the two timestamps could be different, we need to // ensure that the fork version for these timestamps are the same. This may result in a failed // proposal or two at the start of the fork. forkVersion := s.chainSpec.ActiveForkVersionForTimestamp(math.U64(req.GetTime().Unix())) //#nosec: G115 blkVersion := s.chainSpec.ActiveForkVersionForTimestamp(blk.GetTimestamp()) if !version.Equals(blkVersion, forkVersion) { return nil, fmt.Errorf("CometBFT version %v, BeaconBlock version %v: %w", forkVersion, blkVersion, ErrVersionMismatch, ) } // Make sure we have the right number of BlobSidecars blobKzgCommitments := blk.GetBody().GetBlobKzgCommitments() numCommitments := len(blobKzgCommitments) if numCommitments != len(sidecars) { return nil, fmt.Errorf("expected %d sidecars, got %d: %w", numCommitments, len(sidecars), ErrSidecarCommitmentMismatch, ) } if uint64(numCommitments) > s.chainSpec.MaxBlobsPerBlock() { return nil, fmt.Errorf("expected less than %d sidecars, got %d: %w", s.chainSpec.MaxBlobsPerBlock(), numCommitments, core.ErrExceedsBlockBlobLimit, ) } // Verify the block and sidecar signatures. We can simply verify the block // signature and then make sure the sidecar signatures match the block. blkSignature := signedBlk.GetSignature() for i, sidecar := range sidecars { sidecarSignature := sidecar.GetSignature() if !bytes.Equal(blkSignature[:], sidecarSignature[:]) { return nil, fmt.Errorf("%w, idx: %d", ErrSidecarSignatureMismatch, i) } } err = s.VerifyIncomingBlockSignature(ctx, blk, signedBlk.GetSignature()) if err != nil { return nil, err } if numCommitments > 0 { // Process the blob sidecars // // In theory, swapping the order of verification between the sidecars // and the incoming block should not introduce any inconsistencies // in the state on which the sidecar verification depends on (notably // the currently active fork). ProcessProposal should only // keep the state changes as candidates (which is what we do in // VerifyIncomingBlock). err = s.VerifyIncomingBlobSidecars(ctx, sidecars, blk.GetHeader(), blobKzgCommitments) if err != nil { s.logger.Error("failed to verify incoming blob sidecars", "error", err) return nil, err } } // Process the block. s.logger.Debug( // needed for some checks in sim tests "Processing block with fork version", "block", req.Height, "fork", blkVersion.String(), ) consensusBlk := types.NewConsensusBlock( blk, req.GetProposerAddress(), req.GetTime(), ) var valUpdates transition.ValidatorUpdates valUpdates, err = s.VerifyIncomingBlock( ctx, consensusBlk, bytes.Equal(thisNodeAddress, req.NextProposerAddress), ) if err != nil { s.logger.Error("failed to verify incoming block", "error", err) return nil, err } // once we have successfully verified the block we cache it in the node builder. // This ensures the node will be able to build a payload even in scenarios where // EVM won't provide a new payload (e.g. if it received FCU(Head == N+1) due to // optimistic block building, then FCU(Head == N)) if verified block is not finalized) envelope, err := payloadEnvFromPayload(sidecars, blk) if err != nil { return nil, err } s.localBuilder.CacheLatestVerifiedPayload(blk.Slot, envelope) return valUpdates.CanonicalSort(), nil } func payloadEnvFromPayload(sidecars datypes.BlobSidecars, blk *ctypes.BeaconBlock) (ctypes.BuiltExecutionPayloadEnv, error) { blobBundle := &engineprimitives.BlobsBundleV1{} for _, s := range sidecars { blobBundle.Commitments = append(blobBundle.Commitments, s.GetKzgCommitment()) blobBundle.Proofs = append(blobBundle.Proofs, s.GetKzgProof()) blob := s.GetBlob() blobBundle.Blobs = append(blobBundle.Blobs, &blob) } var ( executionRequests []ctypes.EncodedExecutionRequest err error ) switch reqs, errReqs := blk.Body.GetExecutionRequests(); { case errReqs == nil: executionRequests, err = ctypes.GetExecutionRequestsList(reqs) if err != nil { return nil, fmt.Errorf("failed retrieving encoded execution requests from payload: %w", err) } case errors.Is(errReqs, ctypes.ErrFieldNotSupportedOnFork): // nothing to do, executionRequests is nil default: return nil, fmt.Errorf("failed getting execution requests from payload: %w", errReqs) } return ctypes.NewExecutionPayloadEnvelope[*engineprimitives.BlobsBundleV1]( blk.Body.ExecutionPayload, blobBundle, executionRequests, ), nil } func (s *Service) VerifyIncomingBlockSignature( ctx context.Context, beaconBlk *ctypes.BeaconBlock, signature crypto.BLSSignature, ) error { // Get the sidecar verification function from the state processor signatureVerifierFn, err := s.stateProcessor.GetSignatureVerifierFn( s.storageBackend.StateFromContext(ctx), ) if err != nil { return errors.New("failed to create block signature verifier") } err = signatureVerifierFn(beaconBlk, signature) if err != nil { return fmt.Errorf("failed verifying incoming block signature: %w", err) } return err } // VerifyIncomingBlobSidecars verifies the BlobSidecars of an incoming // proposal and logs the process. func (s *Service) VerifyIncomingBlobSidecars( ctx context.Context, sidecars datypes.BlobSidecars, blkHeader *ctypes.BeaconBlockHeader, kzgCommitments eip4844.KZGCommitments[common.ExecutionHash], ) error { // Verify the blobs and ensure they match the local state. err := s.blobProcessor.VerifySidecars(ctx, sidecars, blkHeader, kzgCommitments) if err != nil { s.logger.Error( "Blob sidecars verification failed - rejecting incoming blob sidecars", "reason", err, "slot", blkHeader.GetSlot(), ) return err } s.logger.Info( "Blob sidecars verification succeeded - accepting incoming blob sidecars", "num_blobs", len(sidecars), "slot", blkHeader.GetSlot(), ) return nil } // VerifyIncomingBlock verifies the state root of an incoming block // and logs the process. // //nolint:funlen // abundantly commented func (s *Service) VerifyIncomingBlock( ctx context.Context, blk *types.ConsensusBlock, isNextBlockProposer bool, ) (transition.ValidatorUpdates, error) { beaconBlk := blk.GetBeaconBlock() state := s.storageBackend.StateFromContext(ctx) // Force a sync of the startup head if we haven't done so already. // TODO: Address the need for calling forceStartupSyncOnce in ProcessProposal. On a running // network (such as mainnet), it should be theoretically impossible to hit the case where // ProcessProposal is called before FinalizeBlock. It may be the case that new networks run // into this case during the first block after genesis. // TODO: Consider panicing here if this fails. If our node cannot successfully run // forceStartupSync, then we should shut down the node and fix the problem. s.forceStartupSyncOnce.Do(func() { s.forceSyncUponProcess(ctx, state) }) s.logger.Debug( "Received incoming beacon block", "state_root", beaconBlk.GetStateRoot(), "slot", beaconBlk.GetSlot(), ) // verify block slot stateSlot, err := state.GetSlot() if err != nil { s.logger.Error( "failed loading state slot to verify block slot", "reason", err, ) return nil, err } blkSlot := beaconBlk.GetSlot() if blkSlot != stateSlot+1 { s.logger.Error( "Rejecting incoming beacon block ❌ ", "state slot", stateSlot.Base10(), "block slot", blkSlot.Base10(), "reason", ErrUnexpectedBlockSlot.Error(), ) return nil, ErrUnexpectedBlockSlot } var ( nextBlockData *builder.RequestPayloadData errFetch error shouldBuildNextPayload = s.shouldBuildNextPayload(isNextBlockProposer) ) if shouldBuildNextPayload { // makes sure that preFetchBuildData does not affect state ephemeralState := state.Protect(ctx) nextBlockData, errFetch = s.preFetchBuildData(ephemeralState, blk.GetConsensusTime()) if errFetch != nil { // We don't return with err if pre-fetch fails. Instead we log the issue // and still move to process the current block. Next block can always be // built right after current height is finalized. s.logger.Warn( "Failed pre fetching data for optimistic block building", "case", "block rejectiong", "err", errFetch, ) } } // Verify the state root of the incoming block. valUpdates, err := s.verifyStateRoot(ctx, state, blk) if err != nil { s.logger.Error( "Rejecting incoming beacon block ❌ ", "state_root", beaconBlk.GetStateRoot(), "reason", err, ) if shouldBuildNextPayload { if nextBlockData == nil { // Failed fetching data to build next block. Just return block error return nil, err } go s.handleRebuildPayloadForRejectedBlock(ctx, nextBlockData) } return nil, err } s.logger.Debug( "State root verification succeeded - accepting incoming beacon block", "state_root", beaconBlk.GetStateRoot(), ) if shouldBuildNextPayload { // makes sure that preFetchBuildDataForSuccess does not affect state ephemeralState := state.Protect(ctx) nextBlockData, errFetch = s.preFetchBuildData(ephemeralState, blk.GetConsensusTime()) if errFetch != nil { // We don't mark the block as rejected if it is valid but pre-fetch fails. // Instead we log the issue and move to process the current block. // Next block can always be built right after current height is finalized. s.logger.Warn( "Failed pre fetching data for optimistic block building", "case", "block success", "err", errFetch, ) return valUpdates, nil } go s.handleOptimisticPayloadBuild(ctx, nextBlockData) } return valUpdates, nil } // verifyStateRoot verifies the state root of an incoming block. func (s *Service) verifyStateRoot( ctx context.Context, st *statedb.StateDB, blk *types.ConsensusBlock, ) (transition.ValidatorUpdates, error) { startTime := time.Now() isCacheActive := cache.IsStateCachingActive(s.chainSpec, blk.GetBeaconBlock().GetSlot()) if isCacheActive { // Re-use finalize block metrics if caching is active defer s.metrics.measureStateTransitionDuration(startTime) } else { // Keep ProcessProposal specific metrics before fork is active defer s.metrics.measureStateRootVerificationTime(startTime) } txCtx := transition.NewTransitionCtx( ctx, blk.GetConsensusTime(), blk.GetProposerAddress(), ). WithVerifyPayload(true). WithVerifyRandao(true). WithVerifyResult(true). WithMeterGas(isCacheActive) valUpdates, err := s.stateProcessor.Transition(txCtx, st, blk.GetBeaconBlock()) return valUpdates, err } // shouldBuildNextPayload returns true if optimistic // payload builds are enabled. func (s *Service) shouldBuildNextPayload(isNextBlockProposer bool) bool { return isNextBlockProposer && s.localBuilder.Enabled() } ================================================ FILE: beacon/blockchain/pruning.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "context" ctypes "github.com/berachain/beacon-kit/consensus-types/types" ) func (s *Service) processPruning(ctx context.Context, beaconBlk *ctypes.BeaconBlock) error { // prune availability store start, end := availabilityPruneRangeFn(beaconBlk.GetSlot().Unwrap(), s.chainSpec) err := s.storageBackend.AvailabilityStore().Prune(start, end) if err != nil { return err } // prune deposit store start, end = depositPruneRangeFn(beaconBlk.GetBody().GetDeposits(), s.chainSpec) err = s.storageBackend.DepositStore().Prune(ctx, start, end) if err != nil { return err } return nil } func depositPruneRangeFn([]*ctypes.Deposit, PruningChainSpec) (uint64, uint64) { // The whole deposit list is validated in consensus and its Merkle root is part of // Beacon State. Therefore, every node must keep the full deposit list and deposits // pruning must be turned off. return 0, 0 } //nolint:unparam // this is ok func availabilityPruneRangeFn(slot uint64, cs PruningChainSpec) (uint64, uint64) { window := cs.MinEpochsForBlobsSidecarsRequest().Unwrap() * cs.SlotsPerEpoch() if slot < window { return 0, 0 } return 0, slot - window } ================================================ FILE: beacon/blockchain/service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blockchain import ( "context" "fmt" "sync" "sync/atomic" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/execution/deposit" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/math" ) // Service is the blockchain service. type Service struct { // storageBackend represents the backend storage for not state-enforced data. storageBackend StorageBackend // blobProcessor is used for processing sidecars. blobProcessor BlobProcessor // depositContract is the contract interface for interacting with the // deposit contract. depositContract deposit.Contract // eth1FollowDistance is the follow distance for Ethereum 1.0 blocks. eth1FollowDistance math.U64 // failedBlocksMu protects failedBlocks for concurrent access. failedBlocksMu sync.RWMutex // failedBlocks is a map of blocks that failed to be processed // and should be retried. failedBlocks map[math.U64]struct{} // logger is used for logging messages in the service. logger log.Logger // chainSpec holds the chain specifications. chainSpec ServiceChainSpec // executionEngine is the execution engine responsible for processing // // execution payloads. executionEngine ExecutionEngine // localBuilder is a local builder for constructing new beacon states. localBuilder LocalBuilder // stateProcessor is the state processor for beacon blocks and states. stateProcessor StateProcessor // metrics is the metrics for the service. metrics *chainMetrics // forceStartupSyncOnce is used to force a sync of the startup head. forceStartupSyncOnce *sync.Once // latestFcuReq holds a copy of the latest FCU sent to the execution layer. // It helps avoid resending the same FCU data (and spares a network call) // in case optimistic block building is active latestFcuReq atomic.Pointer[engineprimitives.ForkchoiceStateV1] } // NewService creates a new validator service. func NewService( storageBackend StorageBackend, blobProcessor BlobProcessor, depositContract deposit.Contract, logger log.Logger, chainSpec ServiceChainSpec, executionEngine ExecutionEngine, localBuilder LocalBuilder, stateProcessor StateProcessor, telemetrySink TelemetrySink, ) *Service { return &Service{ storageBackend: storageBackend, blobProcessor: blobProcessor, depositContract: depositContract, eth1FollowDistance: math.U64(chainSpec.Eth1FollowDistance()), failedBlocks: make(map[math.Slot]struct{}), logger: logger, chainSpec: chainSpec, executionEngine: executionEngine, localBuilder: localBuilder, stateProcessor: stateProcessor, metrics: newChainMetrics(telemetrySink), forceStartupSyncOnce: new(sync.Once), } } // Name returns the name of the service. func (s *Service) Name() string { return "blockchain" } // Start starts the blockchain service. func (s *Service) Start(ctx context.Context) error { // Catchup deposits for failed blocks. TODO: remove. go s.depositCatchupFetcher(ctx) return nil } // Stop stops the blockchain service and closes the deposit store. func (s *Service) Stop() error { s.logger.Info("Stopping blockchain service") err := s.storageBackend.DepositStore().Close() if err != nil { s.logger.Error("failed to close deposit store", "err", err) } return nil } // StorageBackend returns the storage backend. func (s *Service) StorageBackend() StorageBackend { return s.storageBackend } // PruneOrphanedBlobs removes any orphaned blob sidecars that may exist from incomplete block finalization. func (s *Service) PruneOrphanedBlobs(lastBlockHeight int64) error { orphanedSlot := math.Slot(lastBlockHeight + 1) // #nosec G115 // Check if any blob sidecars exist at the potentially orphaned slot sidecars, err := s.storageBackend.AvailabilityStore().GetBlobSidecars(orphanedSlot) if err != nil { return fmt.Errorf("failed to read blob sidecars at slot %d: %w", orphanedSlot, err) } // If no sidecars exist at this slot, nothing to clean up if len(sidecars) == 0 { return nil } // Sidecars exist at this slot - they are orphaned, so delete them s.logger.Warn("Found orphaned blob sidecars from incomplete block finalization, removing", "slot", orphanedSlot.Base10(), "num_sidecars", len(sidecars), ) err = s.storageBackend.AvailabilityStore().DeleteBlobSidecars(orphanedSlot) if err != nil { return fmt.Errorf("failed to delete orphaned sidecars at slot %d: %w", orphanedSlot, err) } s.logger.Info("Successfully removed orphaned blob sidecars", "slot", orphanedSlot.Base10()) return nil } ================================================ FILE: beacon/payload-time/time.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package payloadtime import ( "errors" "fmt" "github.com/berachain/beacon-kit/primitives/math" ) // ErrTooFarInTheFuture is returned when the payload timestamp // in a block exceeds the time bound. var ErrTooFarInTheFuture = errors.New("timestamp too far in the future") func Verify( consensusTime, parentPayloadTimestamp, payloadTimestamp math.U64, ) error { bound := max( consensusTime+1, parentPayloadTimestamp+1, ) if payloadTimestamp > bound { return fmt.Errorf( "%w: timestamp bound: %d, got: %d", ErrTooFarInTheFuture, bound, payloadTimestamp, ) } return nil } func Next( consensusTime, parentPayloadTimestamp math.U64, buildOptimistically bool, ) math.U64 { delta := math.U64(0) if buildOptimistically { // we're building a payload to be included into next block. // We estimate it to be included next second. If this estimate // turns out wrong (cause consensus block are finalized faster or // slower than consensusTime+1 sec), we're still fine as long as // Verify pass which should always to since: // Next.consensusTime <= Verify.consensusTime delta = 1 } return max( consensusTime+delta, parentPayloadTimestamp+1, ) } ================================================ FILE: beacon/payload-time/time_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package payloadtime_test import ( "testing" "time" payloadtime "github.com/berachain/beacon-kit/beacon/payload-time" "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) // TestNextTimestampVerifies checks that next payload timestamp // built via payloadtime.Next always pass payloadtime.Verify. func TestNextTimestampVerifies(t *testing.T) { t.Parallel() tests := []struct { name string times func() (time.Time, time.Time) expectedErr error }{ { name: "Payload timestamp < consensus timestamp", times: func() (time.Time, time.Time) { consensusTime := time.Now().Truncate(time.Second) parentPayloadTimestamp := consensusTime.Add(-10 * time.Second) return consensusTime, parentPayloadTimestamp }, expectedErr: nil, }, { name: "Payload timestamp == consensus timestamp", times: func() (time.Time, time.Time) { consensusTime := time.Now().Truncate(time.Second) parentPayloadTimestamp := consensusTime return consensusTime, parentPayloadTimestamp }, expectedErr: nil, }, { name: "Payload timestamp > consensus timestamp", times: func() (time.Time, time.Time) { consensusTime := time.Now().Truncate(time.Second) parentPayloadTimestamp := consensusTime.Add(10 * time.Second) return consensusTime, parentPayloadTimestamp }, expectedErr: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() consensusTime, parentPayloadTimestamp := tt.times() // Optimistic build case nextPayload := payloadtime.Next( math.U64(consensusTime.Unix()), math.U64(parentPayloadTimestamp.Unix()), true, // buildOptimistically ) gotErr := payloadtime.Verify( math.U64(consensusTime.Unix()), math.U64(parentPayloadTimestamp.Unix()), nextPayload, ) if tt.expectedErr == nil { require.NoError(t, gotErr) } else { require.ErrorIs(t, tt.expectedErr, gotErr) } // Just in time build case nextPayload = payloadtime.Next( math.U64(consensusTime.Unix()), math.U64(parentPayloadTimestamp.Unix()), false, // buildOptimistically ) gotErr = payloadtime.Verify( math.U64(consensusTime.Unix()), math.U64(parentPayloadTimestamp.Unix()), nextPayload, ) if tt.expectedErr == nil { require.NoError(t, gotErr) } else { require.ErrorIs(t, tt.expectedErr, gotErr) } }) } } ================================================ FILE: beacon/validator/block_builder.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package validator import ( "context" "fmt" "time" payloadtime "github.com/berachain/beacon-kit/beacon/payload-time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/primitives/version" statedb "github.com/berachain/beacon-kit/state-transition/core/state" ) // BuildBlockAndSidecars builds a new beacon block. // //nolint:funlen // comments are pretty verbose func (s *Service) BuildBlockAndSidecars( ctx context.Context, slotData *types.SlotData, ) ([]byte, []byte, error) { startTime := time.Now() defer s.metrics.measureRequestBlockForProposalTime(startTime) if !s.localPayloadBuilder.Enabled() { // node is not supposed to build blocks return nil, nil, builder.ErrPayloadBuilderDisabled } // The goal here is to acquire a payload whose parent is the previously // finalized block, such that, if this payload is accepted, it will be // the next finalized block in the chain. A byproduct of this design // is that we get the nice property of lazily propagating the finalized // and safe block hashes to the execution client. st := s.sb.StateFromContext(ctx) // blkSlot is the height for the next block, which consensus is requesting BeaconKit to build. blkSlot := slotData.GetSlot() // Prepare the state such that it is ready to build a block for the requested slot. if _, err := s.stateProcessor.ProcessSlots(st, blkSlot); err != nil { return nil, nil, err } // Grab parent block root for payload request. parentBlockRoot, err := st.GetBlockRootAtIndex( (blkSlot.Unwrap() - 1) % s.chainSpec.SlotsPerHistoricalRoot(), ) if err != nil { return nil, nil, err } // Get the payload for the block. envelope, err := s.retrieveExecutionPayload(ctx, st, parentBlockRoot, slotData) if err != nil { return nil, nil, fmt.Errorf("failed retrieving execution payload: %w", err) } // We introduce hard forks with the expectation that the first block proposed after the // hard fork timestamp is when new rules apply. When building blocks, we provide the Execution // Layer client with a timestamp, and it will create its payload based on that timestamp. We // must use this same timestamp from the payload to build the beacon block. This ensures that // we are building on the same fork version as the Execution Layer. timestamp := envelope.GetExecutionPayload().GetTimestamp() // Build forkdata used for the signing root of the reveal and the sidecars. forkData, err := s.buildForkData(st, timestamp) if err != nil { return nil, nil, err } // Create a new empty block from the current state. blk, err := s.getEmptyBeaconBlockForSlot(st, blkSlot, forkData.CurrentVersion, parentBlockRoot) if err != nil { return nil, nil, err } // Build the reveal for the current slot. // TODO: We can optimize to pre-compute this in parallel? reveal, err := s.buildRandaoReveal(forkData, blkSlot) if err != nil { return nil, nil, err } // We have to assemble the block body prior to producing the sidecars // since we need to generate the inclusion proofs. if err = s.buildBlockBody(ctx, st, blk, reveal, envelope); err != nil { return nil, nil, fmt.Errorf("failed build block body: %w", err) } // Compute the state root for the block. if err = s.computeAndSetStateRoot( ctx, slotData.GetProposerAddress(), slotData.GetConsensusTime(), st, blk, ); err != nil { return nil, nil, err } // Craft the signature and signed beacon block. signedBlk, err := ctypes.NewSignedBeaconBlock(blk, forkData, s.chainSpec, s.signer) if err != nil { return nil, nil, err } // Produce blob sidecars with new StateRoot sidecars, err := s.blobFactory.BuildSidecars(signedBlk, envelope.GetBlobsBundle()) if err != nil { return nil, nil, err } s.logger.Info( "Beacon block successfully built", "slot", blkSlot.Base10(), "state_root", blk.GetStateRoot(), "duration", time.Since(startTime).String(), ) signedBlkBytes, bbErr := signedBlk.MarshalSSZ() if bbErr != nil { return nil, nil, bbErr } sidecarsBytes, scErr := sidecars.MarshalSSZ() if scErr != nil { return nil, nil, scErr } return signedBlkBytes, sidecarsBytes, nil } // getEmptyBeaconBlockForSlot creates a new empty block. func (s *Service) getEmptyBeaconBlockForSlot( st *statedb.StateDB, requestedSlot math.Slot, forkVersion common.Version, parentBlockRoot common.Root, ) (*ctypes.BeaconBlock, error) { // Get the proposer index for the slot. proposerIndex, err := st.ValidatorIndexByPubkey( s.signer.PublicKey(), ) if err != nil { return nil, err } // Create a new block. return ctypes.NewBeaconBlockWithVersion( requestedSlot, proposerIndex, parentBlockRoot, forkVersion, ) } func (s *Service) buildForkData(st *statedb.StateDB, timestamp math.U64) (*ctypes.ForkData, error) { genesisValidatorsRoot, err := st.GetGenesisValidatorsRoot() if err != nil { return nil, err } return ctypes.NewForkData( s.chainSpec.ActiveForkVersionForTimestamp(timestamp), genesisValidatorsRoot, ), nil } // buildRandaoReveal builds a randao reveal for the given slot. func (s *Service) buildRandaoReveal( forkData *ctypes.ForkData, slot math.Slot, ) (crypto.BLSSignature, error) { signingRoot := forkData.ComputeRandaoSigningRoot( s.chainSpec.DomainTypeRandao(), s.chainSpec.SlotToEpoch(slot), ) signature, err := s.signer.Sign(signingRoot[:]) if err != nil { return signature, fmt.Errorf("block building failed randao checks: %w", err) } return signature, nil } // retrieveExecutionPayload retrieves the execution payload for the block. func (s *Service) retrieveExecutionPayload( ctx context.Context, st *statedb.StateDB, parentBlockRoot common.Root, slotData *types.SlotData, ) (ctypes.BuiltExecutionPayloadEnv, error) { // TODO: Add external block builders to this flow. // // Get the payload for the block. Pass the expected fork given the current // CometBFT timestamp to try and build coherent blocks (i.e. blocks whose fork // version is the same for payload and the rest of CometBFT block). This coherence // is checked in ProcessProposal. Remember that CometBFT does not guarantee that the // timestamp provided here will be the one used in the block (Comet takes into account // the time it takes to build the block, which should be very small normally). slot := slotData.GetSlot() expectedPayloadFork := s.chainSpec.ActiveForkVersionForTimestamp(slotData.GetConsensusTime()) envelope, err := s.localPayloadBuilder.RetrievePayload(ctx, slot, parentBlockRoot, expectedPayloadFork) if err == nil { return envelope, nil } // If we failed to retrieve the payload, request a synchronous payload. // // NOTE: The state here is properly configured by the // prepareStateForBuilding // // call that needs to be called before requesting the Payload. // TODO: We should decouple the PayloadBuilder from BeaconState to make // this less confusing. s.metrics.failedToRetrievePayload(slot, err) // The latest execution payload header will be from the previous block // during the block building phase. lph, err := st.GetLatestExecutionPayloadHeader() if err != nil { return nil, err } // We must prepare the state for the fork version of the new block being built to handle // the case where the new block is on a new fork version. Although we do not have the // confirmed timestamp by the EL, we will assume it to be `nextPayloadTimestamp` to decide // the new block's fork version. nextPayloadTimestamp := payloadtime.Next( slotData.GetConsensusTime(), lph.GetTimestamp(), false, // buildOptimistically ) err = s.stateProcessor.ProcessFork(st, nextPayloadTimestamp, false) if err != nil { return nil, err } // Expected payloadWithdrawals to include in this payload. payloadWithdrawals, _, err := st.ExpectedWithdrawals(nextPayloadTimestamp) if err != nil { s.logger.Error( "Could not get expected withdrawals to get payload attribute", "error", err, ) return nil, err } // Get the previous randao mix. epoch := s.chainSpec.SlotToEpoch(slot) prevRandao, err := st.GetRandaoMixAtIndex( epoch.Unwrap() % s.chainSpec.EpochsPerHistoricalVector(), ) if err != nil { return nil, err } parentProposerPubkey, err := st.ParentProposerPubkey(nextPayloadTimestamp) if err != nil { return nil, fmt.Errorf("failed retrieving previous proposer public key: %w", err) } r := &builder.RequestPayloadData{ Slot: slot, Timestamp: nextPayloadTimestamp, PayloadWithdrawals: payloadWithdrawals, PrevRandao: prevRandao, ParentBlockRoot: parentBlockRoot, FCState: engineprimitives.ForkchoiceStateV1{ HeadBlockHash: lph.GetBlockHash(), SafeBlockHash: lph.GetParentHash(), FinalizedBlockHash: lph.GetParentHash(), }, ParentProposerPubkey: parentProposerPubkey, } return s.localPayloadBuilder.RequestPayloadSync(ctx, r) } // BuildBlockBody assembles the block body with necessary components. func (s *Service) buildBlockBody( ctx context.Context, st *statedb.StateDB, blk *ctypes.BeaconBlock, reveal crypto.BLSSignature, envelope ctypes.BuiltExecutionPayloadEnv, ) error { // Assemble a new block with the payload. body := blk.GetBody() if body == nil { return ErrNilBlkBody } // Set the reveal on the block body. body.SetRandaoReveal(reveal) // If we get returned a nil blobs bundle, we should return an error. blobsBundle := envelope.GetBlobsBundle() if blobsBundle == nil { return ErrNilBlobsBundle } // Set the KZG commitments on the block body. body.SetBlobKzgCommitments(blobsBundle.GetCommitments()) // Dequeue deposits from the state. depositIndex, err := st.GetEth1DepositIndex() if err != nil { return fmt.Errorf("failed loading eth1 deposit index: %w", err) } // Grab all previous deposits from genesis up to the current index + max deposits per block. deposits, localDepositRoot, err := s.sb.DepositStore().GetDepositsByIndex( ctx, constants.FirstDepositIndex, depositIndex+s.chainSpec.MaxDepositsPerBlock(), ) if err != nil { return err } if uint64(len(deposits)) < depositIndex { return errors.Wrapf(ErrDepositStoreIncomplete, "all historical deposits not available, expected: %d, got: %d", depositIndex, len(deposits), ) } s.logger.Info( "Building block body with local deposits", "start_index", depositIndex, "num_deposits", uint64(len(deposits))-depositIndex, ) eth1Data := ctypes.NewEth1Data(localDepositRoot) body.SetEth1Data(eth1Data) body.SetDeposits(deposits[depositIndex:]) // Set the graffiti on the block body. sizedGraffiti := bytes.ExtendToSize([]byte(s.cfg.Graffiti), bytes.B32Size) graffiti, err := bytes.ToBytes32(sizedGraffiti) if err != nil { return fmt.Errorf("failed processing graffiti: %w", err) } body.SetGraffiti(graffiti) // Fill in unused field with non-nil value body.SetSyncAggregate(&ctypes.SyncAggregate{}) // Set the execution payload on the block body. body.SetExecutionPayload(envelope.GetExecutionPayload()) if version.EqualsOrIsAfter(body.GetForkVersion(), version.Electra()) { encodedReqs := envelope.GetEncodedExecutionRequests() result := make([][]byte, len(encodedReqs)) for i, req := range encodedReqs { result[i] = req // conversion from ExecutionRequest to []byte } var requests *ctypes.ExecutionRequests if requests, err = ctypes.DecodeExecutionRequests(result); err != nil { return err } if err = body.SetExecutionRequests(requests); err != nil { return err } } return nil } // computeAndSetStateRoot computes the state root of an outgoing block // and sets it in the block. func (s *Service) computeAndSetStateRoot( ctx context.Context, proposerAddress []byte, consensusTime math.U64, st *statedb.StateDB, blk *ctypes.BeaconBlock, ) error { stateRoot, err := s.computeStateRoot( ctx, proposerAddress, consensusTime, st, blk, ) if err != nil { s.logger.Error( "failed to compute state root while building block ❗️ ", "slot", blk.GetSlot().Base10(), "error", err, ) return err } blk.SetStateRoot(stateRoot) return nil } // computeStateRoot computes the state root of an outgoing block. func (s *Service) computeStateRoot( ctx context.Context, proposerAddress []byte, consensusTime math.U64, st *statedb.StateDB, blk *ctypes.BeaconBlock, ) (common.Root, error) { startTime := time.Now() defer s.metrics.measureStateRootComputationTime(startTime) // TODO: Think about how this would affect the proposer when // the payload in their block has come from a remote builder. txCtx := transition.NewTransitionCtx( ctx, consensusTime, proposerAddress, ). WithVerifyPayload(false). WithVerifyRandao(false). WithVerifyResult(false). WithMeterGas(false) if _, err := s.stateProcessor.Transition(txCtx, st, blk); err != nil { return common.Root{}, err } return st.HashTreeRoot(), nil } ================================================ FILE: beacon/validator/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package validator // defaultGraffiti is the default graffiti string. const defaultGraffiti = "" // Config is the validator configuration. type Config struct { // Graffiti is the string that will be included in the // graffiti field of the beacon block. Graffiti string `mapstructure:"graffiti"` } // DefaultConfig returns the default fork configuration. func DefaultConfig() Config { return Config{ Graffiti: defaultGraffiti, } } ================================================ FILE: beacon/validator/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package validator import "github.com/berachain/beacon-kit/errors" var ( // ErrNilBlkBody is an error for when the block body is nil. ErrNilBlkBody = errors.New("nil block body") // ErrNilBlobsBundle is an error for when the blobs bundle is nil. ErrNilBlobsBundle = errors.New("nil blobs bundle") // ErrDepositStoreIncomplete is an error for when the deposit store has not returned // the expected amount of deposits. Could be due to pruning when it should not be enabled. ErrDepositStoreIncomplete = errors.New("deposits from deposit store incomplete") ) ================================================ FILE: beacon/validator/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package validator import ( "context" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/types" datypes "github.com/berachain/beacon-kit/da/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/state-transition/core" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage/deposit" ) // BlobFactory represents a blob factory interface. type BlobFactory interface { // BuildSidecars builds sidecars for a given block and blobs bundle. BuildSidecars( signedBlk *ctypes.SignedBeaconBlock, blobs engineprimitives.BlobsBundle, ) (datypes.BlobSidecars, error) } // PayloadBuilder represents a service that is responsible for // building eth1 blocks. type PayloadBuilder interface { // Enabled may be enabled (e.g. for validators) // or disabled (e.g. full nodes) Enabled() bool // RetrievePayload retrieves the payload for the given slot and parentBlockRoot. // If returned error is nil, payload is guaranteed to have expectedForkVersion version. RetrievePayload( ctx context.Context, slot math.Slot, parentBlockRoot common.Root, expectedForkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) // RequestPayloadSync requests a payload for the given slot and // blocks until the payload is delivered. RequestPayloadSync( ctx context.Context, r *builder.RequestPayloadData, ) (ctypes.BuiltExecutionPayloadEnv, error) } // StateProcessor defines the interface for processing the state. type StateProcessor interface { // ProcessFork prepares the state for the fork version at the given timestamp. ProcessFork( st *statedb.StateDB, timestamp math.U64, logUpgrade bool, ) error // ProcessSlots processes the slot. ProcessSlots( st *statedb.StateDB, slot math.Slot, ) (transition.ValidatorUpdates, error) // Transition performs the core state transition. Transition( ctx core.ReadOnlyContext, st *statedb.StateDB, blk *ctypes.BeaconBlock, ) (transition.ValidatorUpdates, error) } // StorageBackend is the interface for the storage backend. type StorageBackend interface { // DepositStore retrieves the deposit store. DepositStore() deposit.StoreManager // StateFromContext retrieves the beacon state from the context. StateFromContext(context.Context) *statedb.StateDB } // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { // IncrementCounter increments a counter metric identified by the provided // keys. IncrementCounter(key string, args ...string) // MeasureSince measures the time since the provided start time, // identified by the provided keys. MeasureSince(key string, start time.Time, args ...string) } type BlockBuilderI interface { BuildBlockAndSidecars( context.Context, *types.SlotData, ) ([]byte, []byte, error) } // ChainSpec defines an interface for accessing chain-specific parameters. type ChainSpec interface { SlotsPerHistoricalRoot() uint64 DomainTypeRandao() common.DomainType MaxDepositsPerBlock() uint64 ActiveForkVersionForTimestamp(timestamp math.U64) common.Version SlotToEpoch(slot math.Slot) math.Epoch EpochsPerHistoricalVector() uint64 ctypes.ProposerDomain } ================================================ FILE: beacon/validator/metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package validator import ( "time" "github.com/berachain/beacon-kit/primitives/math" ) // validatorMetrics is a struct that contains metrics for the chain. type validatorMetrics struct { // sink is the sink for the metrics. sink TelemetrySink } // newValidatorMetrics creates a new validatorMetrics. func newValidatorMetrics( sink TelemetrySink, ) *validatorMetrics { return &validatorMetrics{ sink: sink, } } // measureRequestBlockForProposalTime measures the time taken to run the request // best // block function. func (cm *validatorMetrics) measureRequestBlockForProposalTime( start time.Time, ) { cm.sink.MeasureSince( "beacon_kit.validator.request_block_for_proposal_duration", start, ) } // measureStateRootComputationTime measures the time taken to compute the state // root of a block. // It records the duration from the provided start time to the current time. func (cm *validatorMetrics) measureStateRootComputationTime(start time.Time) { cm.sink.MeasureSince( "beacon_kit.validator.state_root_computation_duration", start, ) } // failedToRetrievePayload increments the counter for the number of // times the validator failed to retrieve payloads. func (cm *validatorMetrics) failedToRetrievePayload( slot math.Slot, err error, ) { cm.sink.IncrementCounter( "beacon_kit.validator.failed_to_retrieve_payload", "slot", slot.Base10(), "error", err.Error(), ) } ================================================ FILE: beacon/validator/service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package validator import ( "context" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/crypto" ) // Service is responsible for building beacon blocks and sidecars. type Service struct { // cfg is the validator config. cfg *Config // logger is a logger. logger log.Logger // chainSpec is the chain spec. chainSpec ChainSpec // signer is used to retrieve the public key of this node. signer crypto.BLSSigner // blobFactory is used to create blob sidecars for blocks. blobFactory BlobFactory // sb is the beacon state backend. sb StorageBackend // stateProcessor is responsible for processing the state. stateProcessor StateProcessor // localPayloadBuilder represents the local block builder, this builder // is connected to this nodes execution client via the EngineAPI. // Building blocks are done by submitting forkchoice updates through. // The local Builder. localPayloadBuilder PayloadBuilder // metrics is a metrics collector. metrics *validatorMetrics } // NewService creates a new validator service. func NewService( cfg *Config, logger log.Logger, chainSpec ChainSpec, sb StorageBackend, stateProcessor StateProcessor, signer crypto.BLSSigner, blobFactory BlobFactory, localPayloadBuilder PayloadBuilder, ts TelemetrySink, ) *Service { return &Service{ cfg: cfg, logger: logger, sb: sb, chainSpec: chainSpec, signer: signer, stateProcessor: stateProcessor, blobFactory: blobFactory, localPayloadBuilder: localPayloadBuilder, metrics: newValidatorMetrics(ts), } } // Name returns the name of the service. func (s *Service) Name() string { return "validator" } func (s *Service) Start( _ context.Context, ) error { return nil } func (s *Service) Stop() error { return nil } ================================================ FILE: chain/chain_ids.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package chain // Chain IDs that must be used for specific Berachain networks. const ( // DevnetEth1ChainID is the chain ID for a local devnet. Used by `make start`, e2e tests, and // many unit tests. DevnetEth1ChainID uint64 = 80087 // MainnetEth1ChainID is the chain ID for the Berachain mainnet. MainnetEth1ChainID uint64 = 80094 // TestnetEth1ChainID is the chain ID for the Berachain public testnet, Bepolia. Also used by // simulated tests. TestnetEth1ChainID uint64 = 80069 ) ================================================ FILE: chain/data.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package chain import ( "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" "github.com/berachain/beacon-kit/primitives/common" ) // SpecData is the underlying data structure for chain-specific parameters. All fields with a // `mapstructure` tag are required. type SpecData struct { delay.Config `mapstructure:"block-delay-configuration"` // Gwei value constants. // // MaxEffectiveBalance is the maximum effective balance allowed for a validator. MaxEffectiveBalance uint64 `mapstructure:"max-effective-balance"` // EffectiveBalanceIncrement is the effective balance increment. EffectiveBalanceIncrement uint64 `mapstructure:"effective-balance-increment"` // HysteresisQuotient is the quotient used in effective balance calculations HysteresisQuotient uint64 `mapstructure:"hysteresis-quotient"` // HysteresisDownwardMultiplier is the multiplier for downward balance // adjustments. HysteresisDownwardMultiplier uint64 `mapstructure:"hysteresis-downward-multiplier"` // HysteresisUpwardMultiplier is the multiplier for upward balance // adjustments. HysteresisUpwardMultiplier uint64 `mapstructure:"hysteresis-upward-multiplier"` // Time parameters constants. // // SlotsPerEpoch is the number of slots per epoch. SlotsPerEpoch uint64 `mapstructure:"slots-per-epoch"` // SlotsPerHistoricalRoot is the number of slots per historical root. SlotsPerHistoricalRoot uint64 `mapstructure:"slots-per-historical-root"` // MinEpochsToInactivityPenalty is the minimum number of epochs before a // validator is penalized for inactivity. MinEpochsToInactivityPenalty uint64 `mapstructure:"min-epochs-to-inactivity-penalty"` // Signature domains. // // DomainDomainTypeProposerProposer is the domain for beacon proposer // signatures. DomainTypeProposer common.DomainType `mapstructure:"domain-type-beacon-proposer"` // DomainTypeAttester is the domain for beacon attester signatures. DomainTypeAttester common.DomainType `mapstructure:"domain-type-beacon-attester"` // DomainTypeRandao is the domain for RANDAO reveal signatures. DomainTypeRandao common.DomainType `mapstructure:"domain-type-randao"` // DomainTypeDeposit is the domain for deposit contract signatures. DomainTypeDeposit common.DomainType `mapstructure:"domain-type-deposit"` // DomainTypeVoluntaryExit is the domain for voluntary exit signatures. DomainTypeVoluntaryExit common.DomainType `mapstructure:"domain-type-voluntary-exit"` // DomainTypeSelectionProof is the domain for selection proof signatures. DomainTypeSelectionProof common.DomainType `mapstructure:"domain-type-selection-proof"` // DomainTypeAggregateAndProof is the domain for aggregate and proof // signatures. DomainTypeAggregateAndProof common.DomainType `mapstructure:"domain-type-aggregate-and-proof"` // DomainTypeApplicationMask is the domain for the application mask. DomainTypeApplicationMask common.DomainType `mapstructure:"domain-type-application-mask"` // Eth1-related values. // // DepositContractAddress is the address of the deposit contract. DepositContractAddress common.ExecutionAddress `mapstructure:"deposit-contract-address"` // MaxDepositsPerBlock specifies the maximum number of deposit operations // allowed per block. MaxDepositsPerBlock uint64 `mapstructure:"max-deposits-per-block"` // DepositEth1ChainID is the chain ID of the execution client. DepositEth1ChainID uint64 `mapstructure:"deposit-eth1-chain-id"` // Eth1FollowDistance is the distance between the eth1 chain and the beacon // chain with respect to reading deposits. Eth1FollowDistance uint64 `mapstructure:"eth1-follow-distance"` // TargetSecondsPerEth1Block is the target time between eth1 blocks. TargetSecondsPerEth1Block uint64 `mapstructure:"target-seconds-per-eth1-block"` // Fork-related values. // // GenesisTime is the time at which the genesis block was created. GenesisTime uint64 `mapstructure:"genesis-time"` // Deneb1ForkTime is the time at which the Deneb1 fork is activated. Deneb1ForkTime uint64 `mapstructure:"deneb-one-fork-time"` // ElectraForkTime is the time at which the Electra fork is activated. ElectraForkTime uint64 `mapstructure:"electra-fork-time"` // Electra1ForkTime is the time at which the Electra1 fork is activated. Electra1ForkTime uint64 `mapstructure:"electra-one-fork-time"` // FuluForkTime is the time at which the Fulu fork is activated (Fusaka CL fork). FuluForkTime uint64 `mapstructure:"fulu-fork-time"` // State list lengths // // EpochsPerHistoricalVector is the number of epochs in the historical // vector. EpochsPerHistoricalVector uint64 `mapstructure:"epochs-per-historical-vector"` // EpochsPerSlashingsVector is the number of epochs in the slashings vector. EpochsPerSlashingsVector uint64 `mapstructure:"epochs-per-slashings-vector"` // HistoricalRootsLimit is the maximum number of historical roots. HistoricalRootsLimit uint64 `mapstructure:"historical-roots-limit"` // ValidatorRegistryLimit is the maximum number of validators in the // registry. ValidatorRegistryLimit uint64 `mapstructure:"validator-registry-limit"` // Capella Values // // MaxWithdrawalsPerPayload indicates the maximum number of withdrawal // operations allowed in a single payload. MaxWithdrawalsPerPayload uint64 `mapstructure:"max-withdrawals-per-payload"` // MaxValidatorsPerWithdrawalsSweep specifies the maximum number of validator withdrawals // allowed per sweep. Note that this value should ideally be smaller than the total number // of validators in the registry. MaxValidatorsPerWithdrawalsSweep uint64 `mapstructure:"max-validators-per-withdrawals-sweep"` // Deneb Values // // MinEpochsForBlobsSidecarsRequest is the minimum number of epochs the node // will keep the blobs for. MinEpochsForBlobsSidecarsRequest uint64 `mapstructure:"min-epochs-for-blobs-sidecars-request"` // MaxBlobCommitmentsPerBlock specifies the maximum number of blob // commitments allowed per block. MaxBlobCommitmentsPerBlock uint64 `mapstructure:"max-blob-commitments-per-block"` // MaxBlobsPerBlock specifies the maximum number of blobs allowed per block. MaxBlobsPerBlock uint64 `mapstructure:"max-blobs-per-block"` // FieldElementsPerBlob specifies the number of field elements per blob. FieldElementsPerBlob uint64 `mapstructure:"field-elements-per-blob"` // BytesPerBlob denotes the size of EIP-4844 blobs in bytes. BytesPerBlob uint64 `mapstructure:"bytes-per-blob"` // Berachain Values at genesis // // ValidatorSetCap is the maximum number of validators that can be active // for a given epoch // Note: ValidatorSetCap must be smaller than ValidatorRegistryLimit. ValidatorSetCap uint64 `mapstructure:"validator-set-cap"` // EVMInflationAddressGenesis is the address on the EVM which will receive the // inflation amount of native EVM balance through a withdrawal every block. EVMInflationAddressGenesis common.ExecutionAddress `mapstructure:"evm-inflation-address"` // EVMInflationPerBlockGenesis is the amount of native EVM balance (in Gwei) to be // minted to the EVMInflationAddress via a withdrawal every block. EVMInflationPerBlockGenesis uint64 `mapstructure:"evm-inflation-per-block"` // Deneb1 Value Changes // // EVMInflationAddressDeneb1 is the address on the EVM which will receive the // inflation amount of native EVM balance through a withdrawal every block in the Deneb1 fork. EVMInflationAddressDeneb1 common.ExecutionAddress `mapstructure:"evm-inflation-address-deneb-one"` // EVMInflationPerBlockDeneb1 is the amount of native EVM balance (in Gwei) to be // minted to the EVMInflationAddressDeneb1 via a withdrawal every block in the Deneb1 fork. EVMInflationPerBlockDeneb1 uint64 `mapstructure:"evm-inflation-per-block-deneb-one"` // Electra Values // // MinActivationBalance [New in Electra:EIP7251] Minimum balance for a validator to become active MinActivationBalance uint64 `mapstructure:"min-activation-balance"` // MinValidatorWithdrawabilityDelay is defined in the Electra spec and introduces // withdrawability delays to allow for slashing. MinValidatorWithdrawabilityDelay uint64 `mapstructure:"min-validator-withdrawability-delay"` // Fulu Value Changes // // HysteresisQuotientFulu is the hysteresis quotient for the Fulu fork (BRIP-0008). HysteresisQuotientFulu uint64 `mapstructure:"hysteresis-quotient-fulu"` // HysteresisUpwardMultiplierFulu is the hysteresis upward multiplier for the Fulu fork. HysteresisUpwardMultiplierFulu uint64 `mapstructure:"hysteresis-upward-multiplier-fulu"` // EVMInflationAddressFulu is the address on the EVM which will receive the // inflation amount of native EVM balance through a withdrawal every block in the Fulu fork. EVMInflationAddressFulu common.ExecutionAddress `mapstructure:"evm-inflation-address-fulu"` // EVMInflationPerBlockFulu is the amount of native EVM balance (in Gwei) to be // minted to the EVMInflationAddressFulu via a withdrawal every block in the Fulu fork. EVMInflationPerBlockFulu uint64 `mapstructure:"evm-inflation-per-block-fulu"` } ================================================ FILE: chain/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package chain import "github.com/berachain/beacon-kit/errors" var ( // ErrInsufficientMaxWithdrawalsPerPayload is returned when the max // withdrawals per payload less than 2. Must allow at least one for the EVM // inflation withdrawal, and at least one more for a validator withdrawal // per block. ErrInsufficientMaxWithdrawalsPerPayload = errors.New( "max withdrawals per payload must be greater than 1") // ErrInvalidValidatorSetCap is returned when the validator set cap is // greater than the validator registry limit. ErrInvalidValidatorSetCap = errors.New( "validator set cap must be less than the validator registry limit", ) ) ================================================ FILE: chain/helpers.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package chain import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" ) // ActiveForkVersionForTimestamp returns the active fork version for a given timestamp. func (s spec) ActiveForkVersionForTimestamp(timestamp math.U64) common.Version { time := timestamp.Unwrap() if time >= s.FuluForkTime() { return version.Fulu() } if time >= s.Electra1ForkTime() { return version.Electra1() } if time >= s.ElectraForkTime() { return version.Electra() } if time >= s.Deneb1ForkTime() { return version.Deneb1() } return version.Deneb() } // GenesisForkVersion returns the fork version at genesis. func (s spec) GenesisForkVersion() common.Version { return s.ActiveForkVersionForTimestamp(math.U64(s.GenesisTime())) } // SlotToEpoch converts a slot to an epoch. func (s spec) SlotToEpoch(slot math.Slot) math.Epoch { return math.Epoch(slot.Unwrap() / s.SlotsPerEpoch()) } // WithinDAPeriod checks if the block epoch is within MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS // of the given current epoch. func (s spec) WithinDAPeriod(block, current math.Slot) bool { return s.SlotToEpoch(block)+s.MinEpochsForBlobsSidecarsRequest() >= s.SlotToEpoch(current) } // IsMainnet returns true if the chain is running with the mainnet chain ID. func (s spec) IsMainnet() bool { return s.DepositEth1ChainID() == MainnetEth1ChainID } // IsTestnet returns true if the chain is running with the testnet chain ID. func (s spec) IsTestnet() bool { return s.DepositEth1ChainID() == TestnetEth1ChainID } // IsDevnet returns true if the chain is running with the devnet chain ID. func (s spec) IsDevnet() bool { return s.DepositEth1ChainID() == DevnetEth1ChainID } ================================================ FILE: chain/helpers_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package chain_test import ( "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) // TODO: Add setupValid, setupInvalid functions and use in each test. // Create an instance of chainSpec with test data. var spec, _ = chain.NewSpec( &chain.SpecData{ Deneb1ForkTime: 9 * 32 * 2, ElectraForkTime: 10 * 32 * 2, Electra1ForkTime: 11 * 32 * 2, FuluForkTime: 12 * 32 * 2, SlotsPerEpoch: 32, MinEpochsForBlobsSidecarsRequest: 5, MaxWithdrawalsPerPayload: 2, }, ) // TestActiveForkVersionForTimestamp tests the ActiveForkVersionForTimestamp method. func TestActiveForkVersionForTimestamp(t *testing.T) { t.Parallel() // Define test cases tests := []struct { name string timestamp uint64 expected common.Version }{ {name: "Before Electra Fork", timestamp: spec.ElectraForkTime() - 1, expected: version.Deneb1()}, {name: "At Electra Fork", timestamp: spec.ElectraForkTime(), expected: version.Electra()}, {name: "After Electra Fork", timestamp: spec.ElectraForkTime() + 1, expected: version.Electra()}, } // Run test cases for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := spec.ActiveForkVersionForTimestamp(math.U64(tt.timestamp)) require.Equal(t, tt.expected, result, "Test case : %s", tt.name) }) } } // TestSlotToEpoch tests the SlotToEpoch method. func TestSlotToEpoch(t *testing.T) { t.Parallel() // Define test cases tests := []struct { name string slot math.Slot expected math.Epoch }{ {name: "Epoch 0, Slot 0", slot: 0, expected: 0}, {name: "Epoch 0, Slot 31", slot: 31, expected: 0}, {name: "Epoch 1, Slot 32", slot: 32, expected: 1}, {name: "Epoch 1, Slot 63", slot: 63, expected: 1}, {name: "Epoch 2, Slot 64", slot: 64, expected: 2}, {name: "Epoch 2, Slot 95", slot: 95, expected: 2}, } // Run test cases for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := spec.SlotToEpoch(tt.slot) require.Equal(t, tt.expected, result, "Test case : %s", tt.name) }) } } // TestWithinDAPeriod tests the WithinDAPeriod method. func TestWithinDAPeriod(t *testing.T) { t.Parallel() // Define test cases tests := []struct { name string block math.Slot current math.Slot expected bool }{ // Block is within DA period (5 epochs). {name: "Within DA Period", block: 0, current: 160, expected: true}, // Block is outside DA period (>5 epochs). {name: "Outside DA Period", block: 0, current: 192, expected: false}, // Block is within DA period. {name: "Within DA Period 2", block: 160, current: 320, expected: true}, // Block is outside DA period. { name: "Outside DA Period 2", block: 160, current: 352, expected: false, }, } // Run test cases for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := spec.WithinDAPeriod(tt.block, tt.current) require.Equal(t, tt.expected, result, "Test case : %s", tt.name) }) } } ================================================ FILE: chain/spec.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package chain import ( "fmt" "time" "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" ) type BalancesSpec interface { // MaxEffectiveBalance returns the maximum balance counted in rewards calculations in Gwei. MaxEffectiveBalance() math.Gwei // EffectiveBalanceIncrement returns the increment of balance used in reward calculations in // Gwei. EffectiveBalanceIncrement() math.Gwei // MinActivationBalance returns the minimum balance required to become an active validator in // Gwei MinActivationBalance() math.Gwei } type HysteresisSpec interface { // HysteresisQuotient returns the quotient used in effective balance // calculations to create hysteresis. This provides resistance to small // balance changes triggering effective balance updates. // This value is fork-gated by timestamp (updated in Fulu per BRIP-0008). HysteresisQuotient(timestamp math.U64) math.U64 // HysteresisDownwardMultiplier returns the multiplier used when checking // if the effective balance should be decreased. // This value is NOT fork-gated by timestamped as no changes are expected to this value. HysteresisDownwardMultiplier() math.U64 // HysteresisUpwardMultiplier returns the multiplier used when checking // if the effective balance should be increased. // This value is fork-gated by timestamp (updated in Fulu per BRIP-0008). HysteresisUpwardMultiplier(timestamp math.U64) math.U64 } type DepositSpec interface { // MaxDepositsPerBlock returns the maximum number of deposit operations per // block. MaxDepositsPerBlock() uint64 // DepositEth1ChainID returns the chain ID of the deposit contract. DepositEth1ChainID() uint64 } type DomainTypeSpec interface { // Signature Domains // DomainTypeProposer returns the domain for proposer signatures. DomainTypeProposer() common.DomainType // DomainTypeAttester returns the domain for attester signatures. DomainTypeAttester() common.DomainType // DomainTypeRandao returns the domain for RANDAO reveal signatures. DomainTypeRandao() common.DomainType // DomainTypeDeposit returns the domain for deposit signatures. DomainTypeDeposit() common.DomainType // DomainTypeVoluntaryExit returns the domain for voluntary exit signatures. DomainTypeVoluntaryExit() common.DomainType // DomainTypeSelectionProof returns the domain for selection proof DomainTypeSelectionProof() common.DomainType // DomainTypeAggregateAndProof returns the domain for aggregate and proof DomainTypeAggregateAndProof() common.DomainType // DomainTypeApplicationMask returns the domain for application signatures. DomainTypeApplicationMask() common.DomainType } // Fork-related values. type ForkSpec interface { // GenesisTime returns the time at which the genesis block was created. GenesisTime() uint64 // Deneb1ForkTime returns the time at which the Deneb1 fork takes effect. Deneb1ForkTime() uint64 // ElectraForkTime returns the time at which the Electra fork takes effect. ElectraForkTime() uint64 // Electra1ForkTime returns the time at which the Electra1 fork takes effect. Electra1ForkTime() uint64 // FuluForkTime returns the time at which the Fulu fork takes effect. FuluForkTime() uint64 } type BlobSpec interface { // MaxBlobCommitmentsPerBlock returns the maximum number of blob commitments // per block. MaxBlobCommitmentsPerBlock() uint64 // MaxBlobsPerBlock returns the maximum number of blobs per block. MaxBlobsPerBlock() uint64 // FieldElementsPerBlob returns the number of field elements per blob. FieldElementsPerBlob() uint64 // WithinDAPeriod checks if a given block slot is within the data // availability period relative to the current slot. WithinDAPeriod(block, current math.Slot) bool // BytesPerBlob returns the number of bytes per blob. BytesPerBlob() uint64 // MinEpochsForBlobsSidecarsRequest returns the minimum number of epochs for // blob sidecar requests. MinEpochsForBlobsSidecarsRequest() math.Epoch } // Helpers for Fork Version type ForkVersionSpec interface { // GenesisForkVersion returns the fork version at genesis. GenesisForkVersion() common.Version // ActiveForkVersionForTimestamp returns the active fork version for a given timestamp. ActiveForkVersionForTimestamp(timestamp math.U64) common.Version } type BerachainSpec interface { // EVMInflationAddress returns the address on the EVM which will receive // the inflation amount of native EVM balance through a withdrawal every // block. EVMInflationAddress(timestamp math.U64) common.ExecutionAddress // EVMInflationPerBlock returns the amount of native EVM balance (in Gwei) // to be minted to the EVMInflationAddress via a withdrawal every block. EVMInflationPerBlock(timestamp math.U64) math.Gwei // ValidatorSetCap retrieves the maximum number of validators allowed in the active set. ValidatorSetCap() uint64 // IsMainnet returns true if the chain is running with the mainnet chain ID. IsMainnet() bool // IsTestnet returns true if the chain is running with the testnet chain ID. IsTestnet() bool // IsDevnet returns true if the chain is running with the devnet chain ID. IsDevnet() bool } type WithdrawalsSpec interface { // MaxWithdrawalsPerPayload returns the maximum number of withdrawals per // payload. MaxWithdrawalsPerPayload() uint64 // MaxValidatorsPerWithdrawalsSweep returns the maximum number of validators // per withdrawal sweep. MaxValidatorsPerWithdrawalsSweep() math.U64 // MinValidatorWithdrawabilityDelay - an exited validator remains eligible to be slashed until its withdrawable_epoch, // which is set to MIN_VALIDATOR_WITHDRAWABILITY_DELAY epochs after its exit_epoch. // This is to allow some extra time for any slashable offences by the validator to be detected and reported. MinValidatorWithdrawabilityDelay() math.Epoch } // Spec defines an interface for accessing chain-specific parameters. type Spec interface { delay.ConfigGetter DepositSpec BalancesSpec HysteresisSpec DomainTypeSpec ForkSpec BlobSpec ForkVersionSpec BerachainSpec WithdrawalsSpec // Time parameters constants. // SlotToEpoch converts a slot number to an epoch number. SlotToEpoch(slot math.Slot) math.Epoch // SlotsPerEpoch returns the number of slots in an epoch. SlotsPerEpoch() uint64 // SlotsPerHistoricalRoot returns the number of slots per historical root. SlotsPerHistoricalRoot() uint64 // MinEpochsToInactivityPenalty returns the minimum number of epochs before // an inactivity penalty is applied. MinEpochsToInactivityPenalty() uint64 // Eth1-related values. // DepositContractAddress returns the deposit contract address. DepositContractAddress() common.ExecutionAddress // Eth1FollowDistance returns the distance between the eth1 chain and the // beacon chain for eth1 data. Eth1FollowDistance() uint64 // TargetSecondsPerEth1Block returns the target time between eth1 blocks. TargetSecondsPerEth1Block() uint64 // State list lengths // EpochsPerHistoricalVector returns the length of the historical vector. EpochsPerHistoricalVector() uint64 // EpochsPerSlashingsVector returns the length of the slashing vector. EpochsPerSlashingsVector() uint64 // HistoricalRootsLimit returns the maximum number of historical root // entries. HistoricalRootsLimit() uint64 // ValidatorRegistryLimit returns the maximum number of validators in the // registry. ValidatorRegistryLimit() uint64 } // spec is a concrete implementation of the Spec interface, holding the actual data. type spec struct { // Data contains the actual chain-specific parameter values. Data *SpecData } // NewSpec creates a new instance of a Spec with the provided data. func NewSpec(data *SpecData) (Spec, error) { s := spec{Data: data} return s, s.validate() } // validate ensures that the chain spec is valid, returning error if it is not. func (s spec) validate() error { if s.Data.MaxWithdrawalsPerPayload <= 1 { return ErrInsufficientMaxWithdrawalsPerPayload } if s.Data.ValidatorSetCap > s.Data.ValidatorRegistryLimit { return ErrInvalidValidatorSetCap } // EVM Inflation values can be zero or non-zero, no validation needed. // Enforce ordering of the forks. Like most chains, BeaconKit does not support arbitrary ordering of forks. // Fork times here are in chronological order orderedForkTimes := []uint64{ s.Data.GenesisTime, s.Data.Deneb1ForkTime, s.Data.ElectraForkTime, s.Data.Electra1ForkTime, s.Data.FuluForkTime, } for i := 1; i < len(orderedForkTimes); i++ { prev, cur := orderedForkTimes[i-1], orderedForkTimes[i] // must not go backwards if prev > cur { return fmt.Errorf( "fork ordering violation: timestamp at index %d (%d) > index %d (%d)", i-1, prev, i, cur, ) } } if s.Data.ConsensusUpdateHeight != 0 { if s.Data.ConsensusUpdateHeight >= s.Data.ConsensusEnableHeight { return fmt.Errorf( "stable block time parameters violation: ConsensusUpdateHeight %d must be smaller than ConsensusEnableHeight %d", s.Data.ConsensusUpdateHeight, s.Data.ConsensusEnableHeight, ) } if s.Data.MaxBlockDelay == 0 { return errors.New("max block delay can't be zero") } if s.Data.TargetBlockTime == 0 { return errors.New("target block time can't be zero") } } // TODO: Add more validation rules here. return nil } func (s spec) SbtMaxBlockDelay() time.Duration { return s.Data.MaxBlockDelay } func (s spec) SbtTargetBlockTime() time.Duration { return s.Data.TargetBlockTime } func (s spec) SbtConstBlockDelay() time.Duration { return s.Data.ConstBlockDelay } func (s spec) SbtConsensusUpdateHeight() int64 { return s.Data.ConsensusUpdateHeight } func (s spec) SbtConsensusEnableHeight() int64 { return s.Data.ConsensusEnableHeight } // MaxEffectiveBalance returns the maximum effective balance. func (s spec) MaxEffectiveBalance() math.Gwei { return math.Gwei(s.Data.MaxEffectiveBalance) } // MinActivationBalance returns the minimum activation balance effective. Introduced in Electra. func (s spec) MinActivationBalance() math.Gwei { return math.Gwei(s.Data.MinActivationBalance) } // EffectiveBalanceIncrement returns the increment of effective balance. func (s spec) EffectiveBalanceIncrement() math.Gwei { return math.Gwei(s.Data.EffectiveBalanceIncrement) } func (s spec) HysteresisQuotient(timestamp math.U64) math.U64 { fv := s.ActiveForkVersionForTimestamp(timestamp) switch { case version.Equals(fv, version.Fulu()): return math.U64(s.Data.HysteresisQuotientFulu) case version.Equals(fv, s.GenesisForkVersion()), version.Equals(fv, version.Deneb1()), version.Equals(fv, version.Electra()), version.Equals(fv, version.Electra1()): return math.U64(s.Data.HysteresisQuotient) } panic(fmt.Sprintf("HysteresisQuotient not supported for this fork version: %d", fv)) } func (s spec) HysteresisDownwardMultiplier() math.U64 { return math.U64(s.Data.HysteresisDownwardMultiplier) } func (s spec) HysteresisUpwardMultiplier(timestamp math.U64) math.U64 { fv := s.ActiveForkVersionForTimestamp(timestamp) switch { case version.Equals(fv, version.Fulu()): return math.U64(s.Data.HysteresisUpwardMultiplierFulu) case version.Equals(fv, s.GenesisForkVersion()), version.Equals(fv, version.Deneb1()), version.Equals(fv, version.Electra()), version.Equals(fv, version.Electra1()): return math.U64(s.Data.HysteresisUpwardMultiplier) } panic(fmt.Sprintf("HysteresisUpwardMultiplier not supported for this fork version: %d", fv)) } // SlotsPerEpoch returns the number of slots per epoch. func (s spec) SlotsPerEpoch() uint64 { return s.Data.SlotsPerEpoch } // SlotsPerHistoricalRoot returns the number of slots per historical root. func (s spec) SlotsPerHistoricalRoot() uint64 { return s.Data.SlotsPerHistoricalRoot } // MinEpochsToInactivityPenalty returns the minimum number of epochs before an // inactivity penalty is applied. func (s spec) MinEpochsToInactivityPenalty() uint64 { return s.Data.MinEpochsToInactivityPenalty } // DomainTypeProposer returns the domain for beacon proposer signatures. func (s spec) DomainTypeProposer() common.DomainType { return s.Data.DomainTypeProposer } // DomainTypeAttester returns the domain for beacon attester signatures. func (s spec) DomainTypeAttester() common.DomainType { return s.Data.DomainTypeAttester } // DomainTypeRandao returns the domain for RANDAO reveal signatures. func (s spec) DomainTypeRandao() common.DomainType { return s.Data.DomainTypeRandao } // DomainTypeDeposit returns the domain for deposit contract signatures. func (s spec) DomainTypeDeposit() common.DomainType { return s.Data.DomainTypeDeposit } // DomainTypeVoluntaryExit returns the domain for voluntary exit signatures. func (s spec) DomainTypeVoluntaryExit() common.DomainType { return s.Data.DomainTypeVoluntaryExit } // DomainTypeSelectionProof returns the domain for selection proof signatures. func (s spec) DomainTypeSelectionProof() common.DomainType { return s.Data.DomainTypeSelectionProof } // DomainTypeAggregateAndProof returns the domain for aggregate and proof // signatures. func (s spec) DomainTypeAggregateAndProof() common.DomainType { return s.Data.DomainTypeAggregateAndProof } // DomainTypeApplicationMask returns the domain for the application mask. func (s spec) DomainTypeApplicationMask() common.DomainType { return s.Data.DomainTypeApplicationMask } // DepositContractAddress returns the address of the deposit contract. func (s spec) DepositContractAddress() common.ExecutionAddress { return s.Data.DepositContractAddress } // MaxDepositsPerBlock returns the maximum number of deposits per block. func (s spec) MaxDepositsPerBlock() uint64 { return s.Data.MaxDepositsPerBlock } // DepositEth1ChainID returns the chain ID of the execution chain. func (s spec) DepositEth1ChainID() uint64 { return s.Data.DepositEth1ChainID } // Eth1FollowDistance returns the distance between the eth1 chain and the beacon // chain. func (s spec) Eth1FollowDistance() uint64 { return s.Data.Eth1FollowDistance } // TargetSecondsPerEth1Block returns the target time between eth1 blocks. func (s spec) TargetSecondsPerEth1Block() uint64 { return s.Data.TargetSecondsPerEth1Block } // GenesisTime returns the time at which the genesis block was created. func (s spec) GenesisTime() uint64 { return s.Data.GenesisTime } // Deneb1ForkTime returns the timestamp of the Deneb1 fork. func (s spec) Deneb1ForkTime() uint64 { return s.Data.Deneb1ForkTime } // ElectraForkTime returns the timestamp of the Electra fork. func (s spec) ElectraForkTime() uint64 { return s.Data.ElectraForkTime } // Electra1ForkTime returns the epoch of the Electra1 fork. func (s spec) Electra1ForkTime() uint64 { return s.Data.Electra1ForkTime } // FuluForkTime returns the timestamp of the Fulu fork. func (s spec) FuluForkTime() uint64 { return s.Data.FuluForkTime } // EpochsPerHistoricalVector returns the number of epochs per historical vector. func (s spec) EpochsPerHistoricalVector() uint64 { return s.Data.EpochsPerHistoricalVector } // EpochsPerSlashingsVector returns the number of epochs per slashings vector. func (s spec) EpochsPerSlashingsVector() uint64 { return s.Data.EpochsPerSlashingsVector } // HistoricalRootsLimit returns the limit of historical roots. func (s spec) HistoricalRootsLimit() uint64 { return s.Data.HistoricalRootsLimit } // ValidatorRegistryLimit returns the limit of the validator registry. func (s spec) ValidatorRegistryLimit() uint64 { return s.Data.ValidatorRegistryLimit } // MaxWithdrawalsPerPayload returns the maximum number of withdrawals per // payload. func (s spec) MaxWithdrawalsPerPayload() uint64 { return s.Data.MaxWithdrawalsPerPayload } // MaxValidatorsPerWithdrawalsSweep returns the maximum number of validators per withdrawals sweep. func (s spec) MaxValidatorsPerWithdrawalsSweep() math.U64 { return math.U64(s.Data.MaxValidatorsPerWithdrawalsSweep) } func (s spec) MinValidatorWithdrawabilityDelay() math.Epoch { return math.Epoch(s.Data.MinValidatorWithdrawabilityDelay) } // MinEpochsForBlobsSidecarsRequest returns the minimum number of epochs for // blobs sidecars request. func (s spec) MinEpochsForBlobsSidecarsRequest() math.Epoch { return math.Epoch(s.Data.MinEpochsForBlobsSidecarsRequest) } // MaxBlobCommitmentsPerBlock returns the maximum number of blob commitments per // block. func (s spec) MaxBlobCommitmentsPerBlock() uint64 { return s.Data.MaxBlobCommitmentsPerBlock } // MaxBlobsPerBlock returns the maximum number of blobs per block. func (s spec) MaxBlobsPerBlock() uint64 { return s.Data.MaxBlobsPerBlock } // FieldElementsPerBlob returns the number of field elements per blob. func (s spec) FieldElementsPerBlob() uint64 { return s.Data.FieldElementsPerBlob } // BytesPerBlob returns the number of bytes per blob. func (s spec) BytesPerBlob() uint64 { return s.Data.BytesPerBlob } // ValidatorSetCap retrieves the maximum number of validators allowed in the active set. func (s spec) ValidatorSetCap() uint64 { return s.Data.ValidatorSetCap } // EVMInflationAddress returns the address on the EVM which will receive the // inflation amount of native EVM balance through a withdrawal every block. func (s spec) EVMInflationAddress(timestamp math.U64) common.ExecutionAddress { fv := s.ActiveForkVersionForTimestamp(timestamp) switch { case version.Equals(fv, version.Fulu()): return s.Data.EVMInflationAddressFulu case version.Equals(fv, version.Deneb1()), version.Equals(fv, version.Electra()), version.Equals(fv, version.Electra1()): return s.Data.EVMInflationAddressDeneb1 case version.Equals(fv, s.GenesisForkVersion()): return s.Data.EVMInflationAddressGenesis } panic(fmt.Sprintf("EVMInflationAddress not supported for this fork version: %d", fv)) } // EVMInflationPerBlock returns the amount of native EVM balance (in Gwei) to // be minted to the EVMInflationAddress via a withdrawal every block. func (s spec) EVMInflationPerBlock(timestamp math.U64) math.Gwei { fv := s.ActiveForkVersionForTimestamp(timestamp) switch { case version.Equals(fv, version.Fulu()): return math.Gwei(s.Data.EVMInflationPerBlockFulu) case version.Equals(fv, version.Deneb1()), version.Equals(fv, version.Electra()), version.Equals(fv, version.Electra1()): return math.Gwei(s.Data.EVMInflationPerBlockDeneb1) case version.Equals(fv, s.GenesisForkVersion()): return math.Gwei(s.Data.EVMInflationPerBlockGenesis) } panic(fmt.Sprintf("EVMInflationPerBlock not supported for this fork version: %d", fv)) } ================================================ FILE: chain/spec_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package chain_test import ( "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) func baseSpecData() *chain.SpecData { return &chain.SpecData{ // satisfy the pre-checks in validate() MaxWithdrawalsPerPayload: 2, ValidatorSetCap: 100, ValidatorRegistryLimit: 100, } } // Fork timestamps used by the fork-gated method tests. Values are chosen to be // well-separated so boundary cases around each fork can be tested explicitly. const ( forkGatedGenesisTime uint64 = 0 forkGatedDeneb1Time uint64 = 100 forkGatedElectraTime uint64 = 200 forkGatedElectra1Time uint64 = 300 forkGatedFuluTime uint64 = 400 ) // Pre-Fulu hysteresis values. Distinct from the Fulu values so tests can detect // when the wrong fork branch is taken. const ( preFuluHysteresisQuotient uint64 = 4 preFuluHysteresisUpwardMultiplier uint64 = 5 fuluHysteresisQuotient uint64 = 40 fuluHysteresisUpwardMultiplierFulu uint64 = 50 ) // EVM inflation per block values, distinct per fork region. const ( evmInflationPerBlockGenesis uint64 = 10 evmInflationPerBlockDeneb1 uint64 = 20 evmInflationPerBlockFulu uint64 = 30 ) var ( evmInflationAddrGenesis = common.MustNewExecutionAddressFromHex( "0x1111111111111111111111111111111111111111", ) evmInflationAddrDeneb1 = common.MustNewExecutionAddressFromHex( "0x2222222222222222222222222222222222222222", ) evmInflationAddrFulu = common.MustNewExecutionAddressFromHex( "0x3333333333333333333333333333333333333333", ) ) // buildForkGatedSpec builds a Spec with distinct fork-gated values so tests can // assert which fork branch is taken for a given timestamp. func buildForkGatedSpec(t *testing.T) chain.Spec { t.Helper() data := baseSpecData() data.GenesisTime = forkGatedGenesisTime data.Deneb1ForkTime = forkGatedDeneb1Time data.ElectraForkTime = forkGatedElectraTime data.Electra1ForkTime = forkGatedElectra1Time data.FuluForkTime = forkGatedFuluTime data.HysteresisQuotient = preFuluHysteresisQuotient data.HysteresisUpwardMultiplier = preFuluHysteresisUpwardMultiplier data.HysteresisQuotientFulu = fuluHysteresisQuotient data.HysteresisUpwardMultiplierFulu = fuluHysteresisUpwardMultiplierFulu data.EVMInflationAddressGenesis = evmInflationAddrGenesis data.EVMInflationPerBlockGenesis = evmInflationPerBlockGenesis data.EVMInflationAddressDeneb1 = evmInflationAddrDeneb1 data.EVMInflationPerBlockDeneb1 = evmInflationPerBlockDeneb1 data.EVMInflationAddressFulu = evmInflationAddrFulu data.EVMInflationPerBlockFulu = evmInflationPerBlockFulu s, err := chain.NewSpec(data) require.NoError(t, err) return s } // TestHysteresisQuotient_ForkBoundary asserts HysteresisQuotient returns the // pre-Fulu value for all fork versions up to and including Electra1, and the // Fulu value at or after FuluForkTime. func TestHysteresisQuotient_ForkBoundary(t *testing.T) { t.Parallel() s := buildForkGatedSpec(t) tests := []struct { name string timestamp uint64 expected math.U64 }{ {name: "At genesis (Deneb)", timestamp: forkGatedGenesisTime, expected: math.U64(preFuluHysteresisQuotient)}, {name: "At Deneb1 fork", timestamp: forkGatedDeneb1Time, expected: math.U64(preFuluHysteresisQuotient)}, {name: "At Electra fork", timestamp: forkGatedElectraTime, expected: math.U64(preFuluHysteresisQuotient)}, {name: "At Electra1 fork", timestamp: forkGatedElectra1Time, expected: math.U64(preFuluHysteresisQuotient)}, {name: "Just before Fulu", timestamp: forkGatedFuluTime - 1, expected: math.U64(preFuluHysteresisQuotient)}, {name: "At Fulu fork", timestamp: forkGatedFuluTime, expected: math.U64(fuluHysteresisQuotient)}, {name: "Just after Fulu", timestamp: forkGatedFuluTime + 1, expected: math.U64(fuluHysteresisQuotient)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := s.HysteresisQuotient(math.U64(tt.timestamp)) require.Equal(t, tt.expected, got) }) } } // TestHysteresisUpwardMultiplier_ForkBoundary asserts HysteresisUpwardMultiplier // returns the pre-Fulu value before FuluForkTime and the Fulu value at or // after FuluForkTime. func TestHysteresisUpwardMultiplier_ForkBoundary(t *testing.T) { t.Parallel() s := buildForkGatedSpec(t) tests := []struct { name string timestamp uint64 expected math.U64 }{ {name: "At genesis (Deneb)", timestamp: forkGatedGenesisTime, expected: math.U64(preFuluHysteresisUpwardMultiplier)}, {name: "At Deneb1 fork", timestamp: forkGatedDeneb1Time, expected: math.U64(preFuluHysteresisUpwardMultiplier)}, {name: "At Electra fork", timestamp: forkGatedElectraTime, expected: math.U64(preFuluHysteresisUpwardMultiplier)}, {name: "At Electra1 fork", timestamp: forkGatedElectra1Time, expected: math.U64(preFuluHysteresisUpwardMultiplier)}, {name: "Just before Fulu", timestamp: forkGatedFuluTime - 1, expected: math.U64(preFuluHysteresisUpwardMultiplier)}, {name: "At Fulu fork", timestamp: forkGatedFuluTime, expected: math.U64(fuluHysteresisUpwardMultiplierFulu)}, {name: "Just after Fulu", timestamp: forkGatedFuluTime + 1, expected: math.U64(fuluHysteresisUpwardMultiplierFulu)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := s.HysteresisUpwardMultiplier(math.U64(tt.timestamp)) require.Equal(t, tt.expected, got) }) } } // TestEVMInflationAddress_ForkBoundary asserts EVMInflationAddress returns the // correct address for each of the three fork regions: genesis (Deneb), // Deneb1/Electra/Electra1, and Fulu. func TestEVMInflationAddress_ForkBoundary(t *testing.T) { t.Parallel() s := buildForkGatedSpec(t) tests := []struct { name string timestamp uint64 expected common.ExecutionAddress }{ {name: "At genesis (Deneb)", timestamp: forkGatedGenesisTime, expected: evmInflationAddrGenesis}, {name: "Between genesis and Deneb1", timestamp: forkGatedDeneb1Time - 1, expected: evmInflationAddrGenesis}, {name: "At Deneb1 fork", timestamp: forkGatedDeneb1Time, expected: evmInflationAddrDeneb1}, {name: "At Electra fork", timestamp: forkGatedElectraTime, expected: evmInflationAddrDeneb1}, {name: "At Electra1 fork", timestamp: forkGatedElectra1Time, expected: evmInflationAddrDeneb1}, {name: "Just before Fulu", timestamp: forkGatedFuluTime - 1, expected: evmInflationAddrDeneb1}, {name: "At Fulu fork", timestamp: forkGatedFuluTime, expected: evmInflationAddrFulu}, {name: "Just after Fulu", timestamp: forkGatedFuluTime + 1, expected: evmInflationAddrFulu}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := s.EVMInflationAddress(math.U64(tt.timestamp)) require.Equal(t, tt.expected, got) }) } } // TestEVMInflationPerBlock_ForkBoundary asserts EVMInflationPerBlock returns // the correct amount for each of the three fork regions: genesis (Deneb), // Deneb1/Electra/Electra1, and Fulu. func TestEVMInflationPerBlock_ForkBoundary(t *testing.T) { t.Parallel() s := buildForkGatedSpec(t) tests := []struct { name string timestamp uint64 expected math.Gwei }{ {name: "At genesis (Deneb)", timestamp: forkGatedGenesisTime, expected: math.Gwei(evmInflationPerBlockGenesis)}, {name: "Between genesis and Deneb1", timestamp: forkGatedDeneb1Time - 1, expected: math.Gwei(evmInflationPerBlockGenesis)}, {name: "At Deneb1 fork", timestamp: forkGatedDeneb1Time, expected: math.Gwei(evmInflationPerBlockDeneb1)}, {name: "At Electra fork", timestamp: forkGatedElectraTime, expected: math.Gwei(evmInflationPerBlockDeneb1)}, {name: "At Electra1 fork", timestamp: forkGatedElectra1Time, expected: math.Gwei(evmInflationPerBlockDeneb1)}, {name: "Just before Fulu", timestamp: forkGatedFuluTime - 1, expected: math.Gwei(evmInflationPerBlockDeneb1)}, {name: "At Fulu fork", timestamp: forkGatedFuluTime, expected: math.Gwei(evmInflationPerBlockFulu)}, {name: "Just after Fulu", timestamp: forkGatedFuluTime + 1, expected: math.Gwei(evmInflationPerBlockFulu)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := s.EVMInflationPerBlock(math.U64(tt.timestamp)) require.Equal(t, tt.expected, got) }) } } func TestValidate_ForkOrder_Success(t *testing.T) { t.Parallel() data := baseSpecData() data.GenesisTime = 10 data.Deneb1ForkTime = 20 data.ElectraForkTime = 30 data.Electra1ForkTime = 40 data.FuluForkTime = 50 _, err := chain.NewSpec(data) require.NoError(t, err) } func TestValidate_ForkOrder_GenesisAfterDeneb(t *testing.T) { t.Parallel() data := baseSpecData() data.GenesisTime = 50 data.Deneb1ForkTime = 20 data.ElectraForkTime = 60 data.Electra1ForkTime = 70 data.FuluForkTime = 80 _, err := chain.NewSpec(data) require.Error(t, err) require.Contains(t, err.Error(), "timestamp at index 0 (50) > index 1 (20)") } func TestValidate_ForkOrder_DenebAfterElectra(t *testing.T) { t.Parallel() data := baseSpecData() data.GenesisTime = 10 data.Deneb1ForkTime = 80 data.ElectraForkTime = 40 data.Electra1ForkTime = 50 data.FuluForkTime = 90 _, err := chain.NewSpec(data) require.Error(t, err) require.Contains(t, err.Error(), "timestamp at index 1 (80) > index 2 (40)") } func TestValidate_ForkOrder_AllForksAtGenesis(t *testing.T) { t.Parallel() data := baseSpecData() data.GenesisTime = 0 data.Deneb1ForkTime = 0 data.ElectraForkTime = 0 data.Electra1ForkTime = 0 _, err := chain.NewSpec(data) require.NoError(t, err) } ================================================ FILE: cli/builder/builder.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "os" "cosmossdk.io/depinject" cmdlib "github.com/berachain/beacon-kit/cli/commands" servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/config" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/log/phuslu" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client" "github.com/spf13/cobra" ) // CLIBuilder is the builder for the commands.Root (root command). type CLIBuilder struct { name string description string // components is a list of component providers for depinject. components []any // suppliers is a list of suppliers for depinject. suppliers []any // nodeBuilderFunc is a function that builds the Node, // eventually called by the cosmos-sdk. // TODO: CLI should not know about the AppCreator nodeBuilderFunc servertypes.AppCreator chainSpecBuilderFunc servertypes.ChainSpecCreator } // New returns a new CLIBuilder with the given options. func New(opts ...Opt) *CLIBuilder { cb := &CLIBuilder{ suppliers: []any{ os.Stdout, // supply io.Writer for logger }, } for _, opt := range opts { opt(cb) } return cb } // Build builds the CLI commands. func (cb *CLIBuilder) Build() (*cmdlib.Root, error) { // allocate memory to hold the dependencies var ( clientCtx client.Context logger *phuslu.Logger ) // build dependencies for the root command if err := depinject.Inject( depinject.Configs( depinject.Supply(cb.suppliers...), depinject.Provide( cb.components..., ), ), &logger, &clientCtx, ); err != nil { return nil, err } // pass in deps to build the root command rootCmd := cmdlib.New( cb.name, cb.description, cb.defaultRunHandler(logger), clientCtx, ) // apply default root command setup cmdlib.DefaultRootCommandSetup( rootCmd, &cometbft.Service{}, cb.nodeBuilderFunc, cb.chainSpecBuilderFunc, ) return rootCmd, nil } // defaultRunHandler returns the default run handler for the CLIBuilder. func (cb *CLIBuilder) defaultRunHandler(logger *phuslu.Logger) func(cmd *cobra.Command) error { return func(cmd *cobra.Command) error { return cb.InterceptConfigsPreRunHandler( cmd, logger, DefaultAppConfigTemplate(), DefaultAppConfig(), cometbft.DefaultConfig(), ) } } func (cb *CLIBuilder) InterceptConfigsPreRunHandler( cmd *cobra.Command, logger *phuslu.Logger, customAppConfigTemplate string, customAppConfig interface{}, cmtConfig *cmtcfg.Config, ) error { return config.SetupCommand( cmd, customAppConfigTemplate, customAppConfig, cmtConfig, logger, ) } ================================================ FILE: cli/builder/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "github.com/berachain/beacon-kit/config" serverconfig "github.com/berachain/beacon-kit/config/config" "github.com/berachain/beacon-kit/config/template" ) // DefaultAppConfigTemplate returns the default configuration template for the // application. func DefaultAppConfigTemplate() string { return serverconfig.DefaultConfigTemplate + "\n" + template.TomlTemplate } // DefaultAppConfig returns the default configuration for the application. func DefaultAppConfig() any { // Define a struct for the custom app configuration. type CustomAppConfig struct { serverconfig.Config BeaconKit *config.Config `mapstructure:"beacon-kit"` } // Start with the default server configuration. cfg := serverconfig.DefaultConfig() cfg.Telemetry.Enabled = true // BeaconKit forces PebbleDB as the database backend. cfg.Pruning = "everything" // IAVL FastNode should ALWAYS be disabled on IAVL v1.x. cfg.IAVLDisableFastNode = true cfg.IAVLCacheSize = 2500 // Create the custom app configuration. customAppConfig := CustomAppConfig{ Config: *cfg, BeaconKit: config.DefaultConfig(), } return customAppConfig } ================================================ FILE: cli/builder/options.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" ) // Opt is a type that defines a function that modifies CLIBuilder. type Opt func(*CLIBuilder) // WithName sets the name for the CLIBuilder. func WithName(name string) Opt { return func(cb *CLIBuilder) { cb.name = name } } // WithDescription sets the description for the CLIBuilder. func WithDescription(description string) Opt { return func(cb *CLIBuilder) { cb.description = description } } // WithComponents sets the components for the CLIBuilder. func WithComponents(components []any) Opt { return func(cb *CLIBuilder) { cb.components = components } } // WithNodeBuilderFunc sets the cosmos app creator for the CLIBuilder. func WithNodeBuilderFunc(nodeBuilderFunc servertypes.AppCreator) Opt { return func(cb *CLIBuilder) { cb.nodeBuilderFunc = nodeBuilderFunc } } // WithChainSpecBuilderFunc sets the chainspec builder func WithChainSpecBuilderFunc(chainBuilderFunc servertypes.ChainSpecCreator) Opt { return func(cb *CLIBuilder) { cb.chainSpecBuilderFunc = chainBuilderFunc } } ================================================ FILE: cli/commands/deposit/commands.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/cosmos/cosmos-sdk/client" "github.com/spf13/cobra" ) // Commands creates a new command for deposit related actions. func Commands(chainSpecCreator servertypes.ChainSpecCreator, appCreator servertypes.AppCreator) *cobra.Command { cmd := &cobra.Command{ Use: "deposit", Short: "deposit subcommands", DisableFlagParsing: false, SuggestionsMinimumDistance: 2, //nolint:mnd // from sdk. RunE: client.ValidateCmd, } cmd.AddCommand( GetValidateDepositCmd(chainSpecCreator), GetCreateValidatorCmd(chainSpecCreator), GetValidatorKeysCmd(), GetDBCheckCmd(appCreator), ) return cmd } ================================================ FILE: cli/commands/deposit/commands_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit_test import ( "os" "path/filepath" "testing" "testing/quick" "github.com/berachain/beacon-kit/cli/commands/deposit" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" cmtcfg "github.com/cometbft/cometbft/config" cmtbls12381 "github.com/cometbft/cometbft/crypto/bls12381" "github.com/cometbft/cometbft/privval" "github.com/stretchr/testify/require" ) func TestCreateAndValidateCommandsDuality(t *testing.T) { t.Parallel() qc := &quick.Config{MaxCount: 100} cs, err := spec.DevnetChainSpec() require.NoError(t, err) // create a tmp folder where test stores bls keys and // overwrite relevant files across test cases tmpFolder := t.TempDir() cometCfg := cmtcfg.DefaultConfig() cometCfg.RootDir = tmpFolder keyFilePath := cometCfg.PrivValidatorKeyFile() stateFilePath := cometCfg.PrivValidatorStateFile() require.NoError(t, os.MkdirAll(filepath.Dir(keyFilePath), 0o777)) require.NoError(t, os.MkdirAll(filepath.Dir(stateFilePath), 0o777)) f := func( blsKeySecret [32]byte, genValRoot common.Root, creds types.WithdrawalCredentials, amount math.Gwei, ) bool { // generate random blsKey from the given secret var privKey *cmtbls12381.PrivKey privKey, err = cmtbls12381.GenPrivKeyFromSecret(blsKeySecret[:]) require.NoError(t, err) // update relevant files and create corresponding blsSigner pv := privval.NewFilePV(privKey, keyFilePath, stateFilePath) pv.Save() blsSigner := signer.NewBLSSigner(keyFilePath, stateFilePath) // create the deposit and check that it verifies var ( msg *types.DepositMessage sign crypto.BLSSignature ) msg, sign, err = deposit.CreateDepositMessage(cs, blsSigner, genValRoot, creds, amount) require.NoError(t, err) return deposit.ValidateDeposit(cs, msg.Pubkey, msg.Credentials, msg.Amount, genValRoot, sign) == nil } require.NoError(t, quick.Check(f, qc)) } ================================================ FILE: cli/commands/deposit/create.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "fmt" clitypes "github.com/berachain/beacon-kit/cli/commands/server/types" clicontext "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/cli/utils/parser" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-core/components" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/spf13/cobra" ) const ( createAddr0 = iota createAmt1 = iota createRoot2 = iota minArgsCreateDeposit = 2 maxArgsCreateDeposit = 3 overrideNodeKey = "override-node-key" valPrivateKey = "validator-private-key" useGenesisValidatorRoot = "genesis-validator-root" useGenesisValidatorRootShorthand = "g" defaultGenesisValidatorRoot = "" ) // GetCreateValidatorCmd returns a command to create a validator deposit. // //nolint:lll // Reads better if long description is one line. func GetCreateValidatorCmd( chainSpecCreator clitypes.ChainSpecCreator, ) *cobra.Command { cmd := &cobra.Command{ Use: "create-validator [withdrawal-address] [amount] ?[beacond/genesis.json]", Short: "Creates a validator deposit message", Long: `Creates a validator deposit message with the necessary credentials. The arguments are expected in the order of withdrawal address, deposit amount, and optionally the beacond genesis file. If the genesis validator root flag is NOT set, the beacond genesis file MUST be provided as the last argument. If the override flag is set to true, a private key must be provided to sign the message.`, Args: cobra.RangeArgs(minArgsCreateDeposit, maxArgsCreateDeposit), RunE: createValidatorCmd(chainSpecCreator), } cmd.Flags().BoolP( overrideNodeKey, "o", false, // no override by default "override the node private key", ) cmd.Flags().String( valPrivateKey, "", // no default private key "validator private key. This is required if the override-node-key flag is set.", ) cmd.Flags().StringP( useGenesisValidatorRoot, useGenesisValidatorRootShorthand, defaultGenesisValidatorRoot, "Use the provided genesis validator root. If this is not set, the beacond genesis file must be provided manually as the last argument.", ) return cmd } // createValidatorCmd returns a command that builds a create validator request. func createValidatorCmd( chainSpecCreator clitypes.ChainSpecCreator, ) func(*cobra.Command, []string) error { return func(cmd *cobra.Command, args []string) error { appOpts := clicontext.GetViperFromCmd(cmd) chainSpec, err := chainSpecCreator(appOpts) if err != nil { return err } // Get the BLS signer. blsSigner, err := getBLSSigner(cmd) if err != nil { return err } withdrawalAddressStr := args[createAddr0] withdrawalAddress, err := common.NewExecutionAddressFromHex(withdrawalAddressStr) if err != nil { return err } credentials := types.NewCredentialsFromExecutionAddress(withdrawalAddress) amountStr := args[createAmt1] amount, err := parser.ConvertAmount(amountStr) if err != nil { return err } genesisValidatorRoot, err := getGenesisValidatorRoot( cmd, chainSpec, args, maxArgsCreateDeposit, ) if err != nil { return err } depositMsg, signature, err := CreateDepositMessage(chainSpec, blsSigner, genesisValidatorRoot, credentials, amount) if err != nil { return err } cmd.Println("✅ Deposit message created successfully!") cmd.Println("Note: This is NOT a transaction receipt; use these values to create a deposit contract transaction.") cmd.Printf("\npubkey: %s\n", depositMsg.Pubkey) cmd.Printf("credentials: %s\n", depositMsg.Credentials) cmd.Printf("amount: %s\n", depositMsg.Amount.Base10()) cmd.Printf("signature: %s\n", signature.String()) return nil } } func CreateDepositMessage( cs ChainSpec, blsSigner crypto.BLSSigner, genValRoot common.Root, creds types.WithdrawalCredentials, amount math.Gwei, ) ( *types.DepositMessage, crypto.BLSSignature, error, ) { // Create and sign the deposit message. All deposits are signed with the genesis version. depositMsg, signature, err := types.CreateAndSignDepositMessage( types.NewForkData(cs.GenesisForkVersion(), genValRoot), cs.DomainTypeDeposit(), blsSigner, creds, amount, ) if err != nil { return nil, crypto.BLSSignature{}, fmt.Errorf("failed CreateAndSignDepositMessage: %w", err) } return depositMsg, signature, ValidateDeposit( cs, depositMsg.Pubkey, depositMsg.Credentials, depositMsg.Amount, genValRoot, signature, ) } // getBLSSigner returns a BLS signer based on the override commands key flag. func getBLSSigner( cmd *cobra.Command, ) (crypto.BLSSigner, error) { var legacyKey components.LegacyKey overrideFlag, err := cmd.Flags().GetBool(overrideNodeKey) if err != nil { return nil, err } // Build the BLS signer. if overrideFlag { var validatorPrivKey string validatorPrivKey, err = cmd.Flags().GetString(valPrivateKey) if err != nil { return nil, err } if validatorPrivKey == "" { return nil, ErrValidatorPrivateKeyRequired } legacyKey, err = signer.LegacyKeyFromString(validatorPrivKey) if err != nil { return nil, err } } return components.ProvideBlsSigner( components.BlsSignerInput{ AppOpts: clicontext.GetViperFromCmd(cmd), PrivKey: legacyKey, }, ) } ================================================ FILE: cli/commands/deposit/db_check.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" clicontext "github.com/berachain/beacon-kit/cli/context" servercmtlog "github.com/berachain/beacon-kit/consensus/cometbft/service/log" "github.com/berachain/beacon-kit/state-transition/core" "github.com/berachain/beacon-kit/storage/db" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" ) // GetDBCheckCmd returns a command for checking that the deposit store // is in sync with the beacon state. func GetDBCheckCmd(appCreator servertypes.AppCreator) *cobra.Command { cmd := &cobra.Command{ Use: "db-check", Short: `Checks if the deposit store is in sync with the beacon state. Fails if either of the beacon or deposit DBs are not available.`, RunE: func(cmd *cobra.Command, _ []string) error { // Create the application from home directory configs and data. v := clicontext.GetViperFromCmd(cmd) logger := clicontext.GetLoggerFromCmd(cmd) cfg := clicontext.GetConfigFromCmd(cmd) db, err := db.OpenDB(cfg.RootDir, dbm.PebbleDBBackend) if err != nil { return err } app := appCreator(logger, db, nil, cfg, v) // Setup the state to check. ctx := sdk.NewContext( app.CommitMultiStore().CacheMultiStore(), false, servercmtlog.WrapSDKLogger(logger), ).WithContext(cmd.Context()) beaconState := app.StorageBackend().StateFromContext(ctx) depositStore := app.StorageBackend().DepositStore() // Verify that the deposit store is in sync with the Beacon state. eth1Data, err := beaconState.GetEth1Data() if err != nil { return err } if err = core.ValidateNonGenesisDeposits( ctx, beaconState, depositStore, // maxDepositsPerBlock: 0 // In this snapshotted state, we will check up to the existing deposits and not any more. 0, // blkDeposits: nil // There are no new block deposits as we are checking at this snapshotted state. nil, // blkDepositRoot: eth1Data.DepositRoot // We will compare against the beacon state's deposit root at this snapshotted state. eth1Data.DepositRoot, ); err != nil { return err } logger.Info("✅ Deposit store is in sync with the Beacon state!") return nil }, } return cmd } ================================================ FILE: cli/commands/deposit/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import "errors" var ( // ErrValidatorPrivateKeyRequired is returned when the validator private key // is required but not provided. ErrValidatorPrivateKeyRequired = errors.New( "validator private key required", ) // ErrPrivateKeyRequired is returned when the broadcast flag is set but a // private key is not provided. ErrPrivateKeyRequired = errors.New( "private key required", ) // ErrDepositReceiptEmpty is returned when the deposit receipt is nil. ErrDepositReceiptEmpty = errors.New( "deposit receipt is nil") // ErrPrivateKeyEmpty is returned when the private key is empty. ErrPrivateKeyEmpty = errors.New( "private key is empty") ) ================================================ FILE: cli/commands/deposit/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "github.com/berachain/beacon-kit/cli/utils/genesis" "github.com/berachain/beacon-kit/primitives/common" ) type ChainSpec interface { DomainTypeDeposit() common.DomainType GenesisForkVersion() common.Version genesis.ChainSpec } ================================================ FILE: cli/commands/deposit/keys.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "encoding/base64" "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-core/components" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/cometbft/cometbft/crypto/bls12381" "github.com/spf13/cobra" ) // GetValidatorKeysCmd returns a command that returns the validator public key in different formats // for the given private key files. // //nolint:lll // reads better if long description is one line. func GetValidatorKeysCmd() *cobra.Command { cmd := &cobra.Command{ Use: "validator-keys", Short: "Outputs the validator public key in different formats.", Long: `Outputs the validator public key in formats of Comet address, Comet pubkey, and Eth/Beacon pubkey. Uses the private key file specified as the value of "priv_validator_key_file" in the config.toml file in the beacond HOMEDIR.`, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) error { // Get the BLS signer. blsSignerI, err := components.ProvideBlsSigner( components.BlsSignerInput{ AppOpts: context.GetViperFromCmd(cmd), }, ) if err != nil { return errors.Wrap(err, "failed to initialize BLS signer from validator files") } blsSigner, ok := blsSignerI.(*signer.BLSSigner) if !ok { return errors.New("failed to assert BLS signer type") } // Get the comet public key. cometKey, err := blsSigner.PrivValidator.GetPubKey() if err != nil { return errors.Wrap(err, "failed to get comet public key from bls signer") } // Get the comet BLS public key. blsKey, err := bls12381.NewPublicKeyFromBytes(cometKey.Bytes()) if err != nil { return errors.Wrap(err, "failed to create BLS key from bytes") } // Output the validator public key in different formats. cmd.Printf( "Comet Address:\n%s\n\n", cometKey.Address(), ) cmd.Printf( "Comet Pubkey (Uncompressed Base64):\n%s\n\n", base64.StdEncoding.EncodeToString(blsKey.Bytes()), ) cmd.Printf( "Eth/Beacon Pubkey (Compressed 48-byte Hex):\n%s\n", blsSigner.PublicKey().String(), ) return nil }, } return cmd } ================================================ FILE: cli/commands/deposit/utils.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "github.com/berachain/beacon-kit/cli/utils/genesis" "github.com/berachain/beacon-kit/cli/utils/parser" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/spf13/cobra" ) // Get the genesis validator root. If the genesis validator root flag is not set, the genesis // validator root is computed from the genesis file at the last argument (idx: maxArgs - 1). func getGenesisValidatorRoot( cmd *cobra.Command, chainSpec ChainSpec, args []string, maxArgs int, ) (common.Root, error) { var genesisValidatorRoot common.Root genesisValidatorRootStr, err := cmd.Flags().GetString(useGenesisValidatorRoot) if err != nil { return common.Root{}, err } if genesisValidatorRootStr != defaultGenesisValidatorRoot { genesisValidatorRoot, err = parser.ConvertGenesisValidatorRoot(genesisValidatorRootStr) } else { if len(args) != maxArgs { return common.Root{}, errors.New( "genesis validator root is required if not using the genesis file flag", ) } genesisValidatorRoot, err = genesis.ComputeValidatorsRootFromFile(args[maxArgs-1], chainSpec) } return genesisValidatorRoot, err } ================================================ FILE: cli/commands/deposit/validate.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( clitypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/cli/utils/parser" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/spf13/cobra" ) const ( validatePubKey0 = iota validateCreds1 = iota validateAmt2 = iota validateSign3 = iota minArgsValidateDeposit = 4 maxArgsValidateDeposit = 5 ) // GetValidateDepositCmd creates a new command for validating a deposit message. // //nolint:lll // Reads better if long description is one line. func GetValidateDepositCmd(chainSpecCreator clitypes.ChainSpecCreator) *cobra.Command { cmd := &cobra.Command{ Use: "validate [pubkey] [withdrawal-credentials] [amount] [signature] ?[beacond/genesis.json]", Short: "Validates a deposit message for creating a new validator", Long: `Validates a deposit message (public key, withdrawal credentials, deposit amount) for creating a new validator. The args taken are in the order of the public key, withdrawal credentials, deposit amount, signature, and optionally the beacond genesis file. If the genesis validator root flag is NOT set, the beacond genesis file MUST be provided as the last argument.`, Args: cobra.RangeArgs(minArgsValidateDeposit, maxArgsValidateDeposit), RunE: validateDepositMessage(chainSpecCreator), } cmd.Flags().StringP( useGenesisValidatorRoot, useGenesisValidatorRootShorthand, defaultGenesisValidatorRoot, "Use the provided genesis validator root. If this is not set, the beacond genesis file must be provided manually as the last argument.", ) return cmd } // validateDepositMessage validates a deposit message for creating a new validator. func validateDepositMessage(chainSpecCreator clitypes.ChainSpecCreator) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { v := context.GetViperFromCmd(cmd) chainSpec, err := chainSpecCreator(v) if err != nil { return err } pubKeyStr := args[validatePubKey0] pubkey, err := parser.ConvertPubkey(pubKeyStr) if err != nil { return err } credsStr := args[validateCreds1] credentials, err := parser.ConvertWithdrawalCredentials(credsStr) if err != nil { return err } amountStr := args[validateAmt2] amount, err := parser.ConvertAmount(amountStr) if err != nil { return err } sigStr := args[validateSign3] signature, err := parser.ConvertSignature(sigStr) if err != nil { return err } genesisValidatorRoot, err := getGenesisValidatorRoot( cmd, chainSpec, args, maxArgsValidateDeposit, ) if err != nil { return err } if err = ValidateDeposit( chainSpec, pubkey, credentials, amount, genesisValidatorRoot, signature, ); err != nil { return err } cmd.Println("✅ Deposit message is valid!") return nil } } func ValidateDeposit( cs ChainSpec, pubkey crypto.BLSPubkey, creds types.WithdrawalCredentials, amount math.Gwei, genValRoot common.Root, signature crypto.BLSSignature, ) error { depositMessage := types.DepositMessage{ Pubkey: pubkey, Credentials: creds, Amount: amount, } // All deposits are signed with the genesis version. return depositMessage.VerifyCreateValidator( types.NewForkData(cs.GenesisForkVersion(), genValRoot), signature, cs.DomainTypeDeposit(), signer.BLSSigner{}.VerifySignature, ) } ================================================ FILE: cli/commands/genesis/collect.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import ( "os" "path/filepath" "strings" "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/encoding/json" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/spf13/afero" "github.com/spf13/cobra" ) // CollectGenesisDepositsCmd - return the cobra command to // collect genesis transactions. func CollectGenesisDepositsCmd() *cobra.Command { cmd := &cobra.Command{ Use: "collect-premined-deposits", Short: "adds a validator to the genesis file", RunE: func(cmd *cobra.Command, _ []string) error { config := context.GetConfigFromCmd(cmd) return CollectGenesisDeposits(config) }, } return cmd } func CollectGenesisDeposits(config *cmtcfg.Config) error { appGenesis, err := genutiltypes.AppGenesisFromFile( config.GenesisFile(), ) if err != nil { return errors.Wrap(err, "failed to read genesis doc from file") } // create the app state appGenesisState, err := genutiltypes.GenesisStateFromAppGenesis(appGenesis) if err != nil { return err } // Ensure the map is initialized before it is indexed below. If the // underlying function returned a nil map with a nil error (which is // permissible in Go), we defensively allocate an empty map to avoid // potential nil dereference panics that static analysis (nilaway) // rightfully complains about. if appGenesisState == nil { appGenesisState = make(map[string]json.RawMessage) } var deposits []*types.Deposit if deposits, err = CollectValidatorJSONFiles( filepath.Join(config.RootDir, "config", "premined-deposits"), appGenesis, ); err != nil { return errors.Wrap( err, "failed to collect validator json files", ) } genesisInfo := &types.Genesis{} if err = json.Unmarshal( appGenesisState["beacon"], genesisInfo, ); err != nil { return errors.Wrap(err, "failed to unmarshal beacon genesis") } for i, deposit := range deposits { deposit.Index = uint64(i) // #nosec G115 -- won't realistically overflow. genesisInfo.Deposits = append(genesisInfo.Deposits, deposit) } appGenesisState["beacon"], err = json.Marshal(genesisInfo) if err != nil { return errors.Wrap(err, "failed to marshal beacon genesis") } if appGenesis.AppState, err = json.MarshalIndent( appGenesisState, "", " ", ); err != nil { return err } return genutil.ExportGenesisFile(appGenesis, config.GenesisFile()) } // CollectValidatorJSONFiles collects JSON files from the specified directory // and unmarshals them into a list of Deposit objects. func CollectValidatorJSONFiles( genTxsDir string, genesis *genutiltypes.AppGenesis, ) ([]*types.Deposit, error) { // prepare a map of all balances in genesis state to then validate // against the validators addresses var appState map[string]json.RawMessage if err := json.Unmarshal(genesis.AppState, &appState); err != nil { return nil, err } // get the list of files in the genTxsDir fos, err := os.ReadDir(genTxsDir) if err != nil { return nil, err } // prepare the list of validators deposits := make([]*types.Deposit, 0) for _, fo := range fos { if fo.IsDir() { continue } if !strings.HasSuffix(fo.Name(), ".json") { continue } var bz []byte bz, err = afero.ReadFile( afero.NewOsFs(), filepath.Join(genTxsDir, fo.Name()), ) if err != nil { return nil, err } val := &types.Deposit{} if err = json.Unmarshal(bz, val); err != nil { return nil, err } deposits = append(deposits, val) } return deposits, nil } ================================================ FILE: cli/commands/genesis/deposit.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import ( "fmt" "os" "path/filepath" servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/cli/utils/parser" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-core/components" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/berachain/beacon-kit/primitives/math" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/spf13/afero" "github.com/spf13/cobra" ) // AddGenesisDepositCmd - returns the cobra command to // add a premined deposit to the genesis file. // //nolint:lll // reads better if long description is one line. func AddGenesisDepositCmd(chainSpecCreator servertypes.ChainSpecCreator) *cobra.Command { cmd := &cobra.Command{ Use: "add-premined-deposit", Short: "adds a validator to the genesis file", Long: `Adds a validator to the genesis file with the necessary credentials. The arguments are expected in the order of the deposit amount and withdrawal address.`, Args: cobra.ExactArgs(2), //nolint:mnd // The number of arguments. RunE: func(cmd *cobra.Command, args []string) error { // Get the deposit amount. depositAmount, err := parser.ConvertAmount(args[0]) if err != nil { return err } // Get the withdrawal address. withdrawalAddress, err := common.NewExecutionAddressFromHex(args[1]) if err != nil { return err } cometConfig := context.GetConfigFromCmd(cmd) appOpts := context.GetViperFromCmd(cmd) outputDocument, _ := cmd.Flags().GetString(flags.FlagOutputDocument) // Get the BLS signer. blsSigner, err := components.ProvideBlsSigner( components.BlsSignerInput{ AppOpts: appOpts, }, ) if err != nil { return err } chainSpec, err := chainSpecCreator(appOpts) if err != nil { return err } return AddGenesisDeposit(chainSpec, cometConfig, blsSigner, depositAmount, withdrawalAddress, outputDocument) }, } return cmd } // AddGenesisDeposit is the modularized version of AddGenesisDepositCmd that can be properly tested from within the runtime. func AddGenesisDeposit( cs ChainSpec, cometConfig *cmtcfg.Config, blsSigner crypto.BLSSigner, depositAmount math.Gwei, withdrawalAddress common.ExecutionAddress, outputDocument string, ) error { _, valPubKey, err := genutil.InitializeNodeValidatorFiles( cometConfig, crypto.CometBLSType, ) if err != nil { return errors.Wrap( err, "failed to initialize commands validator files", ) } if valPubKey == nil { // addresses nilaway return errors.New("failed to initialize commands validator files") } genesisVersion := cs.GenesisForkVersion() depositMsg, signature, err := types.CreateAndSignDepositMessage( types.NewForkData(genesisVersion, common.Root{}), cs.DomainTypeDeposit(), blsSigner, types.NewCredentialsFromExecutionAddress(withdrawalAddress), depositAmount, ) if err != nil { return err } // Verify the deposit message. if err = depositMsg.VerifyCreateValidator( types.NewForkData(genesisVersion, common.Root{}), signature, cs.DomainTypeDeposit(), signer.BLSSigner{}.VerifySignature, ); err != nil { return err } deposit := types.Deposit{ Pubkey: depositMsg.Pubkey, Amount: depositMsg.Amount, Signature: signature, Credentials: depositMsg.Credentials, } if outputDocument == "" { outputDocument, err = makeOutputFilepath(cometConfig.RootDir, crypto.BLSPubkey(valPubKey.Bytes()).String()) if err != nil { return errors.Wrap(err, "failed to create output file path") } } if err = writeDepositToFile(outputDocument, &deposit); err != nil { return errors.Wrap(err, "failed to write signed gen tx") } return nil } func makeOutputFilepath(rootDir, pubkey string) (string, error) { writePath := filepath.Join(rootDir, "config", "premined-deposits") if err := afero.NewOsFs().MkdirAll(writePath, 0o700); err != nil { //nolint:mnd // dir permissions. return "", errors.Wrapf( errors.New("could not create directory"), "%q: %w", writePath, err, ) } return filepath.Join( writePath, fmt.Sprintf("premined-deposit-%v.json", pubkey), ), nil } func writeDepositToFile( outputDocument string, depositMessage *types.Deposit, ) error { //#nosec:G302,G304 // Ignore errors on this line. outputFile, err := afero.NewOsFs().OpenFile( outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644, //nolint:mnd // file permissions. ) if err != nil { return err } //#nosec:G307 // Ignore errors on this line. defer outputFile.Close() bz, err := json.Marshal(depositMessage) if err != nil { return err } _, err = fmt.Fprintf(outputFile, "%s\n", bz) return err } ================================================ FILE: cli/commands/genesis/deposit_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis_test import ( "path" "testing" "github.com/berachain/beacon-kit/cli/commands/genesis" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/crypto/bls12381" "github.com/cometbft/cometbft/types" "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/require" ) func TestGenesisDeposit(t *testing.T) { t.Parallel() homeDir := t.TempDir() t.Log("Home folder:", homeDir) chainSpec, err := spec.MainnetChainSpec() require.NoError(t, err) cometConfig := cmtcfg.DefaultConfig() cometConfig.SetRoot(homeDir) // Forces Comet to Create it cometConfig.NodeKey = "nodekey.json" depositAmount := math.Gwei(250_000 * params.GWei) withdrawalAdress, err := common.NewExecutionAddressFromHex("0x981114102592310C347E61368342DDA67017bf84") require.NoError(t, err) outputDocument := "" blsSigner := signer.BLSSigner{PrivValidator: types.NewMockPVWithKeyType(bls12381.KeyType)} err = genesis.AddGenesisDeposit(chainSpec, cometConfig, blsSigner, depositAmount, withdrawalAdress, outputDocument) require.NoError(t, err) require.FileExists(t, path.Join(homeDir, "nodekey.json")) require.FileExists(t, path.Join(homeDir, "data", "priv_validator_state.json")) require.FileExists(t, path.Join(homeDir, "config", "priv_validator_key.json")) require.DirExists(t, path.Join(homeDir, "config", "premined-deposits")) // TODO: Extend tests to assert on the contents of the files } ================================================ FILE: cli/commands/genesis/genesis.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import ( servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/cosmos/cosmos-sdk/client" "github.com/spf13/cobra" ) // Commands builds the genesis-related command. Users may // provide application specific commands as a parameter. func Commands( csc servertypes.ChainSpecCreator, cmds ...*cobra.Command, ) *cobra.Command { cmd := &cobra.Command{ Use: "genesis", Short: "Application's genesis-related subcommands", DisableFlagParsing: false, SuggestionsMinimumDistance: 2, //nolint:mnd // from sdk. RunE: client.ValidateCmd, } // Adding subcommands for genesis-related operations. cmd.AddCommand( AddGenesisDepositCmd(csc), CollectGenesisDepositsCmd(), AddExecutionPayloadCmd(csc), GetGenesisValidatorRootCmd(csc), SetDepositStorageCmd(csc), ) // Add additional commands for _, subCmd := range cmds { cmd.AddCommand(subCmd) } return cmd } ================================================ FILE: cli/commands/genesis/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import ( "github.com/berachain/beacon-kit/cli/utils/genesis" "github.com/berachain/beacon-kit/primitives/common" ) type ChainSpec interface { genesis.ChainSpec GenesisForkVersion() common.Version DomainTypeDeposit() common.DomainType MaxWithdrawalsPerPayload() uint64 DepositContractAddress() common.ExecutionAddress } ================================================ FILE: cli/commands/genesis/payload.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import ( "fmt" "unsafe" servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/errors" bkitgethtypes "github.com/berachain/beacon-kit/gethlib/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/x/genutil" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" gethengine "github.com/ethereum/go-ethereum/beacon/engine" "github.com/spf13/afero" "github.com/spf13/cobra" ) func AddExecutionPayloadCmd(chainSpecCreator servertypes.ChainSpecCreator) *cobra.Command { cmd := &cobra.Command{ Use: "execution-payload [eth/genesis/file.json]", Short: "adds the eth1 genesis execution payload to the genesis file", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { // Read the genesis file. elGenesisPath := args[0] config := context.GetConfigFromCmd(cmd) v := context.GetViperFromCmd(cmd) chainSpec, err := chainSpecCreator(v) if err != nil { return err } return AddExecutionPayload(chainSpec, elGenesisPath, config) }, } return cmd } func AddExecutionPayload(chainSpec ChainSpec, elGenesisPath string, config *cmtcfg.Config) error { genesisBz, err := afero.ReadFile(afero.NewOsFs(), elGenesisPath) if err != nil { return errors.Wrap(err, "failed to read eth1 genesis file") } // Unmarshal the genesis file. ethGenesis := &bkitgethtypes.Genesis{} if err = ethGenesis.UnmarshalJSON(genesisBz); err != nil { return errors.Wrap(err, "failed to unmarshal eth1 genesis") } genesisBlock := ethGenesis.ToBlock() // Create the execution payload. payload := bkitgethtypes.BlockToExecutableData( genesisBlock, nil, nil, nil, ).ExecutionPayload appGenesis, err := genutiltypes.AppGenesisFromFile(config.GenesisFile()) if err != nil { return errors.Wrap(err, "failed to read genesis doc from file") } // create the app state appGenesisState, err := genutiltypes.GenesisStateFromAppGenesis(appGenesis) if err != nil { return err } // Defensive: ensure the map returned is non-nil before indexing. This // prevents potential nil dereference panics flagged by static analysis // tools such as nilaway. if appGenesisState == nil { appGenesisState = make(map[string]json.RawMessage) } genesisInfo := &types.Genesis{} if err = json.Unmarshal( appGenesisState["beacon"], genesisInfo, ); err != nil { return errors.Wrap(err, "failed to unmarshal beacon state") } // Inject the execution payload. eph, err := executableDataToExecutionPayloadHeader( chainSpec.GenesisForkVersion(), payload, chainSpec.MaxWithdrawalsPerPayload(), ) if err != nil { return errors.Wrap(err, "failed to convert executable data to execution payload header") } if eph == nil { return errors.New("failed to get execution payload header") } genesisInfo.ExecutionPayloadHeader = eph appGenesisState["beacon"], err = json.Marshal(genesisInfo) if err != nil { return errors.Wrap(err, "failed to marshal beacon state") } if appGenesis.AppState, err = json.MarshalIndent( appGenesisState, "", " ", ); err != nil { return err } return genutil.ExportGenesisFile(appGenesis, config.GenesisFile()) } // Converts the eth executable data type to the beacon execution payload header // interface. func executableDataToExecutionPayloadHeader( forkVersion common.Version, data *gethengine.ExecutableData, // todo: re-enable when codec supports. _ uint64, ) (*types.ExecutionPayloadHeader, error) { eph := &types.ExecutionPayloadHeader{} // We do not support fork versions before Deneb and after Fulu. if version.IsAfter(forkVersion, version.Fulu()) || version.IsBefore(forkVersion, version.Deneb()) { return nil, types.ErrForkVersionNotSupported } withdrawals := make( engineprimitives.Withdrawals, len(data.Withdrawals), ) for i, withdrawal := range data.Withdrawals { // #nosec:G103 // primitives.Withdrawals is data.Withdrawals with // hard // types. withdrawals[i] = (*engineprimitives.Withdrawal)( unsafe.Pointer(withdrawal), ) } if len(data.ExtraData) > constants.ExtraDataLength { data.ExtraData = data.ExtraData[:constants.ExtraDataLength] } var blobGasUsed uint64 if data.BlobGasUsed != nil { blobGasUsed = *data.BlobGasUsed } var excessBlobGas uint64 if data.ExcessBlobGas != nil { excessBlobGas = *data.ExcessBlobGas } baseFeePerGas, err := math.NewU256FromBigInt(data.BaseFeePerGas) if err != nil { return nil, fmt.Errorf("failed baseFeePerGas conversion: %w", err) } eph.Versionable = types.NewVersionable(forkVersion) eph.ParentHash = common.ExecutionHash(data.ParentHash) eph.FeeRecipient = common.ExecutionAddress(data.FeeRecipient) eph.StateRoot = common.Bytes32(data.StateRoot) eph.ReceiptsRoot = common.Bytes32(data.ReceiptsRoot) eph.LogsBloom = [256]byte(data.LogsBloom) eph.Random = common.Bytes32(data.Random) eph.Number = math.U64(data.Number) eph.GasLimit = math.U64(data.GasLimit) eph.GasUsed = math.U64(data.GasUsed) eph.Timestamp = math.U64(data.Timestamp) eph.ExtraData = data.ExtraData eph.BaseFeePerGas = baseFeePerGas eph.BlockHash = common.ExecutionHash(data.BlockHash) eph.TransactionsRoot = engineprimitives.Transactions(data.Transactions).HashTreeRoot() eph.WithdrawalsRoot = withdrawals.HashTreeRoot() eph.BlobGasUsed = math.U64(blobGasUsed) eph.ExcessBlobGas = math.U64(excessBlobGas) return eph, nil } ================================================ FILE: cli/commands/genesis/root.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import ( "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/cli/utils/genesis" "github.com/spf13/cobra" ) // GetGenesisValidatorRootCmd returns a command that gets the genesis validator root from a given // beacond genesis file. func GetGenesisValidatorRootCmd(chainSpecCreator types.ChainSpecCreator) *cobra.Command { cmd := &cobra.Command{ Use: "validator-root [beacond/genesis.json]", Short: "gets and returns the genesis validator root", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { v := context.GetViperFromCmd(cmd) chainSpec, err := chainSpecCreator(v) if err != nil { return err } genesisValidatorsRoot, err := genesis.ComputeValidatorsRootFromFile(args[0], chainSpec) if err != nil { return err } cmd.Printf("%s\n", genesisValidatorsRoot) return nil }, } return cmd } ================================================ FILE: cli/commands/genesis/storage.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import ( "bytes" "encoding/json" "math/big" "path/filepath" "github.com/berachain/beacon-kit/cli/commands/genesis/types" clitypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/context" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" cmtcfg "github.com/cometbft/cometbft/config" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" gethcommon "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/spf13/afero" "github.com/spf13/cobra" ) // SetDepositStorageCmd sets deposit contract storage in genesis alloc file. // //nolint:lll // reads better if long description is one line func SetDepositStorageCmd(chainSpecCreator clitypes.ChainSpecCreator) *cobra.Command { cmd := &cobra.Command{ Use: "set-deposit-storage [eth/genesis/file.json]", Short: "sets deposit contract storage in eth genesis", Long: `Updates the deposit contract storage in the passed in eth genesis file. Creates a new EL genesis file with the changes in the BEACOND_HOME directory.`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { // Read the EL genesis file. elGenesisFilePath := args[0] // Get the deposits from the beacon chain genesis appstate. config := context.GetConfigFromCmd(cmd) appOpts := context.GetViperFromCmd(cmd) chainSpec, err := chainSpecCreator(appOpts) if err != nil { return err } return SetDepositStorage(chainSpec, config, elGenesisFilePath) }, } return cmd } func SetDepositStorage( chainSpec ChainSpec, config *cmtcfg.Config, elGenesisFilePath string, ) error { elGenesisBz, err := afero.ReadFile(afero.NewOsFs(), elGenesisFilePath) if err != nil { return errors.Wrap(err, "failed to read eth1 genesis file") } clGenesis, err := genutiltypes.AppGenesisFromFile( config.GenesisFile(), ) if err != nil { return errors.Wrap(err, "failed to read genesis doc from file") } genesisState, err := genutiltypes.GenesisStateFromAppGenesis( clGenesis, ) if err != nil { return errors.Wrap(err, "failed to read appstate from genesis") } beaconStateRaw := genesisState["beacon"] var beaconState struct { Deposits ctypes.Deposits `json:"deposits"` } if err = json.Unmarshal(beaconStateRaw, &beaconState); err != nil { return errors.Wrap(err, "failed to unmarshal beacon state") } deposits := beaconState.Deposits // Set the storage of the deposit contract with deposits count and root. count := big.NewInt(int64(len(deposits))) root := deposits.HashTreeRoot() // Unmarshal the genesis file. elGenesis := &types.DefaultEthGenesisJSON{} allocsKey := types.DefaultAllocsKey if err = json.Unmarshal(elGenesisBz, elGenesis); err != nil { return errors.Wrap(err, "failed to unmarshal eth1 genesis") } depositAddr := gethcommon.Address(chainSpec.DepositContractAddress()) allocs := writeDepositStorage(elGenesis, depositAddr, count, root) // Get just the filename from the path filename := filepath.Base(elGenesisFilePath) outputPath := filepath.Join(config.RootDir, filename) // Write to file. err = writeGenesisAllocToFile(depositAddr, outputPath, elGenesisFilePath, allocs, allocsKey) if err != nil { return errors.Wrap(err, "failed to write genesis alloc to file") } return nil } func writeDepositStorage( elGenesis types.EthGenesis, depositAddr gethcommon.Address, depositsCount *big.Int, depositsRoot common.Root, ) gethtypes.GenesisAlloc { slot0 := gethcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000") slot1 := gethcommon.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001") allocs := elGenesis.Alloc() if entry, ok := allocs[depositAddr]; ok { if entry.Storage == nil { entry.Storage = make(map[gethcommon.Hash]gethcommon.Hash) } entry.Storage[slot0] = gethcommon.BigToHash(depositsCount) entry.Storage[slot1] = gethcommon.BytesToHash(depositsRoot[:]) allocs[depositAddr] = entry } return allocs } func writeGenesisAllocToFile( depositAddr gethcommon.Address, outputDocument string, inputDocument string, genesisAlloc gethtypes.GenesisAlloc, allocsKey string, ) error { // Read existing el genesis file existingBz, err := afero.ReadFile(afero.NewOsFs(), inputDocument) if err != nil { return err } // Unmarshal existing genesis using json.Number to preserve integer precision var existingGenesis map[string]interface{} decoder := json.NewDecoder(bytes.NewReader(existingBz)) decoder.UseNumber() if err = decoder.Decode(&existingGenesis); err != nil { return err } // Get existing alloc. alloc, ok := existingGenesis[allocsKey].(map[string]interface{}) if !ok { return errors.New("invalid alloc format in genesis file") } // Update only the deposit contract entry if account, exists := genesisAlloc[depositAddr]; exists { alloc[depositAddr.Hex()] = account } // Marshal back to JSON bz, err := json.MarshalIndent(existingGenesis, "", " ") if err != nil { return err } // Write back to file return afero.WriteFile( afero.NewOsFs(), outputDocument, bz, 0o644, //nolint:mnd // file permissions. ) } ================================================ FILE: cli/commands/genesis/storage_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis_test import ( "context" "os" "path/filepath" "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/cli/commands/genesis" servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/cosmos/cosmos-sdk/client" "github.com/ethereum/go-ethereum/common" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) //nolint:paralleltest // t.TempDir() do not allow parallelism func TestSetDepositStorageCmd(t *testing.T) { t.Run("command should be available and have correct use", func(t *testing.T) { chainSpec, err := spec.DevnetChainSpec() require.NoError(t, err) cmd := genesis.SetDepositStorageCmd(func(_ servertypes.AppOptions) (chain.Spec, error) { return chainSpec, nil }) require.Equal(t, "set-deposit-storage [eth/genesis/file.json]", cmd.Use) }) t.Run("should set deposit storage correctly", func(t *testing.T) { // Create a temporary directory for test files tmpDir := t.TempDir() // Setup test files mockGenesisPath := setupMockGenesis(t, tmpDir) _ = setupMockCLGenesis(t, tmpDir) // Setup client context clientCtx := client.Context{ HomeDir: tmpDir, } ctx := context.WithValue(t.Context(), client.ClientContextKey, &clientCtx) // Create and execute the command chainSpec, err := spec.DevnetChainSpec() require.NoError(t, err) cmd := genesis.SetDepositStorageCmd(func(_ servertypes.AppOptions) (chain.Spec, error) { return chainSpec, nil }) cmd.SetContext(ctx) // Change working directory to tmpDir for the test currentDir, err := os.Getwd() require.NoError(t, err) t.Chdir(tmpDir) defer func() { t.Chdir(currentDir) }() cmd.SetArgs([]string{mockGenesisPath}) require.NoError(t, cmd.Execute()) verifyStorageOutput(t, mockGenesisPath) }) } func setupMockGenesis(t *testing.T, tmpDir string) string { t.Helper() chainSpec, err := spec.DevnetChainSpec() require.NoError(t, err) depositAddr := common.Address(chainSpec.DepositContractAddress()) mockGenesisPath := filepath.Join(tmpDir, "genesis.json") mockGenesis := map[string]interface{}{ "alloc": map[string]interface{}{ depositAddr.Hex(): map[string]interface{}{ "balance": "0x0", "code": "0x1234", }, }, } genesisBz, err := json.MarshalIndent(mockGenesis, "", " ") require.NoError(t, err) err = afero.WriteFile(afero.NewOsFs(), mockGenesisPath, genesisBz, 0o644) require.NoError(t, err) return mockGenesisPath } func setupMockCLGenesis(t *testing.T, tmpDir string) string { t.Helper() // Create config directory in the root of tmpDir configDir := filepath.Join(tmpDir, "config") require.NoError(t, os.MkdirAll(configDir, 0o755)) mockCLGenesisPath := filepath.Join(configDir, "genesis.json") mockCLGenesis := map[string]interface{}{ "app_state": map[string]interface{}{ "beacon": map[string]interface{}{ "deposits": []interface{}{ map[string]interface{}{ "data": map[string]interface{}{ "amount": "32000000000", "pubkey": "0x1234", "withdrawal_address": "0x5678", "signature": "0x9abc", "deposit_message_root": "0xdef0", }, }, }, }, }, } clGenesisBz, err := json.MarshalIndent(mockCLGenesis, "", " ") require.NoError(t, err) err = afero.WriteFile(afero.NewOsFs(), mockCLGenesisPath, clGenesisBz, 0o644) require.NoError(t, err) return mockCLGenesisPath } func verifyStorageOutput(t *testing.T, genesisPath string) { t.Helper() chainSpec, err := spec.DevnetChainSpec() require.NoError(t, err) depositAddr := common.Address(chainSpec.DepositContractAddress()) // Verify the output genesis file outputBz, err := afero.ReadFile(afero.NewOsFs(), genesisPath) require.NoError(t, err) var output map[string]interface{} err = json.Unmarshal(outputBz, &output) require.NoError(t, err) // Check that the deposit contract storage was set correctly alloc, ok := output["alloc"].(map[string]interface{}) require.True(t, ok) depositContract, ok := alloc[depositAddr.Hex()].(map[string]interface{}) require.True(t, ok) storage, ok := depositContract["storage"].(map[string]interface{}) require.True(t, ok) // Verify storage slots slot0 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000") slot1 := common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001") require.NotEmpty(t, storage[slot0.Hex()]) // Deposit count require.NotEmpty(t, storage[slot1.Hex()]) // Deposit root } ================================================ FILE: cli/commands/genesis/types/constants.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types const ( // DefaultAllocsKey is the key for the allocs in the default genesis file. DefaultAllocsKey = "alloc" ) ================================================ FILE: cli/commands/genesis/types/json.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import gethtypes "github.com/ethereum/go-ethereum/core/types" type EthGenesis interface { Alloc() gethtypes.GenesisAlloc } type DefaultEthGenesisJSON struct { Allocs gethtypes.GenesisAlloc `json:"alloc"` } func (g *DefaultEthGenesisJSON) Alloc() gethtypes.GenesisAlloc { return g.Allocs } ================================================ FILE: cli/commands/initialize/initialize.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // implementation taken from github.com/cosmos/cosmos-sdk/blob/main/x/genutil/client/cli/init.go // and modified to circumvent using default cometbft config which sets the timeout_commit to 0 package initialize import ( "bufio" "fmt" "io" "os" "path/filepath" errorsmod "cosmossdk.io/errors" "cosmossdk.io/math/unsafe" "github.com/berachain/beacon-kit/chain" clitypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/context" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/json" cfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/input" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/cosmos/go-bip39" "github.com/spf13/cobra" ) const ( // FlagOverwrite defines a flag to overwrite an existing genesis JSON file. FlagOverwrite = "overwrite" // FlagSeed defines a flag to initialize the private validator key from a specific seed. FlagRecover = "recover" // FlagDefaultBondDenom defines the default denom to use in the genesis file. FlagDefaultBondDenom = "default-denom" // In BeaconKit we use crypto.CometBLSType only so we don't allow to specify // any consensus key. consensusKeyAlgo = crypto.CometBLSType ) type printInfo struct { Moniker string `json:"moniker" yaml:"moniker"` ChainID string `json:"chain_id" yaml:"chain_id"` NodeID string `json:"node_id" yaml:"node_id"` GenTxsDir string `json:"gentxs_dir" yaml:"gentxs_dir"` AppMessage json.RawMessage `json:"app_message" yaml:"app_message"` } func newPrintInfo(moniker, chainID, nodeID, genTxsDir string, appMessage json.RawMessage) printInfo { return printInfo{ Moniker: moniker, ChainID: chainID, NodeID: nodeID, GenTxsDir: genTxsDir, AppMessage: appMessage, } } func displayInfo(dst io.Writer, info printInfo) error { out, err := json.MarshalIndent(info, "", " ") if err != nil { return err } _, err = fmt.Fprintf(dst, "%s\n", out) //#nosec:G705 // CLI output of JSON-marshaled config, not web content. return err } //nolint:funlen,gocognit,mnd // based on cosmossdk implementation func InitCmd(creator clitypes.ChainSpecCreator, mm interface { DefaultGenesis(chain.Spec) map[string]json.RawMessage ValidateGenesis(genesisData map[string]json.RawMessage) error }) *cobra.Command { cmd := &cobra.Command{ Use: "init ", Short: "Initialize private validator, p2p, genesis, and application configuration files", Long: `Initialize validators's and node's configuration files.`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx := client.GetClientContextFromCmd(cmd) // it's very important here to use `GetConfigFromCmd` as redefined // in BeaconKit instead of cosmos sdk original implementation. Failure // to do so, would result in cosmos sdk default configs being picked // instead of BeaconKit ones config := context.GetConfigFromCmd(cmd) chainID, err := cmd.Flags().GetString(flags.FlagChainID) if err != nil { return errors.New("failed to parse FlagChainID") } switch { case chainID != "": case clientCtx.ChainID != "": chainID = clientCtx.ChainID default: chainID = fmt.Sprintf("test-chain-%v", unsafe.Str(6)) } if config.RootDir == "" { config.RootDir = clientCtx.HomeDir } // Get bip39 mnemonic var mnemonic string shouldRecover, err := cmd.Flags().GetBool(FlagRecover) if err != nil { return errors.New("failed to parse FlagRecover") } if shouldRecover { inBuf := bufio.NewReader(cmd.InOrStdin()) var value string value, err = input.GetString("Enter your bip39 mnemonic", inBuf) if err != nil { return err } mnemonic = value if !bip39.IsMnemonicValid(mnemonic) { return errors.New("invalid mnemonic") } } // Get initial height initHeight, err := cmd.Flags().GetInt64(flags.FlagInitHeight) if err != nil { return errors.New("failed to parse FlagInitHeight") } if initHeight < 1 { initHeight = 1 } nodeID, _, err := genutil.InitializeNodeValidatorFilesFromMnemonic(config, mnemonic, consensusKeyAlgo) if err != nil { return err } config.Moniker = args[0] genFile := config.GenesisFile() overwrite, err := cmd.Flags().GetBool(FlagOverwrite) if err != nil { return errors.New("failed to parse FlagOverwrite") } defaultDenom, err := cmd.Flags().GetString(FlagDefaultBondDenom) if err != nil { return errors.New("failed to parse FlagDefaultBondDenom") } // use os.Stat to check if the file exists _, err = os.Stat(genFile) if !overwrite && !os.IsNotExist(err) { return fmt.Errorf("genesis.json file already exists: %v", genFile) } // Overwrites the SDK default denom for side-effects if defaultDenom != "" { sdk.DefaultBondDenom = defaultDenom } chainSpec, err := creator(context.GetViperFromCmd(cmd)) if err != nil { return fmt.Errorf("failed to create chain spec: %w", err) } appGenState := mm.DefaultGenesis(chainSpec) appState, err := json.MarshalIndent(appGenState, "", " ") if err != nil { return errorsmod.Wrap(err, "Failed to marshal default genesis state") } appGenesis := &types.AppGenesis{} if _, err = os.Stat(genFile); err != nil { if !os.IsNotExist(err) { return err } } else { appGenesis, err = types.AppGenesisFromFile(genFile) if err != nil { return errorsmod.Wrap(err, "Failed to read genesis doc from file") } } appGenesis.AppName = version.AppName appGenesis.AppVersion = version.Version appGenesis.ChainID = chainID appGenesis.AppState = appState appGenesis.InitialHeight = initHeight appGenesis.Consensus = &types.ConsensusGenesis{ Validators: nil, Params: cometbft.DefaultConsensusParams(consensusKeyAlgo, chainSpec), } if err = genutil.ExportGenesisFile(appGenesis, genFile); err != nil { return errorsmod.Wrap(err, "Failed to export genesis file") } toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState) // Note: the config file was already creating before execution this command // by [SetupCommand], and it is being overwritten here. The only difference, // post default values cleanups, should be in the moniker, which is only setup // correctly here cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config) return displayInfo(cmd.ErrOrStderr(), toPrint) }, } cmd.Flags().BoolP(FlagOverwrite, "o", false, "overwrite the genesis.json file") cmd.Flags().Bool(FlagRecover, false, "provide seed phrase to recover existing key instead of creating") cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") cmd.Flags().String(FlagDefaultBondDenom, "", "genesis file default denomination, if left blank default value is 'stake'") cmd.Flags().Int64(flags.FlagInitHeight, 1, "specify the initial block height at genesis") return cmd } ================================================ FILE: cli/commands/jwt/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package jwt import "github.com/berachain/beacon-kit/errors" var ( // ErrNoClientCtx indicates that the client context was not found. ErrNoClientCtx = errors.New("client context not found") ) ================================================ FILE: cli/commands/jwt/jwt.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package jwt import ( "os" "path/filepath" "github.com/berachain/beacon-kit/node-core/components" "github.com/berachain/beacon-kit/primitives/net/jwt" "github.com/cosmos/cosmos-sdk/client" "github.com/spf13/afero" "github.com/spf13/cobra" ) const ( DefaultSecretFileName = "jwt.hex" FlagOutputPath = "output-path" FlagInputPath = "input-path" ConfigFolder = "config" secretDirPerms os.FileMode = 0o700 secretFilePerms os.FileMode = 0o600 ) // Commands creates a new command for managing JWT secrets. func Commands() *cobra.Command { cmd := &cobra.Command{ Use: "jwt", Short: "JWT subcommands", DisableFlagParsing: false, SuggestionsMinimumDistance: 2, //nolint:mnd // from sdk. RunE: client.ValidateCmd, } cmd.AddCommand( NewGenerateJWTCommand(), NewValidateJWTCommand(), ) return cmd } // NewGenerateJWTCommand creates a new command for generating a JWT secret. // //nolint:lll // reads better if long description is one line func NewGenerateJWTCommand() *cobra.Command { cmd := &cobra.Command{ Use: "generate", Short: "Generates a new JWT authentication secret", Long: `This command generates a new JWT authentication secret and writes it to a file. If no output file path is specified, it uses the default file name "jwt.hex" in the current directory.`, RunE: func(cmd *cobra.Command, _ []string) error { // Get the file path from the command flags. outputPath, err := getFilePath(cmd, FlagOutputPath) if err != nil { return err } return generateAuthSecretInFile(cmd, outputPath) }, } cmd.Flags().StringP( FlagOutputPath, "o", "", "Optional output file path for the JWT secret") return cmd } // NewValidateJWTCommand creates a new command for validating a JWT secret. // //nolint:lll // reads better if long description is one line func NewValidateJWTCommand() *cobra.Command { cmd := &cobra.Command{ Use: "validate", Short: "Validates a JWT secret conforms to Engine-RPC requirements", Long: `This command validates a JWT secret by checking if the JWT secret is formatted properly. If no output file path is specified, it uses the default file name "jwt.hex" in the current directory.`, RunE: func(cmd *cobra.Command, _ []string) error { // Get the file path from the command flags. inputPath, err := getFilePath(cmd, FlagInputPath) if err != nil { return err } return validateJWTSecret(cmd, inputPath) }, } cmd.Flags().StringP( FlagInputPath, "i", "", "Optional input file path for the JWT secret", ) return cmd } // getFilePath retrieves the file path for the JWT secret from the command flag. // If no path is specified, it returns the default secret file name. func getFilePath(cmd *cobra.Command, path string) (string, error) { specifiedFilePath, err := cmd.Flags().GetString(path) if err != nil { return "", err } if specifiedFilePath != "" { return specifiedFilePath, nil } // If no path is specified, try to get the cosmos client context and use // the configured home directory to write the secret to the default file // name. clientCtx, ok := cmd.Context(). Value(client.ClientContextKey).(*client.Context) if !ok { return "", ErrNoClientCtx } specifiedFilePath = filepath.Join( clientCtx.HomeDir, ConfigFolder, DefaultSecretFileName, ) // Use default secret file name if no path is specified return specifiedFilePath, nil } // generateAuthSecretInFile writes a newly generated JWT secret // to a specified file. func generateAuthSecretInFile(cmd *cobra.Command, fileName string) error { var err error fs := afero.NewOsFs() fileDir := filepath.Dir(fileName) exists, err := afero.DirExists(fs, fileDir) if err != nil { return err } if !exists { if err = fs.MkdirAll(fileDir, secretDirPerms); err != nil { return err } } secret, err := jwt.NewRandom() if err != nil { return err } fileExists, err := afero.Exists(fs, fileName) if err != nil { return err } if err = afero.WriteFile( fs, fileName, []byte(secret.Hex()), secretFilePerms, ); err != nil { return err } // WriteFile only sets permissions on file creation, so explicitly chmod if the file already existed. if fileExists { if err = fs.Chmod(fileName, secretFilePerms); err != nil { return err } } cmd.Printf( "Successfully wrote new JSON-RPC authentication secret to: %s", fileName, ) return nil } func validateJWTSecret(cmd *cobra.Command, filePath string) error { _, err := components.LoadJWTFromFile(filePath) if err != nil { return err } cmd.Printf("Successfully validated JWT secret") return nil } ================================================ FILE: cli/commands/jwt/jwt_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package jwt_test import ( "encoding/hex" "os" "path/filepath" "testing" jwt "github.com/berachain/beacon-kit/cli/commands/jwt" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) func Test_NewGenerateJWTCommand(t *testing.T) { t.Parallel() t.Run( "command should be available and have correct use", func(t *testing.T) { cmd := jwt.NewGenerateJWTCommand() require.Equal(t, "generate", cmd.Use) }, ) t.Run("should create proper file in current directory", func(t *testing.T) { cmd := jwt.NewGenerateJWTCommand() cmd.SetArgs([]string{"--output-path", jwt.DefaultSecretFileName}) require.NoError(t, cmd.Execute()) // We check the file has the contents we expect. checkAuthFileIntegrity(t, jwt.DefaultSecretFileName) require.NoError(t, os.RemoveAll(jwt.DefaultSecretFileName)) }) t.Run("should create proper file in specified folder", func(t *testing.T) { customOutput := filepath.Join("data", "jwt.hex") cmd := jwt.NewGenerateJWTCommand() cmd.SetArgs([]string{"--output-path", customOutput}) require.NoError(t, cmd.Execute()) // We check the file has the contents we expect. checkAuthFileIntegrity(t, customOutput) require.NoError(t, os.RemoveAll(filepath.Dir(customOutput))) }) t.Run("creates proper file in nested specified folder", func(t *testing.T) { rootDirectory := "data" customOutputPath := filepath.Join( rootDirectory, "nest", "nested", "jwt.hex", ) cmd := jwt.NewGenerateJWTCommand() cmd.SetArgs([]string{"--output-path", customOutputPath}) require.NoError(t, cmd.Execute()) // We check the file has the contents we expect. checkAuthFileIntegrity(t, customOutputPath) require.NoError(t, os.RemoveAll(rootDirectory)) }) t.Run("should override existing file when flag is set", func(t *testing.T) { // Create a temporary file to simulate an existing file tempFile, err := os.CreateTemp(t.TempDir(), "existing_jwt.hex") require.NoError(t, err) defer os.Remove(tempFile.Name()) // clean up // Write some content to the file to simulate an existing JWT _, err = tempFile.WriteString("not_a_jwt_secret") require.NoError(t, err) tempFile.Close() // Execute the command with the --force flag to override the existing // file cmd := jwt.NewGenerateJWTCommand() cmd.SetArgs([]string{"--output-path", tempFile.Name()}) require.NoError(t, cmd.Execute()) // Check the file has been overridden with the new content checkAuthFileIntegrity(t, tempFile.Name()) require.NoError(t, os.RemoveAll(tempFile.Name())) }) } func Test_GenerateJWTCommand_FilePermissions(t *testing.T) { t.Parallel() t.Run("new file should have 0600 permissions", func(t *testing.T) { tempDir := t.TempDir() outputPath := filepath.Join(tempDir, "jwt.hex") cmd := jwt.NewGenerateJWTCommand() cmd.SetArgs([]string{"--output-path", outputPath}) require.NoError(t, cmd.Execute()) info, err := os.Stat(outputPath) require.NoError(t, err) require.Equal(t, os.FileMode(0600), info.Mode().Perm(), "new JWT file should have 0600 permissions") }) t.Run("pre-existing file with permissive permissions should be fixed", func(t *testing.T) { tempDir := t.TempDir() outputPath := filepath.Join(tempDir, "jwt.hex") // Create file with world-readable permissions err := os.WriteFile(outputPath, []byte("old_content"), 0755) require.NoError(t, err) // Verify it has permissive permissions info, err := os.Stat(outputPath) require.NoError(t, err) require.Equal(t, os.FileMode(0755), info.Mode().Perm()) // Run the generate command cmd := jwt.NewGenerateJWTCommand() cmd.SetArgs([]string{"--output-path", outputPath}) require.NoError(t, cmd.Execute()) // Verify permissions are now restricted info, err = os.Stat(outputPath) require.NoError(t, err) require.Equal(t, os.FileMode(0600), info.Mode().Perm(), "pre-existing JWT file should have permissions fixed to 0600") // Also verify the content is valid checkAuthFileIntegrity(t, outputPath) }) } func checkAuthFileIntegrity(tb testing.TB, fPath string) { tb.Helper() fs := afero.NewOsFs() fileInfo, err := fs.Stat(fPath) require.NoError(tb, err) require.NotNil(tb, fileInfo) enc, err := afero.ReadFile(fs, fPath) require.NoError(tb, err) var decoded = make([]byte, hex.DecodedLen(len(enc[2:]))) _, err = hex.Decode(decoded, enc[2:]) require.NoError(tb, err) require.Len(tb, decoded, 32) } ================================================ FILE: cli/commands/root.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package commands import ( svrcmd "github.com/berachain/beacon-kit/cli/commands/server/cmd" "github.com/berachain/beacon-kit/cli/config" sdkclient "github.com/cosmos/cosmos-sdk/client" sdkconfig "github.com/cosmos/cosmos-sdk/client/config" "github.com/spf13/cobra" ) // Root is a wrapper around cobra.Command. type Root struct { cmd *cobra.Command } // New returns a new root command with the provided configuration. func New( name string, description string, runHandler func(cmd *cobra.Command) error, clientCtx sdkclient.Context, ) *Root { // create the underlying cobra command cmd := &cobra.Command{ Use: name, Short: description, PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { // set the default command outputs cmd.SetOut(cmd.OutOrStdout()) cmd.SetErr(cmd.ErrOrStderr()) var err error // Update the client context with the flags from the command clientCtx, err = sdkclient.ReadPersistentCommandFlags( clientCtx, cmd.Flags(), ) if err != nil { return err } customClientTemplate, customClientConfig := config.InitClientConfig() // Update the client context with the default custom config clientCtx, err = sdkconfig.CreateClientConfig( clientCtx, customClientTemplate, customClientConfig, ) if err != nil { return err } if err = sdkclient.SetCmdClientContextHandler( clientCtx, cmd, ); err != nil { return err } return runHandler(cmd) }, } cmd.CompletionOptions.DisableDefaultCmd = true return &Root{ cmd: cmd, } } // Run executes the root command. func (root *Root) Run(defaultNodeHome string) error { return svrcmd.Execute( root.cmd, "", defaultNodeHome, ) } ================================================ FILE: cli/commands/server/cmd/execute.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package cmd import ( "context" "strings" "github.com/berachain/beacon-kit/cli/flags" "github.com/berachain/beacon-kit/config" "github.com/cosmos/cosmos-sdk/client" sdkflags "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" "github.com/spf13/viper" ) // Execute executes the root command of an application. It handles creating a // server context object with the appropriate server and client objects injected // into the underlying stdlib Context. It also handles adding core CLI flags, // specifically the logging flags. It returns an error upon execution failure. func Execute(rootCmd *cobra.Command, envPrefix, defaultHome string) error { // Create and set a client.Context on the command's Context. During the // pre-run // of the root command, a default initialized client.Context is provided to // seed child command execution with values such as AccountRetriever, // Keyring, // and a CometBFT RPC. This requires the use of a pointer reference when // getting and setting the client.Context. Ideally, we utilize // https://github.com/spf13/cobra/pull/1118. ctx := CreateExecuteContext(context.Background()) rootCmd.PersistentFlags().String( sdkflags.FlagHome, defaultHome, "directory for config and data") // Chain Spec flags. rootCmd.PersistentFlags().String( flags.ChainSpec, config.DefaultChainSpec, "chain spec to use") rootCmd.PersistentFlags().String( flags.ChainSpecFilePath, config.DefaultChainSpecFilePath, "path to the chain spec toml file") // Update the global viper with the root command's configuration. viper.SetEnvPrefix(envPrefix) viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) viper.AutomaticEnv() return rootCmd.ExecuteContext(ctx) } // CreateExecuteContext returns a base Context with client context // values initialized. func CreateExecuteContext(ctx context.Context) context.Context { return context.WithValue(ctx, client.ClientContextKey, &client.Context{}) } ================================================ FILE: cli/commands/server/pruning.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package server import ( "fmt" "strings" pruningtypes "cosmossdk.io/store/pruning/types" "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/spf13/cast" ) // GetPruningOptionsFromFlags parses command flags and returns the correct // PruningOptions. If a pruning strategy is provided, that will be parsed and // returned, otherwise, it is assumed custom pruning options are provided. func GetPruningOptionsFromFlags( appOpts types.AppOptions, ) (pruningtypes.PruningOptions, error) { strategy := strings.ToLower(cast.ToString(appOpts.Get(FlagPruning))) switch strategy { case pruningtypes.PruningOptionDefault, pruningtypes.PruningOptionNothing, pruningtypes.PruningOptionEverything: return pruningtypes.NewPruningOptionsFromString(strategy), nil case pruningtypes.PruningOptionCustom: opts := pruningtypes.NewCustomPruningOptions( cast.ToUint64(appOpts.Get(FlagPruningKeepRecent)), cast.ToUint64(appOpts.Get(FlagPruningInterval)), ) if err := opts.Validate(); err != nil { return opts, fmt.Errorf("invalid custom pruning options: %w", err) } return opts, nil default: return pruningtypes.PruningOptions{}, fmt.Errorf( "unknown pruning strategy %s", strategy, ) } } ================================================ FILE: cli/commands/server/rollback.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package server import ( "fmt" types "github.com/berachain/beacon-kit/cli/commands/server/types" clicontext "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/storage/db" cmtcmd "github.com/cometbft/cometbft/cmd/cometbft/commands" dbm "github.com/cosmos/cosmos-db" "github.com/spf13/cobra" ) // NewRollbackCmd creates a command to rollback CometBFT and multistore state by // one height. func NewRollbackCmd( appCreator types.AppCreator, ) *cobra.Command { var removeBlock bool cmd := &cobra.Command{ Use: "rollback", Short: "rollback Cosmos SDK and CometBFT state by one height", Long: ` A state rollback is performed to recover from an incorrect application state transition, when CometBFT has persisted an incorrect app hash and is thus unable to make progress. Rollback overwrites a state at height n with the state at height n - 1. The application also rolls back to height n - 1. No blocks are removed, so upon restarting CometBFT the transactions in block n will be re-executed against the application. `, RunE: func(cmd *cobra.Command, _ []string) error { v := clicontext.GetViperFromCmd(cmd) logger := clicontext.GetLoggerFromCmd(cmd) cfg := clicontext.GetConfigFromCmd(cmd) db, err := db.OpenDB(cfg.RootDir, dbm.PebbleDBBackend) if err != nil { return err } app := appCreator(logger, db, nil, cfg, v) // rollback CometBFT state height, hash, err := cmtcmd.RollbackState(cfg, removeBlock) if err != nil { return fmt.Errorf("failed to rollback CometBFT state: %w", err) } // rollback the multistore if err = app.CommitMultiStore().RollbackToVersion(height); err != nil { return fmt.Errorf("failed to rollback to version: %w", err) } logger.Info( "Rolled back state", "height", height, "hash", fmt.Sprintf("%X", hash), ) return nil }, } cmd.Flags(). BoolVar(&removeBlock, "hard", false, "remove last block as well as state") return cmd } ================================================ FILE: cli/commands/server/start.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package server import ( pruningtypes "cosmossdk.io/store/pruning/types" types "github.com/berachain/beacon-kit/cli/commands/server/types" clicontext "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/storage/db" cmtcmd "github.com/cometbft/cometbft/cmd/cometbft/commands" dbm "github.com/cosmos/cosmos-db" "github.com/spf13/cobra" ) const ( // CometBFT full-node start flags. flagAddress = "address" flagTransport = "transport" FlagHaltHeight = "halt-height" FlagHaltTime = "halt-time" FlagInterBlockCache = "inter-block-cache" FlagPruning = "pruning" FlagPruningKeepRecent = "pruning-keep-recent" FlagPruningInterval = "pruning-interval" FlagMinRetainBlocks = "min-retain-blocks" FlagIAVLCacheSize = "iavl-cache-size" FlagDisableIAVLFastNode = "iavl-disable-fastnode" ) // StartCmdOptions defines options that can be customized in // `StartCmdWithOptions`,. type StartCmdOptions struct { // AddFlags allows adding custom flags to the start command. AddFlags func(cmd *cobra.Command) } // StartCmdWithOptions runs the service passed in, either stand-alone or // in-process with // CometBFT. func StartCmdWithOptions( appCreator types.AppCreator, opts StartCmdOptions, ) *cobra.Command { cmd := &cobra.Command{ Use: "start", SilenceUsage: true, Short: "Run the node", Long: `Run the node application with CometBFT in process. By default, the application will run with CometBFT in process. Pruning options can be provided via the '--pruning' flag or alternatively with '--pruning-keep-recent', and 'pruning-interval' together. For '--pruning' the options are as follows: default: the last 362880 states are kept, pruning at 10 block intervals nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) everything: 2 latest states will be kept; pruning at 10 block intervals. custom: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' `, RunE: func(cmd *cobra.Command, _ []string) error { logger := clicontext.GetLoggerFromCmd(cmd) cfg := clicontext.GetConfigFromCmd(cmd) v := clicontext.GetViperFromCmd(cmd) _, err := GetPruningOptionsFromFlags(v) if err != nil { return err } // Open the Database db, err := db.OpenDB(cfg.RootDir, dbm.PebbleDBBackend) if err != nil { return err } // Create the application. return appCreator(logger, db, nil, cfg, v). Start(cmd.Context()) }, } addStartNodeFlags(cmd, opts) return cmd } // addStartNodeFlags should be added to any CLI commands that start the network. func addStartNodeFlags( cmd *cobra.Command, opts StartCmdOptions, ) { cmd.Flags().String( flagAddress, "tcp://127.0.0.1:26658", "Listen address") cmd.Flags(). String( flagTransport, "socket", "Transport protocol: socket, grpc") cmd.Flags(). Uint64( FlagHaltHeight, 0, "Block height at which to gracefully halt the chain and shutdown the node") cmd.Flags(). Uint64( FlagHaltTime, 0, "Minimum block time (in Unix seconds) at which to gracefully halt the chain and shutdown the node") cmd.Flags().Bool( FlagInterBlockCache, true, "Enable inter-block caching") cmd.Flags(). String( FlagPruning, pruningtypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)") cmd.Flags(). Uint64( FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')") cmd.Flags(). Uint64(FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')") cmd.Flags(). Uint64( FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune CometBFT blocks") cmd.Flags(). Bool(FlagDisableIAVLFastNode, false, "Disable fast node for IAVL tree") // add support for all CometBFT-specific command line options cmtcmd.AddNodeFlags(cmd) if opts.AddFlags != nil { opts.AddFlags(cmd) } } ================================================ FILE: cli/commands/server/types/types.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "io" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/types" cmtcfg "github.com/cometbft/cometbft/config" dbm "github.com/cosmos/cosmos-db" ) type ( // AppOptions, usually implemented by Viper, holds the configuration for the application. AppOptions interface { Get(string) interface{} } // AppCreator is a function that allows us to lazily initialize an application using various // configurations. AppCreator func(*phuslu.Logger, dbm.DB, io.Writer, *cmtcfg.Config, AppOptions) types.Node // ChainSpecCreator is a function that allows us to lazily initialize the ChainSpec. ChainSpecCreator func(AppOptions) (chain.Spec, error) ) ================================================ FILE: cli/commands/setup.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package commands import ( "github.com/berachain/beacon-kit/cli/commands/deposit" "github.com/berachain/beacon-kit/cli/commands/genesis" "github.com/berachain/beacon-kit/cli/commands/initialize" "github.com/berachain/beacon-kit/cli/commands/jwt" "github.com/berachain/beacon-kit/cli/commands/server" servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/flags" cmtcli "github.com/berachain/beacon-kit/consensus/cometbft/cli" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/cosmos/cosmos-sdk/version" ) // DefaultRootCommandSetup sets up the default commands for the root command. func DefaultRootCommandSetup( root *Root, mm *cometbft.Service, appCreator servertypes.AppCreator, chainSpecCreator servertypes.ChainSpecCreator, ) { // Add all the commands to the root command. root.cmd.AddCommand( // `comet` cmtcli.Commands(appCreator), // `init` initialize.InitCmd(chainSpecCreator, mm), // `genesis` genesis.Commands(chainSpecCreator), // `deposit` deposit.Commands(chainSpecCreator, appCreator), // `jwt` jwt.Commands(), // `rollback` server.NewRollbackCmd(appCreator), // `start` server.StartCmdWithOptions(appCreator, server.StartCmdOptions{ AddFlags: flags.AddBeaconKitFlags, }), // `status` cmtcli.StatusCommand(), // `version` version.NewVersionCommand(), ) } ================================================ FILE: cli/components/client_context.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "os" "path/filepath" "github.com/cosmos/cosmos-sdk/client" ) //nolint:gochecknoglobals // todo:fix from sdk. var DefaultNodeHome string //nolint:gochecknoinits // annoying from sdk. func init() { userHomeDir, err := os.UserHomeDir() if err != nil { panic(err) } DefaultNodeHome = filepath.Join(userHomeDir, ".beacond") } // ProvideClientContext returns a new client context with the given options. func ProvideClientContext() (client.Context, error) { clientCtx := client.Context{}. WithInput(os.Stdin). WithHomeDir(DefaultNodeHome). WithViper("") // uses by default the binary name as prefix // Do not call CreateClientConfig here as it may create directories // in the default home directory before the --home flag is parsed. // This will be called again in PersistentPreRunE after flags are parsed. return clientCtx, nil } ================================================ FILE: cli/components/defaults.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components // DefaultClientComponents returns the default components for // the client. func DefaultClientComponents() []any { return []any{ ProvideClientContext, ProvideLogger, } } ================================================ FILE: cli/components/logger.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "io" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/phuslu" ) type LoggerInput struct { depinject.In Out io.Writer } // ProvideLogger creates a the default phuslu logger. // It reads the log level and format from the server context. func ProvideLogger( in LoggerInput, ) *phuslu.Logger { // the logger config should be passed in here, but it is not yet populated // so we pass in nil for now to get the default logger. logger := phuslu.NewLogger(in.Out, nil) logger.AddKeyColor("error", log.Red) logger.AddKeyColor("err", log.Red) return logger } ================================================ FILE: cli/config/app.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "errors" "fmt" "os" "path/filepath" "github.com/berachain/beacon-kit/config/config" "github.com/spf13/viper" ) // handleAppConfig writes the provided to the file at /app.toml, or // reads it into the provided instance if it exists. func handleAppConfig( viper *viper.Viper, configDirPath string, customAppTemplate string, appConfig any, ) error { // If the app.toml file does not exist, populate it with the values from . appCfgFilePath := filepath.Join(configDirPath, "app.toml") if _, err := os.Stat(appCfgFilePath); os.IsNotExist(err) { return writeAppConfig( viper, appCfgFilePath, customAppTemplate, appConfig, ) } // Merge the app.toml file into the viper instance. viper.SetConfigType("toml") viper.SetConfigName("app") viper.AddConfigPath(configDirPath) if err := viper.MergeInConfig(); err != nil { return fmt.Errorf("failed to merge configuration: %w", err) } return nil } // writeAppConfig creates a new configuration file with default // values at the specified file path . func writeAppConfig( rootViper *viper.Viper, appConfigFilePath string, appTemplate string, appConfig any, ) error { var ( writeConfig any // config to write to the file appTemplatePopulated = appTemplate != "" appConfigPopulated = appConfig != nil ) switch { case appTemplatePopulated && appConfigPopulated: // template and config are both populated, so we set the template // and populate the config with the values from the viper instance if err := config.SetConfigTemplate(appTemplate); err != nil { return fmt.Errorf("failed to set config template: %w", err) } if err := rootViper.Unmarshal(&appConfig); err != nil { return fmt.Errorf("failed to unmarshal app config: %w", err) } writeConfig = appConfig case !appTemplatePopulated && !appConfigPopulated: // template and config are both nil, so we read the config from the file // at appConfigFilePath appConfig, err := config.ParseConfig(rootViper) if err != nil { return fmt.Errorf("failed to parse %s: %w", appConfigFilePath, err) } writeConfig = appConfig default: return errors.New("appTemplate and appConfig must both nil or not nil") } // write the appConfig to the file at appConfigFilePath if err := config.WriteConfigFile(appConfigFilePath, writeConfig); err != nil { return fmt.Errorf("failed to write %s: %w", appConfigFilePath, err) } return nil } ================================================ FILE: cli/config/client.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import client "github.com/cosmos/cosmos-sdk/client/config" // InitClientConfig sets up the default client configuration, allowing for // overrides. func InitClientConfig() (string, any) { clientConfig := client.DefaultConfig() clientConfig.KeyringBackend = "test" return client.DefaultClientConfigTemplate, clientConfig } ================================================ FILE: cli/config/comet.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "fmt" "os" cmtcfg "github.com/cometbft/cometbft/config" "github.com/spf13/viper" ) // handleCometConfig reads the comet config at into the // provided instance. If the file does not exist, it will be populated // with the values from . // will then be updated with the latest values from . func handleCometConfig( viper *viper.Viper, cometConfigFile string, cometConfig *cmtcfg.Config, rootDir string, configDirPath string, ) error { _, err := os.Stat(cometConfigFile) if os.IsNotExist(err) { // file does not exist, we create a new comet config file one // with default values. cmtcfg.EnsureRoot(rootDir) cmtcfg.WriteConfigFile(cometConfigFile, cometConfig) } else if err != nil { return err } // read the config.toml file into the viper instance viper.SetConfigType("toml") viper.SetConfigName("config") viper.AddConfigPath(configDirPath) if err = viper.ReadInConfig(); err != nil { return fmt.Errorf("failed to read in %s: %w", cometConfigFile, err) } // update the comet config with the latest values from viper if err = viper.Unmarshal(cometConfig); err != nil { return err } cometConfig.SetRoot(rootDir) return nil } ================================================ FILE: cli/config/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import "errors" // ErrFlagBind is returned when there is an error binding a flag to the viper // instance. var ErrFlagBind = errors.New("failed to bind flag") ================================================ FILE: cli/config/server.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "context" "fmt" "os" "path" "path/filepath" "strings" clicontext "github.com/berachain/beacon-kit/cli/context" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log/phuslu" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" ) // SetupCommand returns a cobra.Command initialized with a viper // instance. If the files expected to contain the comet and app // configs are empty, it will be populated with the values from // and . In either case, the resulting // values in these files will be merged with viper. func SetupCommand( cmd *cobra.Command, appTemplate string, appConfig any, cmtConfig *cmtcfg.Config, logger *phuslu.Logger, ) error { // initialize the server context if err := InitializeCmd(cmd, logger); err != nil { return err } if err := handleConfigs( clicontext.GetViperFromCmd(cmd), appTemplate, appConfig, cmtConfig, ); err != nil { return err } return nil } // InitializeCmd returns a command object with the root viper instance. // The comet config and app config are merged into the viper instance. // If the app config is empty, the viper instance is populated with // the app config values. func InitializeCmd(cmd *cobra.Command, logger *phuslu.Logger) error { // Get the executable name and configure the viper instance so that // environmental variables are checked based off that name. baseName, err := baseName() if err != nil { return err } viper := newPrefixedViper(baseName) // bind cobra flags to the viper instance if err = bindFlags(baseName, cmd, viper); err != nil { return errors.Wrapf(ErrFlagBind, "error binding flags: %w", err) } ctx := cmd.Context() ctx = context.WithValue(ctx, clicontext.ViperContextKey, viper) ctx = context.WithValue( ctx, clicontext.LoggerContextKey, logger, ) cmd.SetContext(ctx) return nil } // newPrefixedViper creates a new viper instance with the given environment // prefix, and replaces all (.) and (-) with (_). func newPrefixedViper(prefix string) *viper.Viper { viper := viper.New() viper.SetEnvPrefix(prefix) viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_")) viper.AutomaticEnv() return viper } // baseName returns the base name of the executable. // ex: full path /usr/local/bin/myapp -> myapp func baseName() (string, error) { executableName, err := os.Executable() if err != nil { return "", fmt.Errorf("failed to fetch executable name: %w", err) } return path.Base(executableName), nil } // bindFlags binds the command line flags to the viper instance. func bindFlags( basename string, cmd *cobra.Command, v *viper.Viper, ) (err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("bindFlags failed: %v", r) } }() cmd.Flags().VisitAll(func(f *pflag.Flag) { // this should be redundant err = v.BindEnv(f.Name, fmt.Sprintf("%s_%s", basename, strings.ToUpper( strings.ReplaceAll(f.Name, "-", "_")))) if err != nil { panic(err) } err = v.BindPFlag(f.Name, f) if err != nil { panic(err) } if !f.Changed && v.IsSet(f.Name) { val := v.Get(f.Name) err = cmd.Flags().Set(f.Name, fmt.Sprintf("%v", val)) if err != nil { panic(err) } } }) return err } // handleConfigs writes a new comet config file and app config file, and // merges them into the provided viper instance. func handleConfigs( viper *viper.Viper, customAppTemplate string, customConfig any, cometConfig *cmtcfg.Config, ) error { rootDir := viper.GetString(flags.FlagHome) configDirPath := filepath.Join(rootDir, "config") cmtCfgFile := filepath.Join(configDirPath, "config.toml") if err := handleCometConfig( viper, cmtCfgFile, cometConfig, rootDir, configDirPath, ); err != nil { return err } return handleAppConfig( viper, configDirPath, customAppTemplate, customConfig, ) } ================================================ FILE: cli/context/cmd.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package context import ( cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/log/phuslu" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" "github.com/spf13/viper" ) func GetViperFromCmd(cmd *cobra.Command) *viper.Viper { value := cmd.Context().Value(ViperContextKey) v, ok := value.(*viper.Viper) if !ok { return viper.New() } return v } func GetLoggerFromCmd(cmd *cobra.Command) *phuslu.Logger { v := cmd.Context().Value(LoggerContextKey) logger, ok := v.(*phuslu.Logger) if !ok { return phuslu.NewLogger(cmd.OutOrStdout(), nil) } return logger } func GetConfigFromCmd(cmd *cobra.Command) *cmtcfg.Config { v := cmd.Context().Value(ViperContextKey) viper, ok := v.(*viper.Viper) if !ok { return cometbft.DefaultConfig() } return GetConfigFromViper(viper) } func GetConfigFromViper(v *viper.Viper) *cmtcfg.Config { conf := cometbft.DefaultConfig() err := v.Unmarshal(conf) rootDir := v.GetString(flags.FlagHome) if err != nil { return cometbft.DefaultConfig().SetRoot(rootDir) } return conf.SetRoot(rootDir) } ================================================ FILE: cli/context/keys.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package context type ( loggerContextKey struct{} viperContextKey struct{} ) //nolint:gochecknoglobals // context keys var ( LoggerContextKey loggerContextKey ViperContextKey viperContextKey ) ================================================ FILE: cli/flags/flags.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package flags import ( "github.com/berachain/beacon-kit/config" "github.com/spf13/cobra" ) const ( // Beacon Kit Root Flag. beaconKitRoot = "beacon-kit." ChainSpec = beaconKitRoot + "chain-spec" ChainSpecFilePath = beaconKitRoot + "chain-spec-file" ShutdownTimeout = beaconKitRoot + "shutdown-timeout" // Builder Config. builderRoot = beaconKitRoot + "payload-builder." SuggestedFeeRecipient = builderRoot + "suggested-fee-recipient" BuilderEnabled = builderRoot + "enabled" BuildPayloadTimeout = builderRoot + "payload-timeout" // Validator Config. validatorRoot = beaconKitRoot + "validator." Graffiti = validatorRoot + "graffiti" // Engine Config. engineRoot = beaconKitRoot + "engine." RPCDialURL = engineRoot + "rpc-dial-url" RPCRetryInterval = engineRoot + "rpc-retry-interval" RPCMaxRetryInterval = engineRoot + "rpc-max-retry-interval" RPCTimeout = engineRoot + "rpc-timeout" RPCStartupCheckInterval = engineRoot + "rpc-startup-check-interval" RPCHealthCheckInteval = engineRoot + "rpc-health-check-interval" RPCJWTRefreshInterval = engineRoot + "rpc-jwt-refresh-interval" JWTSecretPath = engineRoot + "jwt-secret-path" // KZG Config. kzgRoot = beaconKitRoot + "kzg." KZGTrustedSetupPath = kzgRoot + "trusted-setup-path" KZGImplementation = kzgRoot + "implementation" // Logger Config. loggerRoot = beaconKitRoot + "logger." TimeFormat = loggerRoot + "time-format" LogLevel = loggerRoot + "log-level" Style = loggerRoot + "style" // Block Store Service Config. blockStoreServiceRoot = beaconKitRoot + "block-store-service." BlockStoreServiceAvailabilityWindow = blockStoreServiceRoot + "availability-window" // Node API Config. nodeAPIRoot = beaconKitRoot + "node-api." NodeAPIEnabled = nodeAPIRoot + "enabled" NodeAPIAddress = nodeAPIRoot + "address" NodeAPILogging = nodeAPIRoot + "logging" // BLS Config. PrivValidatorKeyFile = "priv_validator_key_file" PrivValidatorStateFile = "priv_validator_state_file" ) // AddBeaconKitFlags implements servertypes.ModuleInitFlags interface. func AddBeaconKitFlags(startCmd *cobra.Command) { defaultCfg := config.DefaultConfig() startCmd.Flags().Duration( ShutdownTimeout, defaultCfg.ShutdownTimeout, "maximum time to wait for the node to gracefully shutdown before forcing an exit", ) startCmd.Flags().String( JWTSecretPath, defaultCfg.Engine.JWTSecretPath, "path to the execution client secret", ) startCmd.Flags().String( RPCDialURL, defaultCfg.Engine.RPCDialURL.String(), "rpc dial url", ) startCmd.Flags().Duration( RPCRetryInterval, defaultCfg.Engine.RPCRetryInterval, "initial rpc retry interval", ) startCmd.Flags().Duration( RPCMaxRetryInterval, defaultCfg.Engine.RPCMaxRetryInterval, "max rpc retry interval", ) startCmd.Flags().Duration( RPCTimeout, defaultCfg.Engine.RPCTimeout, "rpc timeout", ) startCmd.Flags().Duration( RPCStartupCheckInterval, defaultCfg.Engine.RPCStartupCheckInterval, "rpc startup check interval", ) startCmd.Flags().Duration( RPCJWTRefreshInterval, defaultCfg.Engine.RPCJWTRefreshInterval, "rpc jwt refresh interval", ) startCmd.Flags().Bool( BuilderEnabled, defaultCfg.PayloadBuilder.Enabled, "payload builder enabled", ) startCmd.Flags().Duration( BuildPayloadTimeout, defaultCfg.PayloadBuilder.PayloadTimeout, "payload builder timeout", ) startCmd.Flags().String( SuggestedFeeRecipient, defaultCfg.PayloadBuilder.SuggestedFeeRecipient.Hex(), "suggested fee recipient", ) startCmd.Flags().String( KZGTrustedSetupPath, defaultCfg.KZG.TrustedSetupPath, "kzg trusted setup path", ) startCmd.Flags().String( KZGImplementation, defaultCfg.KZG.Implementation, "kzg implementation", ) startCmd.Flags().String( TimeFormat, defaultCfg.Logger.TimeFormat, "time format", ) startCmd.Flags().String( LogLevel, defaultCfg.Logger.LogLevel, "log level", ) startCmd.Flags().String( Style, defaultCfg.Logger.Style, "style", ) startCmd.Flags().Int( BlockStoreServiceAvailabilityWindow, defaultCfg.BlockStoreService.AvailabilityWindow, "block service availability window", ) startCmd.Flags().Bool( NodeAPIEnabled, defaultCfg.NodeAPI.Enabled, "node api enabled", ) startCmd.Flags().String( NodeAPIAddress, defaultCfg.NodeAPI.Address, "node api address", ) startCmd.Flags().Bool( NodeAPILogging, defaultCfg.NodeAPI.Logging, "node api logging", ) } ================================================ FILE: cli/utils/genesis/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import "github.com/berachain/beacon-kit/chain" type ChainSpec interface { chain.BalancesSpec } ================================================ FILE: cli/utils/genesis/root.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis import ( "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/spf13/afero" ) // Beacon, AppState and Genesis are code duplications that // collectively reproduce part of genesis file structure type Beacon struct { Deposits types.Deposits `json:"deposits"` } type AppState struct { Beacon `json:"beacon"` } type Genesis struct { AppState `json:"app_state"` } // ComputeValidatorsRootFromFile returns the validator root for a given genesis file and chain spec. func ComputeValidatorsRootFromFile(genesisFile string, cs ChainSpec) (common.Root, error) { genesisBz, err := afero.ReadFile(afero.NewOsFs(), genesisFile) if err != nil { return common.Root{}, errors.Wrap(err, "failed to genesis json file") } var appGenesis Genesis err = json.Unmarshal(genesisBz, &appGenesis) if err != nil { return common.Root{}, errors.Wrap(err, "failed to unmarshal JSON") } return ComputeValidatorsRoot(appGenesis.Deposits, cs), nil } // ComputeValidatorsRoot returns the validator root for a given set of genesis deposits // and a chain spec. func ComputeValidatorsRoot(genesisDeposits types.Deposits, cs ChainSpec) common.Root { validators := make(types.Validators, len(genesisDeposits)) minEffectiveBalance := cs.MinActivationBalance() for i, deposit := range genesisDeposits { val := types.NewValidatorFromDeposit( deposit.Pubkey, deposit.Credentials, deposit.Amount, cs.EffectiveBalanceIncrement(), cs.MaxEffectiveBalance(), ) // mimic processGenesisActivation if val.GetEffectiveBalance() >= minEffectiveBalance { val.SetActivationEligibilityEpoch(0) val.SetActivationEpoch(0) } validators[i] = val } return validators.HashTreeRoot() } ================================================ FILE: cli/utils/genesis/root_test.go ================================================ //go:build test // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package genesis_test import ( libbytes "bytes" "fmt" "math/rand" "reflect" "testing" "testing/quick" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/cli/utils/genesis" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" statetransition "github.com/berachain/beacon-kit/testing/state-transition" "github.com/stretchr/testify/require" ) // generator for random deposits. type TestDeposits []types.Deposit func (TestDeposits) Generate(rand *rand.Rand, size int) reflect.Value { res := make(TestDeposits, size) for i := range size { var ( pubKey crypto.BLSPubkey creds types.WithdrawalCredentials sign crypto.BLSSignature err error ) _, err = rand.Read(pubKey[:]) if err != nil { panic(fmt.Errorf("failed generating random pubKey: %w", err)) } _, err = rand.Read(creds[:]) if err != nil { panic(fmt.Errorf("failed generating random cred: %w", err)) } _, err = rand.Read(sign[:]) if err != nil { panic(fmt.Errorf("failed generating random sign: %w", err)) } res[i] = types.Deposit{ Pubkey: pubKey, Credentials: creds, Amount: math.Gwei(rand.Uint64()), Signature: sign, Index: 0, // indexes will be set in order in the test } } return reflect.ValueOf(res) } func TestCompareGenesisCmdWithStateProcessor(t *testing.T) { t.Parallel() qc := &quick.Config{MaxCount: 1_000} csDev, err := spec.DevnetChainSpec() require.NoError(t, err) csTest, err := spec.TestnetChainSpec() require.NoError(t, err) csMain, err := spec.MainnetChainSpec() require.NoError(t, err) specs := []chain.Spec{csDev, csTest, csMain} for i, cs := range specs { t.Run(fmt.Sprintf("spec-%d", i), func(t *testing.T) { f := func(inputs TestDeposits) bool { deposits := make(types.Deposits, len(inputs)) for i, input := range inputs { deposits[i] = &types.Deposit{ Pubkey: input.Pubkey, Credentials: input.Credentials, Amount: input.Amount, Signature: input.Signature, Index: uint64(i), } } // genesis validators root from CLI cliValRoot := genesis.ComputeValidatorsRoot(deposits, cs) // genesis validators root from StateProcessor sp, st, _, _, _, _ := statetransition.SetupTestState(t, cs) genPayloadHeader := types.NewEmptyExecutionPayloadHeaderWithVersion(cs.GenesisForkVersion()) _, err = sp.InitializeBeaconStateFromEth1( st, deposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) var processorRoot common.Root processorRoot, err = st.GetGenesisValidatorsRoot() require.NoError(t, err) // assert that they generate the same root, given the same list of deposits return libbytes.Equal(cliValRoot[:], processorRoot[:]) } require.NoError(t, quick.Check(f, qc)) }) } } ================================================ FILE: cli/utils/parser/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package parser import "errors" var ( // ErrInvalidPubKeyLength is returned when the public key is invalid. ErrInvalidPubKeyLength = errors.New( "invalid public key length", ) // ErrInvalidWithdrawalCredentialsLength is returned when the withdrawal // credentials are invalid. ErrInvalidWithdrawalCredentialsLength = errors.New( "invalid withdrawal credentials length", ) // ErrInvalidAmount is returned when the deposit amount is invalid. ErrInvalidAmount = errors.New( "invalid amount", ) // ErrInvalidSignatureLength is returned when the signature is invalid. ErrInvalidSignatureLength = errors.New( "invalid signature length", ) // ErrInvalidRootLength is returned when the deposit root is invalid. ErrInvalidRootLength = errors.New( "invalid root length", ) // ErrInvalid0xPrefixedHexString is returned when the input string is not // a valid 0x prefixed hex string. ErrInvalid0xPrefixedHexString = errors.New( "invalid 0x prefixed hex string", ) ) ================================================ FILE: cli/utils/parser/validator.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package parser import ( "math/big" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/math" ) // ConvertPubkey converts a string to a public key. func ConvertPubkey(pubkey string) (crypto.BLSPubkey, error) { // convert the public key to a BLSPubkey. pubkeyBytes, err := hex.ToBytes(pubkey) if err != nil { return crypto.BLSPubkey{}, err } if len(pubkeyBytes) != constants.BLSPubkeyLength { return crypto.BLSPubkey{}, ErrInvalidPubKeyLength } return crypto.BLSPubkey(pubkeyBytes), nil } // ConvertWithdrawalCredentials converts a string to a withdrawal credentials. func ConvertWithdrawalCredentials(credentials string) ( types.WithdrawalCredentials, error, ) { // convert the credentials to a WithdrawalCredentials. credentialsBytes, err := hex.ToBytes(credentials) if err != nil { return types.WithdrawalCredentials{}, err } if len(credentialsBytes) != constants.RootLength { return types.WithdrawalCredentials{}, ErrInvalidWithdrawalCredentialsLength } return types.WithdrawalCredentials(credentialsBytes), nil } // ConvertAmount converts a string to a deposit amount. // //nolint:mnd // lots of magic numbers func ConvertAmount(amount string) (math.Gwei, error) { // Convert the amount to a Gwei. amountBigInt, ok := new(big.Int).SetString(amount, 10) if !ok || !amountBigInt.IsUint64() { return 0, ErrInvalidAmount } return math.Gwei(amountBigInt.Uint64()), nil } // ConvertSignature converts a string to a signature. func ConvertSignature(signature string) (crypto.BLSSignature, error) { // convert the signature to a BLSSignature. signatureBytes, err := hex.ToBytes(signature) if err != nil { return crypto.BLSSignature{}, err } if len(signatureBytes) != constants.BLSSignatureLength { return crypto.BLSSignature{}, ErrInvalidSignatureLength } return crypto.BLSSignature(signatureBytes), nil } // ConvertGenesisValidatorRoot converts a string to a genesis validator root. func ConvertGenesisValidatorRoot(root string) (common.Root, error) { rootBytes, err := hex.ToBytes(root) if err != nil { return common.Root{}, err } if len(rootBytes) != constants.RootLength { return common.Root{}, ErrInvalidRootLength } return common.Root(rootBytes), nil } ================================================ FILE: cmd/beacond/defaults.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package main import ( "github.com/berachain/beacon-kit/node-core/components" ) func DefaultComponents() []any { c := []any{ components.ProvideAttributesFactory, components.ProvideAvailabilityStore, components.ProvideDepositContract, components.ProvideBlockStore, components.ProvideBlsSigner, components.ProvideBlobProcessor, components.ProvideBlobProofVerifier, components.ProvideChainService, components.ProvideNode, components.ProvideConfig, components.ProvideServerConfig, components.ProvideDepositStore, components.ProvideEngineClient, components.ProvideExecutionEngine, components.ProvideJWTSecret, components.ProvideLocalBuilder, components.ProvideReportingService, components.ProvideCometBFTService, components.ProvideServiceRegistry, components.ProvideSidecarFactory, components.ProvideStateProcessor, components.ProvideKVStore, components.ProvideStorageBackend, components.ProvideTelemetrySink, components.ProvideTelemetryService, components.ProvideTrustedSetup, components.ProvideValidatorService, components.ProvideNodeAPIServer, components.ProvideShutDownService, } return c } ================================================ FILE: cmd/beacond/main.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package main import ( "log/slog" "os" clibuilder "github.com/berachain/beacon-kit/cli/builder" clicomponents "github.com/berachain/beacon-kit/cli/components" "github.com/berachain/beacon-kit/config/spec" nodebuilder "github.com/berachain/beacon-kit/node-core/builder" "go.uber.org/automaxprocs/maxprocs" ) // run runs the beacon node. func run() error { // Set the uber max procs if _, err := maxprocs.Set(); err != nil { return err } // Build the node using the node-core. nb := nodebuilder.New( // Set the Runtime Components to the Default. nodebuilder.WithComponents( DefaultComponents(), ), ) // Build the root command using the builder cb := clibuilder.New( // Set the Name to the Default. clibuilder.WithName( "beacond", ), // Set the Description to the Default. clibuilder.WithDescription( "A beacon-kit node usable with most Ethereum execution clients", ), // Set the Runtime Components to the Default. clibuilder.WithComponents( clicomponents.DefaultClientComponents(), ), // Set the NodeBuilderFunc to the NodeBuilder Build. clibuilder.WithNodeBuilderFunc(nb.Build), clibuilder.WithChainSpecBuilderFunc(spec.Create), ) cmd, err := cb.Build() if err != nil { return err } // eventually we want to decouple from cosmos cli, and just pass in a built // Node and Cmd to a runner // for now, running the cmd will start the node return cmd.Run(clicomponents.DefaultNodeHome) } // main is the entry point. func main() { if err := run(); err != nil { //nolint:sloglint // todo fix. slog.Error("startup failure", "error", err) os.Exit(1) } } ================================================ FILE: codecov.yml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. coverage: status: project: default: target: 0% patch: off comment: layout: "reach, diff, flags, files" behavior: once require_changes: true show_carryforward_flags: true ignore: - "**/*.pb.go" - "**/*.pb.gw.go" - "**/*.pulsar.go" - "**/*.abigen.go" - "**/*.ssz.go" - "**/*.rlpgen.go" - "**/*.json.go" - "**/*.mock.go" - "**/proto" - "**/build" - "**/testing/e2e" ================================================ FILE: config/config/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "fmt" pruningtypes "cosmossdk.io/store/pruning/types" "github.com/cosmos/cosmos-sdk/telemetry" "github.com/spf13/viper" ) // BaseConfig defines the server's basic configuration. type BaseConfig struct { Pruning string `mapstructure:"pruning"` PruningKeepRecent string `mapstructure:"pruning-keep-recent"` PruningInterval string `mapstructure:"pruning-interval"` // HaltHeight contains a non-zero block height at which a node will // gracefully // halt and shutdown that can be used to assist upgrades and testing. // // Note: Commitment of state will be attempted on the corresponding block. HaltHeight uint64 `mapstructure:"halt-height"` // HaltTime contains a non-zero minimum block time (in Unix seconds) at // which // a node will gracefully halt and shutdown that can be used to assist // upgrades and testing. // // Note: Commitment of state will be attempted on the corresponding block. HaltTime uint64 `mapstructure:"halt-time"` // MinRetainBlocks defines the minimum block height offset from the current // block being committed, such that blocks past this offset may be pruned // from CometBFT. It is used as part of the process of determining the // ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 // indicates // that no blocks should be pruned. // // This configuration value is only responsible for pruning CometBFT blocks. // It has no bearing on application state pruning which is determined by the // "pruning-*" configurations. // // Note: CometBFT block pruning is dependent on this parameter in // conjunction with the unbonding (safety threshold) period, state pruning // and state sync // snapshot parameters to determine the correct minimum value of // ResponseCommit.RetainHeight. MinRetainBlocks uint64 `mapstructure:"min-retain-blocks"` // InterBlockCache enables inter-block caching. InterBlockCache bool `mapstructure:"inter-block-cache"` // IavlCacheSize set the size of the iavl tree cache. IAVLCacheSize uint64 `mapstructure:"iavl-cache-size"` // IAVLDisableFastNode enables or disables the fast sync node. IAVLDisableFastNode bool `mapstructure:"iavl-disable-fastnode"` } // Config defines the server's top level configuration. type Config struct { BaseConfig `mapstructure:",squash"` // Telemetry defines the application telemetry configuration Telemetry telemetry.Config `mapstructure:"telemetry"` } // DefaultConfig returns server's default configuration. func DefaultConfig() *Config { return &Config{ BaseConfig: BaseConfig{ InterBlockCache: true, Pruning: pruningtypes.PruningOptionDefault, PruningKeepRecent: "0", PruningInterval: "0", MinRetainBlocks: 0, //nolint:mnd // its a bet. IAVLCacheSize: 5000, IAVLDisableFastNode: false, }, Telemetry: telemetry.Config{ Enabled: false, GlobalLabels: [][]string{}, }, } } // GetConfig returns a fully parsed Config object. func GetConfig(v *viper.Viper) (Config, error) { conf := DefaultConfig() if err := v.Unmarshal(conf); err != nil { return Config{}, fmt.Errorf("error extracting app config: %w", err) } return *conf, nil } // ValidateBasic returns an error if min-gas-prices field is empty in // BaseConfig. Otherwise, it returns nil. func (c Config) ValidateBasic() error { // if c.Pruning == pruningtypes.PruningOptionEverything && // c.StateSync.SnapshotInterval > 0 { // return sdkerrors.ErrAppConfig.Wrapf( // "cannot enable state sync snapshots with '%s' pruning setting", // pruningtypes.PruningOptionEverything, // ) // } return nil } ================================================ FILE: config/config/config.toml.tpl ================================================ # This is a TOML config file. # For more information, see https://github.com/toml-lang/toml ############################################################################### ### Base Configuration ### ############################################################################### # default: the last 362880 states are kept, pruning at 10 block intervals # nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) # everything: 2 latest states will be kept; pruning at 10 block intervals. # custom: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' pruning = "{{ .BaseConfig.Pruning }}" # These are applied if and only if the pruning strategy is custom. pruning-keep-recent = "{{ .BaseConfig.PruningKeepRecent }}" pruning-interval = "{{ .BaseConfig.PruningInterval }}" # HaltHeight contains a non-zero block height at which a node will gracefully # halt and shutdown that can be used to assist upgrades and testing. # # Note: Commitment of state will be attempted on the corresponding block. halt-height = {{ .BaseConfig.HaltHeight }} # HaltTime contains a non-zero minimum block time (in Unix seconds) at which # a node will gracefully halt and shutdown that can be used to assist upgrades # and testing. # # Note: Commitment of state will be attempted on the corresponding block. halt-time = {{ .BaseConfig.HaltTime }} # MinRetainBlocks defines the minimum block height offset from the current # block being committed, such that all blocks past this offset are pruned # from CometBFT. It is used as part of the process of determining the # ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates # that no blocks should be pruned. # # This configuration value is only responsible for pruning CometBFT blocks. # It has no bearing on application state pruning which is determined by the # "pruning-*" configurations. # # Note: CometBFT block pruning is dependent on this parameter in conjunction # with the unbonding (safety threshold) period, state pruning and state sync # snapshot parameters to determine the correct minimum value of # ResponseCommit.RetainHeight. min-retain-blocks = {{ .BaseConfig.MinRetainBlocks }} # InterBlockCache enables inter-block caching. inter-block-cache = {{ .BaseConfig.InterBlockCache }} # IavlCacheSize set the size of the iavl tree cache (in number of nodes). iavl-cache-size = {{ .BaseConfig.IAVLCacheSize }} # IAVLDisableFastNode enables or disables the fast node feature of IAVL. # Default is false. iavl-disable-fastnode = {{ .BaseConfig.IAVLDisableFastNode }} ############################################################################### ### Telemetry Configuration ### ############################################################################### [telemetry] # Prefixed with keys to separate services. service-name = "{{ .Telemetry.ServiceName }}" # Enabled enables the application telemetry functionality. When enabled, # an in-memory sink is also enabled by default. Operators may also enabled # other sinks such as Prometheus. enabled = {{ .Telemetry.Enabled }} # Enable prefixing gauge values with hostname. enable-hostname = {{ .Telemetry.EnableHostname }} # Enable adding hostname to labels. enable-hostname-label = {{ .Telemetry.EnableHostnameLabel }} # Enable adding service to labels. enable-service-label = {{ .Telemetry.EnableServiceLabel }} # PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. prometheus-retention-time = {{ .Telemetry.PrometheusRetentionTime }} # GlobalLabels defines a global set of name/value label tuples applied to all # metrics emitted using the wrapper functions defined in telemetry package. # # Example: # [["chain_id", "cosmoshub-1"]] global-labels = [{{ range $k, $v := .Telemetry.GlobalLabels }} ["{{index $v 0 }}", "{{ index $v 1}}"],{{ end }} ] # MetricsSink defines the type of metrics sink to use. metrics-sink = "{{ .Telemetry.MetricsSink }}" # StatsdAddr defines the address of a statsd server to send metrics to. # Only utilized if MetricsSink is set to "statsd" or "dogstatsd". statsd-addr = "{{ .Telemetry.StatsdAddr }}" # DatadogHostname defines the hostname to use when emitting metrics to # Datadog. Only utilized if MetricsSink is set to "dogstatsd". datadog-hostname = "{{ .Telemetry.DatadogHostname }}" ================================================ FILE: config/config/toml.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // //nolint:gochecknoglobals // todo fix. package config import ( "bytes" _ "embed" "fmt" "os" "text/template" "github.com/spf13/viper" ) //go:embed config.toml.tpl var DefaultConfigTemplate string var configTemplate *template.Template //nolint:gochecknoinits // i agree, todo fix. func init() { var err error tmpl := template.New("appConfigFileTemplate") if configTemplate, err = tmpl.Parse(DefaultConfigTemplate); err != nil { panic(err) } } // ParseConfig retrieves the default environment configuration for the // application. func ParseConfig(v *viper.Viper) (*Config, error) { conf := DefaultConfig() err := v.Unmarshal(conf) return conf, err } // SetConfigTemplate sets the custom app config template for the application. func SetConfigTemplate(customTemplate string) error { var err error tmpl := template.New("appConfigFileTemplate") if configTemplate, err = tmpl.Parse(customTemplate); err != nil { return err } return nil } // WriteConfigFile renders config using the template and writes it to // configFilePath. func WriteConfigFile(configFilePath string, config interface{}) error { var buffer bytes.Buffer if err := configTemplate.Execute(&buffer, config); err != nil { return err } if err := os.WriteFile(configFilePath, buffer.Bytes(), 0o600); err != nil { return fmt.Errorf("failed to write file: %w", err) } return nil } ================================================ FILE: config/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "time" "github.com/berachain/beacon-kit/beacon/validator" "github.com/berachain/beacon-kit/config/template" viperlib "github.com/berachain/beacon-kit/config/viper" "github.com/berachain/beacon-kit/da/kzg" "github.com/berachain/beacon-kit/errors" engineclient "github.com/berachain/beacon-kit/execution/client" log "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-api/server" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/storage/block" "github.com/mitchellh/mapstructure" "github.com/spf13/viper" ) const ( DefaultChainSpec = "mainnet" DefaultChainSpecFilePath = "" defaultShutdownTimeout = 5 * time.Minute ) // AppOptions is from the SDK, we should look to remove its usage. type AppOptions interface { Get(string) interface{} } // DefaultConfig returns the default configuration for a BeaconKit chain. func DefaultConfig() *Config { return &Config{ ChainSpec: DefaultChainSpec, ChainSpecFilePath: DefaultChainSpecFilePath, ShutdownTimeout: defaultShutdownTimeout, Engine: engineclient.DefaultConfig(), Logger: log.DefaultConfig(), KZG: kzg.DefaultConfig(), PayloadBuilder: builder.DefaultConfig(), Validator: validator.DefaultConfig(), BlockStoreService: block.DefaultConfig(), NodeAPI: server.DefaultConfig(), } } // Config is the main configuration struct for the BeaconKit chain. type Config struct { // ChainSpec is the type of chain spec to use. ChainSpec string `mapstructure:"chain-spec"` // ChainSpecFilePath is the path to the chain spec file to use. ChainSpecFilePath string `mapstructure:"chain-spec-file"` // ShutdownTimeout is the maximum time to wait for the node to gracefully shutdown before // forcing an exit. ShutdownTimeout time.Duration `mapstructure:"shutdown-timeout"` // Engine is the configuration for the execution client. Engine engineclient.Config `mapstructure:"engine"` // Logger is the configuration for the logger. Logger log.Config `mapstructure:"logger"` // KZG is the configuration for the KZG blob verifier. KZG kzg.Config `mapstructure:"kzg"` // PayloadBuilder is the configuration for the local build payload timeout. PayloadBuilder builder.Config `mapstructure:"payload-builder"` // Validator is the configuration for the validator client. Validator validator.Config `mapstructure:"validator"` // BlockStoreService is the configuration for the block store service. BlockStoreService block.Config `mapstructure:"block-store-service"` // NodeAPI is the configuration for the node API. NodeAPI server.Config `mapstructure:"node-api"` } // GetEngine returns the execution client configuration. func (c Config) GetEngine() *engineclient.Config { return &c.Engine } // GetPayloadBuilder returns the block store configuration. func (c Config) GetPayloadBuilder() *builder.Config { return &c.PayloadBuilder } // GetBlockStoreService returns the block store configuration. func (c Config) GetBlockStoreService() *block.Config { return &c.BlockStoreService } // GetLogger returns the logger configuration. func (c Config) GetLogger() *log.Config { return &c.Logger } // Template returns the configuration template. func (c Config) Template() string { return template.TomlTemplate } // ReadConfigFromAppOpts reads the configuration options from the given // application options. func ReadConfigFromAppOpts(opts AppOptions) (*Config, error) { v, ok := opts.(*viper.Viper) if !ok { return nil, errors.New("invalid application options type") } type cfgUnmarshaller struct { BeaconKit Config `mapstructure:"beacon-kit"` } cfg := cfgUnmarshaller{} if err := v.Unmarshal(&cfg, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), viperlib.StringToExecutionAddressFunc(), viperlib.StringToDialURLFunc(), viperlib.StringToConnectionURLFunc(), ))); err != nil { return nil, err } return &cfg.BeaconKit, nil } ================================================ FILE: config/spec/creator.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package spec import ( "errors" "fmt" "reflect" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/flags" viperlib "github.com/berachain/beacon-kit/config/viper" "github.com/mitchellh/mapstructure" "github.com/spf13/cast" "github.com/spf13/viper" ) const ( devnet = "devnet" mainnet = "mainnet" testnet = "testnet" file = "file" ) // Create creates a chain spec based on the app options config flag for "chain-spec". // If unset, the default of "mainnet" chain spec is used. func Create(appOpts types.AppOptions) (chain.Spec, error) { var ( chainSpec chain.Spec err error ) switch cast.ToString(appOpts.Get(flags.ChainSpec)) { case file: chainSpec, err = handleChainSpecFile(appOpts) case devnet: chainSpec, err = DevnetChainSpec() case testnet: chainSpec, err = TestnetChainSpec() case mainnet: fallthrough default: chainSpec, err = MainnetChainSpec() } if err != nil { return nil, err } if chainSpec == nil { return nil, errors.New("no chain spec found") } return chainSpec, nil } // handleChainSpecFile loads a chain spec from the file path given in the app options. func handleChainSpecFile(appOpts types.AppOptions) (chain.Spec, error) { specPath := cast.ToString(appOpts.Get(flags.ChainSpecFilePath)) if specPath == "" { return nil, fmt.Errorf("expected flag '%s' for chain spec", flags.ChainSpecFilePath) } specData, err := loadSpecData(specPath) if err != nil { return nil, err } return chain.NewSpec(specData) } // loadSpecData reads the TOML chain-spec file from the given path using Viper, // unmarshals it into a SpecData, and validates that all required fields are set. func loadSpecData(path string) (*chain.SpecData, error) { v := viper.New() v.SetConfigFile(path) v.SetConfigType("toml") if err := v.ReadInConfig(); err != nil { return nil, fmt.Errorf("failed to read config: %w", err) } // Ensure all required fields are set, including embedded structs. specData := chain.SpecData{} if err := validateRequiredFields(reflect.TypeOf(specData), v, ""); err != nil { return nil, err } // Define a decode hook to handle addresses and domain types. decodeHookFunc := mapstructure.ComposeDecodeHookFunc( viperlib.StringToExecutionAddressFunc(), viperlib.NumericToDomainTypeFunc(), ) if err := v.Unmarshal(&specData, viper.DecodeHook(decodeHookFunc)); err != nil { return nil, fmt.Errorf("failed to unmarshal config into SpecData: %w", err) } return &specData, nil } // validateRequiredFields validates that all fields with mapstructure tags are present in // the configuration. This includes fields in embedded structs. // //nolint:gocognit func validateRequiredFields(t reflect.Type, v *viper.Viper, prefix string) error { // Handle pointer types if t.Kind() == reflect.Ptr { t = t.Elem() } // Only process struct types if t.Kind() != reflect.Struct { return nil } for i := range t.NumField() { field := t.Field(i) tag := field.Tag.Get("mapstructure") // Skip fields without mapstructure tag if tag == "" { // Check if this is an embedded struct that might have its own fields if field.Anonymous && field.Type.Kind() == reflect.Struct { // For embedded structs without a tag, check their fields directly if err := validateRequiredFields(field.Type, v, prefix); err != nil { return err } } continue } // Build the full key path fullKey := tag if prefix != "" { fullKey = prefix + "." + tag } // For struct fields (embedded or not) with mapstructure tags, validate their sub-fields if field.Anonymous || field.Type.Kind() == reflect.Struct { // This is an embedded struct with its own mapstructure tag // Validate its sub-fields with the tag as prefix if err := validateRequiredFields(field.Type, v, tag); err != nil { return err } continue } // Regular field - check if it's set in the config if !v.IsSet(fullKey) { return fmt.Errorf("missing required configuration for key: %s", fullKey) } } return nil } ================================================ FILE: config/spec/creator_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package spec_test import ( "os" "path/filepath" "testing" "github.com/berachain/beacon-kit/cli/flags" "github.com/berachain/beacon-kit/config/spec" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // dummyAppOptions is a simple implementation of the AppOptions interface for testing. type dummyAppOptions struct { values map[string]interface{} } func (d dummyAppOptions) Get(key string) interface{} { return d.values[key] } func TestCreateChainSpec_Devnet(t *testing.T) { t.Parallel() // Set the app opts to force the devnet branch. opts := dummyAppOptions{values: map[string]interface{}{ flags.ChainSpec: "devnet", }} cs, err := spec.Create(opts) require.NoError(t, err) require.NotNil(t, cs) devnetSpec, err := spec.DevnetChainSpec() require.NoError(t, err) require.Equal(t, cs, devnetSpec, "expected devnet chain spec to match") } func TestCreateChainSpec_Testnet(t *testing.T) { t.Parallel() // Set the app opts to force the testnet branch. opts := dummyAppOptions{values: map[string]interface{}{ flags.ChainSpec: "testnet", }} cs, err := spec.Create(opts) require.NoError(t, err) require.NotNil(t, cs) testnetSpec, err := spec.TestnetChainSpec() require.NoError(t, err) require.Equal(t, cs, testnetSpec, "expected testnet chain spec to match") } func TestCreateChainSpec_Mainnet(t *testing.T) { t.Parallel() // Set the app opts to force the mainnet branch. opts := dummyAppOptions{values: map[string]interface{}{ flags.ChainSpec: "mainnet", }} cs, err := spec.Create(opts) require.NoError(t, err) require.NotNil(t, cs) mainnetSpec, err := spec.MainnetChainSpec() require.NoError(t, err) require.Equal(t, cs, mainnetSpec, "expected mainnet chain spec to match") } func TestCreateChainSpec_Default_NoSpecFlag(t *testing.T) { t.Parallel() // Provide an empty app opts so that no spec flag is present. opts := dummyAppOptions{values: map[string]interface{}{}} cs, err := spec.Create(opts) require.NoError(t, err) mainnetSpec, err := spec.MainnetChainSpec() require.NoError(t, err) require.Equal(t, cs, mainnetSpec, "expected mainnet chain spec to match") } func TestCreateChainSpec_File(t *testing.T) { t.Parallel() // Provide a non-empty value for the custom spec file of mainnet. opts := dummyAppOptions{values: map[string]interface{}{ flags.ChainSpec: "file", flags.ChainSpecFilePath: "../../testing/networks/80094/spec.toml", }} mcs, err := spec.Create(opts) require.NoError(t, err) mainnetSpec, err := spec.MainnetChainSpec() require.NoError(t, err) require.Equal(t, mainnetSpec, mcs, "the chain spec loaded from TOML does not match the mainnet spec") // Provide a non-empty value for the custom spec file of testnet. opts.values[flags.ChainSpecFilePath] = "../../testing/networks/80069/spec.toml" tcs, err := spec.Create(opts) require.NoError(t, err) testnetSpec, err := spec.TestnetChainSpec() require.NoError(t, err) require.Equal(t, testnetSpec, tcs, "the chain spec loaded from TOML does not match the testnet spec") // Provide a non-empty value for the custom spec file of devnet. opts.values[flags.ChainSpecFilePath] = "../../testing/files/spec.toml" dcs, err := spec.Create(opts) require.NoError(t, err) devnetSpec, err := spec.DevnetChainSpec() require.NoError(t, err) require.Equal(t, devnetSpec, dcs, "the chain spec loaded from TOML does not match the devnet spec") } func TestCreateChainSpec_FieldValidation(t *testing.T) { t.Parallel() tempDir := t.TempDir() // Read the valid spec file to use as a success case reference validSpec, err := os.ReadFile("../../testing/files/spec.toml") require.NoError(t, err) tests := []struct { name string specContent string wantErr string // empty means no error expected }{ { name: "valid spec with block-delay-configuration", specContent: string(validSpec), wantErr: "", }, { name: "empty spec file", specContent: "", wantErr: "missing required configuration for key:", }, { name: "partial block-delay-configuration", specContent: `[block-delay-configuration] max-block-delay = 300_000_000_000 `, wantErr: "missing required configuration for key: block-delay-configuration.target-block-time", }, { name: "missing max-effective-balance after block-delay-configuration", specContent: `[block-delay-configuration] max-block-delay = 300_000_000_000 target-block-time = 2_000_000_000 const-block-delay = 500_000_000 consensus-update-height = 1 consensus-enable-height = 2 `, wantErr: "missing required configuration for key: max-effective-balance", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { specFile := filepath.Join(tempDir, tt.name+".toml") require.NoError(t, os.WriteFile(specFile, []byte(tt.specContent), 0600)) opts := dummyAppOptions{values: map[string]interface{}{ flags.ChainSpec: "file", flags.ChainSpecFilePath: specFile, }} _, createErr := spec.Create(opts) if tt.wantErr == "" { require.NoError(t, createErr) } else { require.Error(t, createErr) assert.Contains(t, createErr.Error(), tt.wantErr) } }) } } ================================================ FILE: config/spec/defaults.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package spec // NOTE: Most of these default values are taken from ETH2.0 spec. // Some values (mentioned below) are modified to better suit Berachain's system. const ( // Gwei value constants. defaultMaxEffectiveBalance = 32e9 defaultActivationBalance = 32e9 defaultEffectiveBalanceIncrement = 1e9 defaultHysteresisQuotient = 4 defaultHysteresisDownwardMultiplier = 1 defaultHysteresisUpwardMultiplier = 5 // Time parameters constants. defaultSlotsPerEpoch = 32 defaultSlotsPerHistoricalRoot = 8 defaultMinEpochsToInactivityPenalty = 4 // Signature domains. defaultDomainTypeProposer = 0 defaultDomainTypeAttester = 1 defaultDomainTypeRandao = 2 defaultDomainTypeDeposit = 3 defaultDomainTypeVoluntaryExit = 4 defaultDomainTypeSelectionProof = 5 defaultDomainTypeAggregateAndProof = 6 defaultDomainTypeApplicationMask = 16777216 // "0x00000001" in little endian // Eth1-related values. defaultDepositContractAddress = "0x4242424242424242424242424242424242424242" // Berachain specific. defaultMaxDepositsPerBlock = 16 defaultDepositEth1ChainID = 1 defaultEth1FollowDistance = 1 // Berachain specific. defaultTargetSecondsPerEth1Block = 2 // Berachain specific. // State list length constants. defaultEpochsPerHistoricalVector = 8 defaultEpochsPerSlashingsVector = 8 defaultHistoricalRootsLimit = 8 defaultValidatorRegistryLimit = 1099511627776 // Capella values. defaultMaxWithdrawalsPerPayload = 16 defaultMaxValidatorsPerWithdrawalsSweep = 1 << 14 // Deneb values. defaultMinEpochsForBlobsSidecarsRequest = 4096 defaultMaxBlobCommitmentsPerBlock = 4096 defaultMaxBlobsPerBlock = 6 defaultFieldElementsPerBlob = 4096 defaultBytesPerBlob = 131072 // Berachain values. defaultValidatorSetCap = 256 defaultEVMInflationAddress = "0x0000000000000000000000000000000000000000" defaultEVMInflationPerBlock = 0 // Electra values. defaultMinValidatorWithdrawabilityDelay = 256 ) ================================================ FILE: config/spec/defaults_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package spec_test import ( "testing" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/stretchr/testify/require" ) func TestDomainTypeConversion(t *testing.T) { t.Parallel() cs := spec.MainnetChainSpecData() require.Equal(t, bytes.B4([]byte{0x00, 0x00, 0x00, 0x00}), cs.DomainTypeProposer) require.Equal(t, bytes.B4([]byte{0x01, 0x00, 0x00, 0x00}), cs.DomainTypeAttester) require.Equal(t, bytes.B4([]byte{0x02, 0x00, 0x00, 0x00}), cs.DomainTypeRandao) require.Equal(t, bytes.B4([]byte{0x03, 0x00, 0x00, 0x00}), cs.DomainTypeDeposit) require.Equal(t, bytes.B4([]byte{0x04, 0x00, 0x00, 0x00}), cs.DomainTypeVoluntaryExit) require.Equal(t, bytes.B4([]byte{0x05, 0x00, 0x00, 0x00}), cs.DomainTypeSelectionProof) require.Equal(t, bytes.B4([]byte{0x06, 0x00, 0x00, 0x00}), cs.DomainTypeAggregateAndProof) require.Equal(t, bytes.B4([]byte{0x00, 0x00, 0x00, 0x01}), cs.DomainTypeApplicationMask) } ================================================ FILE: config/spec/devnet.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package spec import ( "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/primitives/common" "github.com/ethereum/go-ethereum/params" ) const ( // devnetEVMInflationAddress is the address of the EVM inflation contract. devnetEVMInflationAddress = "0x6942069420694206942069420694206942069420" // devnetEVMInflationPerBlock is the amount of native EVM balance (in units // of Gwei) to be minted per EL block. devnetEVMInflationPerBlock = 10 * params.GWei // devnetMaxStakeAmount is the maximum amount of native EVM balance (in units // of Gwei) that can be staked. devnetMaxStakeAmount = 4000 * params.GWei // devnetGenesisTime is the timestamp of devnet genesis. devnetGenesisTime = 0 // devnetDeneb1ForkTime is the timestamp at which the Deneb1 fork occurs. devnetDeneb1ForkTime = 0 // devnetElectraForkTime is the timestamp at which the Electra fork occurs. devnetElectraForkTime = 0 // devnetElectra1ForkTime is the timestamp at which the Electra1 fork occurs. // devnet is configured to start on electra1. devnetElectra1ForkTime = 0 // devnetEVMInflationAddressDeneb1 is the address of the EVM inflation contract // after the Deneb1 fork. devnetEVMInflationAddressDeneb1 = "0x4206942069420694206942069420694206942069" // devnetEVMInflationPerBlockDeneb1 is the amount of native EVM balance (in units // of Gwei) to be minted per EL block after the Deneb1 fork. devnetEVMInflationPerBlockDeneb1 = 11 * params.GWei // devnetMinValidatorWithdrawabilityDelay is the delay (in epochs) before a validator can withdraw their stake. devnetMinValidatorWithdrawabilityDelay = 32 // devnetFuluForkTime is the timestamp at which the Fulu fork occurs on devnet. // Set to 0 so devnet starts with Fulu active. devnetFuluForkTime = 0 // devnetEVMInflationPerBlockFulu is the amount of native EVM balance (in units // of Gwei) to be minted per EL block after the Fulu fork on devnet. devnetEVMInflationPerBlockFulu = 12 * params.GWei ) // DevnetChainSpecData is the chain.SpecData for a devnet. It is similar to mainnet but // has different values for testing EVM inflation, staking, and hard forks. // // TODO: remove modifications from mainnet spec to align with mainnet behavior. func DevnetChainSpecData() *chain.SpecData { specData := MainnetChainSpecData() specData.DepositEth1ChainID = chain.DevnetEth1ChainID specData.Config.ConsensusUpdateHeight = 1 specData.Config.ConsensusEnableHeight = 2 // Fork timings are set to facilitate local testing across fork versions. specData.GenesisTime = devnetGenesisTime specData.Deneb1ForkTime = devnetDeneb1ForkTime specData.ElectraForkTime = devnetElectraForkTime specData.Electra1ForkTime = devnetElectra1ForkTime specData.FuluForkTime = devnetFuluForkTime // EVM inflation is different from mainnet to test. specData.EVMInflationAddressGenesis = common.MustNewExecutionAddressFromHex(devnetEVMInflationAddress) specData.EVMInflationPerBlockGenesis = devnetEVMInflationPerBlock // EVM inflation is different from mainnet for now, after the Deneb1 fork. specData.EVMInflationAddressDeneb1 = common.MustNewExecutionAddressFromHex(devnetEVMInflationAddressDeneb1) specData.EVMInflationPerBlockDeneb1 = devnetEVMInflationPerBlockDeneb1 // Staking is different from mainnet for now. specData.MaxEffectiveBalance = devnetMaxStakeAmount specData.MinActivationBalance = defaultActivationBalance specData.EffectiveBalanceIncrement = defaultEffectiveBalanceIncrement specData.SlotsPerEpoch = defaultSlotsPerEpoch specData.MinValidatorWithdrawabilityDelay = devnetMinValidatorWithdrawabilityDelay // EVM inflation for the Fulu fork on devnet. The address remains the same as the Deneb1 fork. specData.EVMInflationAddressFulu = common.MustNewExecutionAddressFromHex(devnetEVMInflationAddressDeneb1) specData.EVMInflationPerBlockFulu = devnetEVMInflationPerBlockFulu return specData } // DevnetChainSpec is the chain.Spec for a devnet. Used by `make start` and unit tests. func DevnetChainSpec() (chain.Spec, error) { return chain.NewSpec(DevnetChainSpecData()) } ================================================ FILE: config/spec/mainnet.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package spec import ( "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/ethereum/go-ethereum/params" ) const ( // BGT contract address. // // A hard fork will occur to set this value as the BGT contract address // when BGT beings to be minted. mainnetEVMInflationAddress = defaultEVMInflationAddress // 0 BERA is minted to the BGT contract per block at genesis. // // A hard fork will occur to set this value as the upper bound of redeemable BGT per // block when BGT begins to be minted. mainnetEVMInflationPerBlock = defaultEVMInflationPerBlock // mainnetValidatorSetCap is 69 on Mainnet at genesis. mainnetValidatorSetCap = 69 // mainnetMaxValidatorsPerWithdrawalsSweep is 31 because we expect at least 36 // validators in the total validators set. We choose a prime number smaller // than the minimum amount of total validators possible. mainnetMaxValidatorsPerWithdrawalsSweep = 31 // mainnetMaxEffectiveBalance is the max stake of 10 million BERA at genesis. mainnetMaxEffectiveBalance = 10_000_000 * params.GWei // mainnetEffectiveBalanceIncrement is 10k BERA at genesis // (equivalent to the Deposit Contract's MIN_DEPOSIT_AMOUNT). mainnetEffectiveBalanceIncrement = 10_000 * params.GWei // mainnetMinActivationBalance [New in Electra:EIP7251] Minimum balance for a validator to // become active. mainnetMinActivationBalance = 250_000 * params.GWei // mainnetSlotsPerEpoch is 192 to mirror the time of epochs on Ethereum mainnet. mainnetSlotsPerEpoch = 192 // mainnetMinEpochsForBlobsSidecarsRequest is 4096 at genesis to match Ethereum mainnet. mainnetMinEpochsForBlobsSidecarsRequest = defaultMinEpochsForBlobsSidecarsRequest // mainnetMaxBlobCommitmentsPerBlock is 4096 at genesis to match Ethereum mainnet. mainnetMaxBlobCommitmentsPerBlock = defaultMaxBlobCommitmentsPerBlock // The deposit contract address on mainnet at genesis is the same as the // default deposit contract address. mainnetDepositContractAddress = defaultDepositContractAddress // mainnetGenesisTime is the timestamp of the Berachain mainnet genesis block. mainnetGenesisTime = 1_737_381_600 // mainnetDeneb1ForkTime is the timestamp at which the Deneb1 fork occurs. // This is calculated based on the timestamp of the 2855th mainnet epoch, block 548160, which // was used to initiate the fork when beacon-kit forked by epoch instead of by timestamp. mainnetDeneb1ForkTime = 1_738_415_507 // mainnetElectraForkTime is the timestamp at which the Electra fork occurs. mainnetElectraForkTime = 1_749_056_400 // mainnetElectra1ForkTime is the timestamp at which the Electra1 fork occurs. mainnetElectra1ForkTime = 1_756_915_200 // mainnetEVMInflationAddressDeneb1 is the address on the EVM which will receive the // inflation amount of native EVM balance through a withdrawal every block in the Deneb1 fork. mainnetEVMInflationAddressDeneb1 = "0x656b95E550C07a9ffe548bd4085c72418Ceb1dba" // mainnetEVMInflationPerBlockDeneb1 is the amount of native EVM balance (in Gwei) to be // minted to the EVMInflationAddressDeneb1 via a withdrawal every block in the Deneb1 fork. mainnetEVMInflationPerBlockDeneb1 = 5.75 * params.GWei // mainnetMinValidatorWithdrawabilityDelay is the number of epochs of delay epochs of delay for a balance to be withdrawable. // 256 Epochs equates to roughly ~27 hours of withdrawal delay. This gives us room to emergency fork if needed. mainnetMinValidatorWithdrawabilityDelay = defaultMinValidatorWithdrawabilityDelay // These are the heights at which SBT is activated on mainnet. mainnetSBTConsensusUpdateHeight = 9_983_085 mainnetSBTConsensusEnableHeight = 9_983_086 // mainnetFuluForkTime is the timestamp at which the Fulu fork occurs. // TODO: Set to actual fork time before Fulu activation. mainnetFuluForkTime = 9_999_999_999_999_999 // mainnetHysteresisQuotientFulu is the hysteresis quotient for the Fulu fork (BRIP-0008). mainnetHysteresisQuotientFulu = 100 // mainnetHysteresisUpwardMultiplierFulu is the hysteresis upward multiplier for the Fulu fork. mainnetHysteresisUpwardMultiplierFulu = 10 // mainnetEVMInflationAddressFulu is the address on the EVM which will receive the // inflation amount of native EVM balance through a withdrawal every block in the Fulu fork. // TODO: Set to actual address before Fulu activation. mainnetEVMInflationAddressFulu = "0x0000000000000000000000000000000000000000" // mainnetEVMInflationPerBlockFulu is the amount of native EVM balance (in Gwei) to be // minted to the EVMInflationAddressFulu via a withdrawal every block in the Fulu fork. // TODO: Set to actual value before Fulu activation. mainnetEVMInflationPerBlockFulu = 0 ) // MainnetChainSpecData is the chain.SpecData for the Berachain mainnet. func MainnetChainSpecData() *chain.SpecData { specData := &chain.SpecData{ Config: delay.DefaultConfig(), // Gwei values constants. MaxEffectiveBalance: mainnetMaxEffectiveBalance, EffectiveBalanceIncrement: mainnetEffectiveBalanceIncrement, HysteresisQuotient: defaultHysteresisQuotient, HysteresisDownwardMultiplier: defaultHysteresisDownwardMultiplier, HysteresisUpwardMultiplier: defaultHysteresisUpwardMultiplier, // Time parameters constants. SlotsPerEpoch: mainnetSlotsPerEpoch, SlotsPerHistoricalRoot: defaultSlotsPerHistoricalRoot, MinEpochsToInactivityPenalty: defaultMinEpochsToInactivityPenalty, // Signature domains. DomainTypeProposer: bytes.FromUint32(defaultDomainTypeProposer), DomainTypeAttester: bytes.FromUint32(defaultDomainTypeAttester), DomainTypeRandao: bytes.FromUint32(defaultDomainTypeRandao), DomainTypeDeposit: bytes.FromUint32(defaultDomainTypeDeposit), DomainTypeVoluntaryExit: bytes.FromUint32(defaultDomainTypeVoluntaryExit), DomainTypeSelectionProof: bytes.FromUint32(defaultDomainTypeSelectionProof), DomainTypeAggregateAndProof: bytes.FromUint32(defaultDomainTypeAggregateAndProof), DomainTypeApplicationMask: bytes.FromUint32(defaultDomainTypeApplicationMask), // Eth1-related values. DepositContractAddress: common.MustNewExecutionAddressFromHex(mainnetDepositContractAddress), MaxDepositsPerBlock: defaultMaxDepositsPerBlock, DepositEth1ChainID: chain.MainnetEth1ChainID, Eth1FollowDistance: defaultEth1FollowDistance, TargetSecondsPerEth1Block: defaultTargetSecondsPerEth1Block, // Fork-related values. GenesisTime: mainnetGenesisTime, Deneb1ForkTime: mainnetDeneb1ForkTime, ElectraForkTime: mainnetElectraForkTime, Electra1ForkTime: mainnetElectra1ForkTime, FuluForkTime: mainnetFuluForkTime, // State list length constants. EpochsPerHistoricalVector: defaultEpochsPerHistoricalVector, EpochsPerSlashingsVector: defaultEpochsPerSlashingsVector, HistoricalRootsLimit: defaultHistoricalRootsLimit, ValidatorRegistryLimit: defaultValidatorRegistryLimit, // Capella values. MaxWithdrawalsPerPayload: defaultMaxWithdrawalsPerPayload, MaxValidatorsPerWithdrawalsSweep: mainnetMaxValidatorsPerWithdrawalsSweep, // Deneb values. MinEpochsForBlobsSidecarsRequest: mainnetMinEpochsForBlobsSidecarsRequest, MaxBlobCommitmentsPerBlock: mainnetMaxBlobCommitmentsPerBlock, MaxBlobsPerBlock: defaultMaxBlobsPerBlock, FieldElementsPerBlob: defaultFieldElementsPerBlob, BytesPerBlob: defaultBytesPerBlob, // Berachain values at genesis. ValidatorSetCap: mainnetValidatorSetCap, EVMInflationAddressGenesis: common.MustNewExecutionAddressFromHex(mainnetEVMInflationAddress), EVMInflationPerBlockGenesis: mainnetEVMInflationPerBlock, // Deneb1 values. EVMInflationAddressDeneb1: common.MustNewExecutionAddressFromHex(mainnetEVMInflationAddressDeneb1), EVMInflationPerBlockDeneb1: mainnetEVMInflationPerBlockDeneb1, // Electra values. MinActivationBalance: mainnetMinActivationBalance, MinValidatorWithdrawabilityDelay: mainnetMinValidatorWithdrawabilityDelay, // Fulu values (BRIP-0008 hysteresis + PoL vNext). HysteresisQuotientFulu: mainnetHysteresisQuotientFulu, HysteresisUpwardMultiplierFulu: mainnetHysteresisUpwardMultiplierFulu, EVMInflationAddressFulu: common.MustNewExecutionAddressFromHex(mainnetEVMInflationAddressFulu), EVMInflationPerBlockFulu: mainnetEVMInflationPerBlockFulu, } specData.Config.ConsensusUpdateHeight = mainnetSBTConsensusUpdateHeight specData.Config.ConsensusEnableHeight = mainnetSBTConsensusEnableHeight return specData } // MainnetChainSpec is the ChainSpec for the Berachain mainnet. func MainnetChainSpec() (chain.Spec, error) { return chain.NewSpec(MainnetChainSpecData()) } ================================================ FILE: config/spec/testnet.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package spec import ( "github.com/berachain/beacon-kit/chain" ) // TestnetChainSpecData is the chain.SpecData for Berachain's public testnet, Bepolia. func TestnetChainSpecData() *chain.SpecData { specData := MainnetChainSpecData() // Testnet uses chain ID of 80069. specData.DepositEth1ChainID = chain.TestnetEth1ChainID // Timestamp of the genesis block of Bepolia testnet. specData.GenesisTime = 1_739_976_735 // Deneb1 fork timing on Bepolia. This is calculated based on the timestamp of the first bepolia // epoch, block 192, which was used to initiate the fork when beacon-kit forked by epoch instead // of by timestamp. specData.Deneb1ForkTime = 1_740_090_694 // Timestamp of the Electra fork on Bepolia. specData.ElectraForkTime = 1_746_633_600 // Enable stable block time before the Electra1 fork. specData.Config.ConsensusUpdateHeight = 7_768_334 specData.Config.ConsensusEnableHeight = 7_768_335 // Timestamp of the Electra1 fork on Bepolia. specData.Electra1ForkTime = 1_754_496_000 // Timestamp of the Fulu fork on Bepolia. // TODO: Set to actual fork time before Fulu activation. specData.FuluForkTime = 9_999_999_999_999_999 return specData } // TestnetChainSpec is the chain.Spec for Berachain's public testnet. func TestnetChainSpec() (chain.Spec, error) { return chain.NewSpec(TestnetChainSpecData()) } ================================================ FILE: config/template/template.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package template const TomlTemplate = ` ############################################################################### ### BeaconKit ### ############################################################################### [beacon-kit] # ChainSpec is the type of chain spec to use. chain-spec = "{{ .BeaconKit.ChainSpec }}" # ChainSpecFilePath is the path to the chain spec file to use. chain-spec-file = "{{ .BeaconKit.ChainSpecFilePath }}" # ShutdownTimeout is the maximum time to wait for the node to gracefully # shutdown before forcing an exit. shutdown-timeout = "{{ .BeaconKit.ShutdownTimeout }}" [beacon-kit.engine] # HTTP url of the execution client JSON-RPC endpoint. rpc-dial-url = "{{ .BeaconKit.Engine.RPCDialURL }}" # RPC timeout for execution client requests. rpc-timeout = "{{ .BeaconKit.Engine.RPCTimeout }}" # Interval for the startup check. rpc-startup-check-interval = "{{ .BeaconKit.Engine.RPCStartupCheckInterval }}" # Interval for the JWT refresh. rpc-jwt-refresh-interval = "{{ .BeaconKit.Engine.RPCJWTRefreshInterval }}" # Path to the execution client JWT-secret jwt-secret-path = "{{.BeaconKit.Engine.JWTSecretPath}}" [beacon-kit.logger] # TimeFormat is a string that defines the format of the time in the logger. time-format = "{{.BeaconKit.Logger.TimeFormat}}" # LogLevel is the level of logging. Logger will log messages with verbosity up # to LogLevel. log-level = "{{.BeaconKit.Logger.LogLevel}}" # Style is the style of the logger. style = "{{.BeaconKit.Logger.Style}}" [beacon-kit.kzg] # Path to the trusted setup path. trusted-setup-path = "{{.BeaconKit.KZG.TrustedSetupPath}}" # KZG implementation to use. # Options are "crate-crypto/go-kzg-4844". implementation = "{{.BeaconKit.KZG.Implementation}}" [beacon-kit.payload-builder] # Enabled determines if the local payload builder is enabled. # It should be enabled for validators, but it can be disabled # for full nodes. enabled = {{ .BeaconKit.PayloadBuilder.Enabled }} # Post bellatrix, this address will receive the transaction fees produced by any blocks # from this node. suggested-fee-recipient = "{{.BeaconKit.PayloadBuilder.SuggestedFeeRecipient}}" # The timeout for local build payload. This should match, or be slightly less # than the configured timeout on your execution client. It also must be less than # timeout_proposal in the CometBFT configuration. payload-timeout = "{{ .BeaconKit.PayloadBuilder.PayloadTimeout }}" [beacon-kit.validator] # Graffiti string that will be included in the graffiti field of the beacon block. graffiti = "{{ .BeaconKit.Validator.Graffiti }}" [beacon-kit.block-store-service] # AvailabilityWindow is the number of slots to keep in the store. # Setting AvailabilityWindow to 0 disables block store and does not allow the node # to serve proof or namespace apis from beacon node-api. availability-window = "{{ .BeaconKit.BlockStoreService.AvailabilityWindow }}" [beacon-kit.node-api] # Enabled determines if the node API is enabled. enabled = "{{ .BeaconKit.NodeAPI.Enabled }}" # Address is the address to bind the node API to. address = "{{ .BeaconKit.NodeAPI.Address }}" # Logging determines if the node API logging is enabled. logging = "{{ .BeaconKit.NodeAPI.Logging }}" ` ================================================ FILE: config/viper/parser.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package viper import ( "net/url" "reflect" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" beaconurl "github.com/berachain/beacon-kit/primitives/net/url" "github.com/mitchellh/mapstructure" "github.com/spf13/cast" ) // NumericToDomainTypeFunc returns a DecodeHookFunc that converts // numeric values to a `common.DomainType` (which is a `bytes.B4`). func NumericToDomainTypeFunc() mapstructure.DecodeHookFunc { return func( f reflect.Type, t reflect.Type, data interface{}, ) (interface{}, error) { var dt common.DomainType if t != reflect.TypeOf(dt) { return data, nil } switch f.Kind() { case reflect.String: return dt, dt.UnmarshalText([]byte(data.(string))) //nolint:errcheck // Safe to ignore. default: num, err := cast.ToUint32E(data) if err != nil { return common.DomainType{}, err } return bytes.FromUint32(num), nil } } } // StringToExecutionAddressFunc returns a DecodeHookFunc that converts // string to a `primitives.ExecutionAddresses` by parsing the string. func StringToExecutionAddressFunc() mapstructure.DecodeHookFunc { return stringTo(common.NewExecutionAddressFromHex) } // StringToDialURLFunc returns a DecodeHookFunc that converts // string to *url.URL by parsing the string. func StringToDialURLFunc() mapstructure.DecodeHookFunc { return stringTo( func(s string) (*url.URL, error) { url, err := url.Parse(s) if err != nil { return nil, err } return url, nil }, ) } // StringToConnectionURLFunc returns a DecodeHookFunc that converts // string to *beaconurl.ConnectionURL by parsing the string. func StringToConnectionURLFunc() mapstructure.DecodeHookFunc { return stringTo(beaconurl.NewFromRaw) } // stringTo is a helper function for creating DecodeHookFuncs that convert // string to a specific type by parsing the string. func stringTo[T any]( constructor func(string) (T, error), ) mapstructure.DecodeHookFunc { return func( f reflect.Type, t reflect.Type, data interface{}, ) (interface{}, error) { if f.Kind() != reflect.String { return data, nil } var retType T if t != reflect.TypeOf(retType) { return data, nil } // Convert it by parsing //nolint:errcheck // should be safe return constructor(data.(string)) } } ================================================ FILE: consensus/cometbft/cli/commands.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package server import ( "context" "github.com/berachain/beacon-kit/cli/commands/server/types" clicontext "github.com/berachain/beacon-kit/cli/context" service "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/storage/db" cmtcmd "github.com/cometbft/cometbft/cmd/cometbft/commands" cmtcfg "github.com/cometbft/cometbft/config" cmtjson "github.com/cometbft/cometbft/libs/json" "github.com/cometbft/cometbft/node" "github.com/cometbft/cometbft/p2p" pvm "github.com/cometbft/cometbft/privval" cmtversion "github.com/cometbft/cometbft/version" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/grpc/cmtservice" "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/spf13/cobra" "sigs.k8s.io/yaml" ) // Commands add server commands. func Commands( appCreator types.AppCreator, ) *cobra.Command { cometCmd := &cobra.Command{ Use: "comet", Aliases: []string{"cometbft", "tendermint"}, Short: "CometBFT subcommands", } cometCmd.AddCommand( ShowNodeIDCmd(), ShowValidatorCmd(), ShowAddressCmd(), VersionCmd(), cmtcmd.ResetAllCmd, cmtcmd.ResetStateCmd, BootstrapStateCmd(appCreator), ) return cometCmd } // StatusCommand returns the command to return the status of the network. func StatusCommand() *cobra.Command { cmd := &cobra.Command{ Use: "status", Short: "Query remote node for status", RunE: func(cmd *cobra.Command, _ []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { return err } cometRPC, err := clientCtx.GetNode() if err != nil { return err } status, err := cmtservice.GetNodeStatus( context.Background(), cometRPC, ) if err != nil { return err } output, err := cmtjson.Marshal(status) if err != nil { return err } // In order to maintain backwards compatibility, the default json // format output //#nosec:G703 // its a bet. outputFormat, _ := cmd.Flags().GetString(flags.FlagOutput) if outputFormat == flags.OutputFormatJSON { clientCtx = clientCtx.WithOutputFormat(flags.OutputFormatJSON) } return clientCtx.PrintRaw(output) }, } cmd.Flags(). StringP(flags.FlagNode, "n", "tcp://localhost:26657", "Node to connect to") cmd.Flags(). StringP(flags.FlagOutput, "o", "json", "Output format (text|json)") return cmd } // ShowNodeIDCmd - ported from CometBFT, dump node ID to stdout. func ShowNodeIDCmd() *cobra.Command { return &cobra.Command{ Use: "show-node-id", Short: "Show this node's ID", RunE: func(cmd *cobra.Command, _ []string) error { cfg := clicontext.GetConfigFromCmd(cmd) nodeKey, err := p2p.LoadNodeKey(cfg.NodeKeyFile()) if err != nil { return err } cmd.Println(nodeKey.ID()) return nil }, } } // ShowValidatorCmd - ported from CometBFT, show this node's validator info. func ShowValidatorCmd() *cobra.Command { cmd := cobra.Command{ Use: "show-validator", Short: "Show this node's CometBFT validator info", RunE: func(cmd *cobra.Command, _ []string) error { cfg := clicontext.GetConfigFromCmd(cmd) privValidator := pvm.LoadFilePV( cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile(), ) pk, err := privValidator.GetPubKey() if err != nil { return err } sdkPK, err := cryptocodec.FromCmtPubKeyInterface(pk) if err != nil { return err } registry := codectypes.NewInterfaceRegistry() cryptocodec.RegisterInterfaces(registry) cdc := codec.NewProtoCodec(registry) bz, err := cdc.MarshalInterfaceJSON(sdkPK) if err != nil { return err } cmd.Println(string(bz)) return nil }, } return &cmd } // ShowAddressCmd - show this node's validator address. func ShowAddressCmd() *cobra.Command { cmd := &cobra.Command{ Use: "show-address", Short: "Shows this node's CometBFT validator consensus address", RunE: func(cmd *cobra.Command, _ []string) error { cfg := clicontext.GetConfigFromCmd(cmd) privValidator := pvm.LoadFilePV( cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile(), ) valConsAddr := (sdk.ConsAddress)(privValidator.GetAddress()) cmd.Println(valConsAddr.String()) return nil }, } return cmd } // VersionCmd prints CometBFT and ABCI version numbers. func VersionCmd() *cobra.Command { return &cobra.Command{ Use: "version", Short: "Print CometBFT libraries' version", Long: `Print protocols' and libraries' version numbers against which this app has been compiled.`, RunE: func(cmd *cobra.Command, _ []string) error { bs, err := yaml.Marshal(&struct { CometBFT string ABCI string BlockProtocol uint64 P2PProtocol uint64 }{ CometBFT: cmtversion.CMTSemVer, ABCI: cmtversion.ABCIVersion, BlockProtocol: cmtversion.BlockProtocol, P2PProtocol: cmtversion.P2PProtocol, }) if err != nil { return err } cmd.Println(string(bs)) return nil }, } } func BootstrapStateCmd( appCreator types.AppCreator, ) *cobra.Command { cmd := &cobra.Command{ Use: "bootstrap-state", Short: `Bootstrap CometBFT state at an arbitrary block height using a light client`, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { logger := clicontext.GetLoggerFromCmd(cmd) cfg := clicontext.GetConfigFromCmd(cmd) v := clicontext.GetViperFromCmd(cmd) height, err := cmd.Flags().GetInt64("height") if err != nil { return err } if height == 0 { home := v.GetString(flags.FlagHome) var dbi dbm.DB dbi, err = db.OpenDB(home, dbm.PebbleDBBackend) if err != nil { return err } app := appCreator(logger, dbi, nil, cfg, v) height = app.CommitMultiStore().LastCommitID().Version } return node.BootstrapState( cmd.Context(), cfg, cmtcfg.DefaultDBProvider, service.GetGenDocProvider(cfg), uint64(height), // #nosec G115 nil, ) }, } cmd.Flags(). Int64("height", 0, `Block height to bootstrap state at, if not provided it uses the latest block height in app state`) return cmd } ================================================ FILE: consensus/cometbft/service/abci.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package cometbft import ( "context" "errors" "fmt" "time" errorsmod "cosmossdk.io/errors" cmtabci "github.com/cometbft/cometbft/abci/types" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" sdkversion "github.com/cosmos/cosmos-sdk/version" ) var errInvalidHeight = errors.New("invalid height") func (s *Service) InitChain( _ context.Context, req *cmtabci.InitChainRequest, ) (*cmtabci.InitChainResponse, error) { // Check if ctx is still good. CometBFT does not check this. if s.ctx.Err() != nil { // If the context is getting cancelled, we are shutting down. return &cmtabci.InitChainResponse{}, s.ctx.Err() } //nolint:contextcheck // see s.ctx comment for more details return s.initChain(s.ctx, req) } // PrepareProposal implements the PrepareProposal ABCI method and returns a // ResponsePrepareProposal object to the client. func (s *Service) PrepareProposal( _ context.Context, req *cmtabci.PrepareProposalRequest, ) (*cmtabci.PrepareProposalResponse, error) { // Check if ctx is still good. CometBFT does not check this. if s.ctx.Err() != nil { // If the context is getting cancelled, we are shutting down. // It is ok returning an empty proposal. //nolint:nilerr // explicitly allowing this case return &cmtabci.PrepareProposalResponse{Txs: req.Txs}, nil } //nolint:contextcheck // see s.ctx comment for more details return s.prepareProposal(s.ctx, req) } func (s *Service) Info(context.Context, *cmtabci.InfoRequest, ) (*cmtabci.InfoResponse, error) { lastCommitID := s.sm.GetCommitMultiStore().LastCommitID() appVersion := initialAppVersion if lastCommitID.Version > 0 { var err error appVersion, err = s.appVersion() if err != nil { return nil, fmt.Errorf("failed getting app version: %w", err) } } return &cmtabci.InfoResponse{ Data: AppName, Version: sdkversion.Version, AppVersion: appVersion, LastBlockHeight: lastCommitID.Version, LastBlockAppHash: lastCommitID.Hash, }, nil } // ProcessProposal implements the ProcessProposal ABCI method and returns a // ResponseProcessProposal object to the client. func (s *Service) ProcessProposal( _ context.Context, req *cmtabci.ProcessProposalRequest, ) (*cmtabci.ProcessProposalResponse, error) { // Check if ctx is still good. CometBFT does not check this. if s.ctx.Err() != nil { // Node will panic on context cancel with "CONSENSUS FAILURE!!!" due to // returning an error. This is expected. We do not want to accept or // reject a proposal based on incomplete data. return nil, s.ctx.Err() } //nolint:contextcheck // see s.ctx comment for more details return s.processProposal(s.ctx, req) } func (s *Service) FinalizeBlock( _ context.Context, req *cmtabci.FinalizeBlockRequest, ) (*cmtabci.FinalizeBlockResponse, error) { // Check if ctx is still good. CometBFT does not check this. if s.ctx.Err() != nil { // Node will panic on context cancel with "CONSENSUS FAILURE!!!" due to error. // We expect this to happen and do not want to finalize any incomplete or invalid state. return nil, s.ctx.Err() } //nolint:contextcheck // see s.ctx comment for more details return s.finalizeBlock(s.ctx, req) } // Commit implements the ABCI interface. It will commit all state that exists in // the deliver state's multi-store and includes the resulting commit ID in the // returned cmtabci.ResponseCommit. Commit will set the check state based on the // latest header and reset the deliver state. Also, if a non-zero halt height is // defined in config, Commit will execute a deferred function call to check // against that height and gracefully halt if it matches the latest committed // height. func (s *Service) Commit( _ context.Context, req *cmtabci.CommitRequest, ) (*cmtabci.CommitResponse, error) { // Check if ctx is still good. CometBFT does not check this. if s.ctx.Err() != nil { // Node will panic on context cancel with "CONSENSUS FAILURE!!!" due to error. // We expect this to happen and do not want to commit any incomplete or invalid state. return nil, s.ctx.Err() } return s.commit(req) } // NOTE: Partially copied from https://github.com/cosmos/cosmos-sdk/blob/960d44842b9e313cbe762068a67a894ac82060ab/baseapp/abci.go#L168 func (s *Service) Query( _ context.Context, req *abci.QueryRequest, ) (*abci.QueryResponse, error) { resp := new(abci.QueryResponse) // add panic recovery for all queries // // Ref: https://github.com/cosmos/cosmos-sdk/pull/8039 defer func() { if r := recover(); r != nil { *resp = queryResult(errorsmod.Wrapf(sdkerrors.ErrPanic, "%v", r)) } }() // when a client did not provide a query height, manually inject the latest if req.Height == 0 { req.Height = s.lastBlockHeight() } s.telemetrySink.IncrementCounter("beacon_kit.comet.query_count", "path", req.Path) startTime := time.Now() defer s.telemetrySink.MeasureSince( "beacon_kit.comet.query_duration", startTime, "path", req.Path, ) path := splitABCIQueryPath(req.Path) if len(path) == 0 { *resp = queryResult(errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided")) return resp, nil } // Only "/store" prefix for store queries are supported. if path[0] != "store" { *resp = queryResult(errorsmod.Wrap(sdkerrors.ErrNotSupported, "unsupported query path")) return resp, nil } *resp = s.handleQueryStore(path, req) return resp, nil } // // NOOP methods // func (Service) ListSnapshots( context.Context, *abci.ListSnapshotsRequest, ) (*abci.ListSnapshotsResponse, error) { return &abci.ListSnapshotsResponse{}, nil } func (Service) LoadSnapshotChunk( context.Context, *abci.LoadSnapshotChunkRequest, ) (*abci.LoadSnapshotChunkResponse, error) { return &abci.LoadSnapshotChunkResponse{}, nil } func (Service) OfferSnapshot( context.Context, *abci.OfferSnapshotRequest, ) (*abci.OfferSnapshotResponse, error) { return &abci.OfferSnapshotResponse{}, nil } func (Service) ApplySnapshotChunk( context.Context, *abci.ApplySnapshotChunkRequest, ) (*abci.ApplySnapshotChunkResponse, error) { return &abci.ApplySnapshotChunkResponse{}, nil } func (Service) ExtendVote( context.Context, *abci.ExtendVoteRequest, ) (*abci.ExtendVoteResponse, error) { return &abci.ExtendVoteResponse{}, nil } func (Service) VerifyVoteExtension( context.Context, *abci.VerifyVoteExtensionRequest, ) (*abci.VerifyVoteExtensionResponse, error) { return &abci.VerifyVoteExtensionResponse{}, nil } func (*Service) CheckTx( context.Context, *abci.CheckTxRequest, ) (*abci.CheckTxResponse, error) { return &abci.CheckTxResponse{}, nil } ================================================ FILE: consensus/cometbft/service/abci_utils.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package cometbft import ( "strings" errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // NOTE: Partially copied from: https://github.com/cosmos/cosmos-sdk/blob/960d44842b9e313cbe762068a67a894ac82060ab/baseapp/abci.go#L1098 func (s *Service) handleQueryStore(path []string, req *abci.QueryRequest) abci.QueryResponse { queryable, ok := s.sm.GetCommitMultiStore().(storetypes.Queryable) if !ok { return queryResult( errorsmod.Wrap(sdkerrors.ErrUnknownRequest, "multi-store does not support queries"), ) } req.Path = "/" + strings.Join(path[1:], "/") // req.Path == "/beacon" if req.Height <= 1 && req.Prove { return queryResult( errorsmod.Wrap( sdkerrors.ErrInvalidRequest, "cannot query with proof when height <= 1; please provide a valid height", )) } sdkReq := storetypes.RequestQuery(*req) resp, err := queryable.Query(&sdkReq) if err != nil { return queryResult(err) } resp.Height = req.Height return abci.QueryResponse(*resp) } // NOTE: Copied from here: https://github.com/cosmos/cosmos-sdk/blob/960d44842b9e313cbe762068a67a894ac82060ab/baseapp/errors.go#L37-L46. // This was made public in v0.53, under the sdkerrors module. // NOTE: the debug parameter has been removed since Service does not expose this functionality. // // queryResult returns a ResponseQuery from an error. It will try to parse ABCI // info from the error. func queryResult(err error) abci.QueryResponse { space, code, log := errorsmod.ABCIInfo(err, false) return abci.QueryResponse{ Codespace: space, Code: code, Log: log, } } // NOTE: Copied from here: https://github.com/cosmos/cosmos-sdk/blob/960d44842b9e313cbe762068a67a894ac82060ab/baseapp/abci.go#L1153-L1165 // // splitABCIQueryPath splits a string path using the delimiter '/'. // // e.g. "this/is/funny" becomes []string{"this", "is", "funny"} func splitABCIQueryPath(requestPath string) []string { path := strings.Split(requestPath, "/") // first element is empty string if len(path) > 0 && path[0] == "" { path = path[1:] } return path } ================================================ FILE: consensus/cometbft/service/cache/cache.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package cache import ( "errors" "fmt" "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" lru "github.com/hashicorp/golang-lru/v2" ) // TelemetrySink is an interface for recording metrics. type TelemetrySink interface { // SetGauge sets a gauge metric to the specified value. SetGauge(key string, value int64, args ...string) } const minActivationHeight = 2 func IsStateCachingActive(cfg delay.ConfigGetter, height math.Slot) bool { // We choose to activate caching only after stable block time is activated // so to avoid rushes of blocks. In any case however caching cannot be activated // for genesis and first block, which has special handling. activationHeight := math.Slot(max(cfg.SbtConsensusEnableHeight(), minActivationHeight)) //#nosec: G115 return height >= activationHeight } var ( _ States = (*candidateStates)(nil) ErrStateNotFound = errors.New("state not found") ErrNoFinalState = errors.New("no state marked as final") ErrFinalStateIsNil = errors.New("state marked as final is nil") ErrFinalizingUnknownState = errors.New("attempt at finalizing unknown state") ) // States is the interface controlling the caching of state and metadata once a block // has been succeesfully executed once. States assumes that consensus allows no forks, // and that no blocks at height H+1 is ever processed if height H has not been finalized. type States interface { // SetCached allows caching state and metadata once a block has been executed. // It should be called for blocks which successfully pass PrepareProposal. // toCache is simply cached without checks, since CometBFT should guarantee that // blocks are verified at most once. SetCached(hash string, toCache *Element) // GetCached allows retrieval of cached state and metadata. // It should be called by FinalizedBlock to verify whether the block // has already been executed GetCached(hash string) (*Element, error) // MarkAsFinal allows marking one of the cached states as the one to be finalized and committed. // It should be called upon FinalizeBlock to then allow Commit to store the state. // It errs if we attempt to finalize a state which was not previously cached MarkAsFinal(hash string) error // GetFinal allows to retrieve state and stateHash marked as final. // Is should be call by Commit to retrieve the state finalized in FinalizeBlock GetFinal() (string, *State, error) // Reset allows wiping out all the verified states once one of the has been committed Reset() } type Element struct { State *State ValUpdates transition.ValidatorUpdates } type candidateStates struct { states *lru.Cache[string, *Element] finalStateHash *string sink TelemetrySink } // New creates a new States cache with the given maximum size and telemetry sink. func New(maxSize int, sink TelemetrySink) States { c, err := lru.New[string, *Element](maxSize) if err != nil { panic(fmt.Errorf("failed to create candidate states cache: %w", err)) } return &candidateStates{ states: c, finalStateHash: nil, sink: sink, } } func (cs *candidateStates) SetCached(hash string, toCache *Element) { cs.states.Add(hash, toCache) } func (cs *candidateStates) GetCached(hash string) (*Element, error) { cached, found := cs.states.Get(hash) if !found { return nil, ErrStateNotFound } return cached, nil } func (cs *candidateStates) MarkAsFinal(hash string) error { if !cs.states.Contains(hash) { return ErrFinalizingUnknownState } cs.finalStateHash = &hash return nil } func (cs *candidateStates) GetFinal() (string, *State, error) { if cs.finalStateHash == nil { return "", nil, ErrNoFinalState } cached, found := cs.states.Get(*cs.finalStateHash) if !found { return "", nil, ErrFinalStateIsNil } return *cs.finalStateHash, cached.State, nil } func (cs *candidateStates) Reset() { cs.sink.SetGauge("beacon_kit.comet.cached_states_size_at_reset", int64(cs.states.Len())) cs.states.Purge() cs.finalStateHash = nil } ================================================ FILE: consensus/cometbft/service/cache/cache_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cache_test import ( "errors" "fmt" "testing" "github.com/berachain/beacon-kit/consensus/cometbft/service/cache" ) const maxCachedStates = 10 // mockTelemetrySink is a simple mock for testing. type mockTelemetrySink struct { lastGaugeKey string lastGaugeValue int64 } func (m *mockTelemetrySink) SetGauge(key string, value int64, _ ...string) { m.lastGaugeKey = key m.lastGaugeValue = value } func TestCandidateStates_BasicOperations(t *testing.T) { t.Parallel() sink := &mockTelemetrySink{} c := cache.New(maxCachedStates, sink) // Test SetCached and GetCached elem := &cache.Element{State: &cache.State{}} c.SetCached("test-hash", elem) got, err := c.GetCached("test-hash") if err != nil { t.Fatalf("unexpected error: %v", err) } if got != elem { t.Error("retrieved element does not match stored element") } // Test GetCached for non-existent key _, err = c.GetCached("non-existent") if !errors.Is(err, cache.ErrStateNotFound) { t.Errorf("expected ErrStateNotFound, got: %v", err) } // Test MarkAsFinal err = c.MarkAsFinal("test-hash") if err != nil { t.Fatalf("unexpected error marking as final: %v", err) } // Test MarkAsFinal for non-existent key err = c.MarkAsFinal("non-existent") if !errors.Is(err, cache.ErrFinalizingUnknownState) { t.Errorf("expected ErrFinalizingUnknownState, got: %v", err) } // Test GetFinal hash, state, err := c.GetFinal() if err != nil { t.Fatalf("unexpected error getting final: %v", err) } if hash != "test-hash" { t.Errorf("expected hash 'test-hash', got: %s", hash) } if state != elem.State { t.Error("final state does not match expected state") } // Test Reset c.Reset() // Verify the metric was recorded with correct size (1 element was in cache) if sink.lastGaugeKey != "beacon_kit.comet.cached_states_size_at_reset" { t.Errorf("expected gauge key 'beacon_kit.comet.cached_states_size_at_reset', got: %s", sink.lastGaugeKey) } if sink.lastGaugeValue != 1 { t.Errorf("expected gauge value 1, got: %d", sink.lastGaugeValue) } _, err = c.GetCached("test-hash") if !errors.Is(err, cache.ErrStateNotFound) { t.Error("expected cache to be empty after reset") } _, _, err = c.GetFinal() if !errors.Is(err, cache.ErrNoFinalState) { t.Errorf("expected ErrNoFinalState after reset, got: %v", err) } } func TestCandidateStates_BoundedSize(t *testing.T) { t.Parallel() sink := &mockTelemetrySink{} c := cache.New(maxCachedStates, sink) // Add more entries than maxCachedStates for i := range maxCachedStates + 5 { hash := fmt.Sprintf("hash-%d", i) c.SetCached(hash, &cache.Element{}) } // Verify oldest entries were evicted (LRU behavior) for i := range 5 { hash := fmt.Sprintf("hash-%d", i) _, err := c.GetCached(hash) if !errors.Is(err, cache.ErrStateNotFound) { t.Errorf("expected hash-%d to be evicted, but it was found", i) } } // Verify newest entries are still present for i := 5; i < maxCachedStates+5; i++ { hash := fmt.Sprintf("hash-%d", i) _, err := c.GetCached(hash) if err != nil { t.Errorf("expected hash-%d to be present, got error: %v", i, err) } } } ================================================ FILE: consensus/cometbft/service/cache/state.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cache import ( "sync" storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) type State struct { ms storetypes.CacheMultiStore mtx sync.RWMutex ctx sdk.Context } func NewState(ms storetypes.CacheMultiStore, ctx sdk.Context) *State { return &State{ ms: ms, ctx: ctx, } } // CacheMultiStore calls and returns a CacheMultiStore on the state's underling // CacheMultiStore. func (st *State) CacheMultiStore() storetypes.CacheMultiStore { return st.ms.CacheMultiStore() } // SetContext updates the state's context to the context provided. func (st *State) SetContext(ctx sdk.Context) { st.mtx.Lock() defer st.mtx.Unlock() st.ctx = ctx } // Context returns the Context of the state. func (st *State) Context() sdk.Context { st.mtx.RLock() defer st.mtx.RUnlock() return st.ctx } func (st *State) Write() { st.ms.Write() } ================================================ FILE: consensus/cometbft/service/commit.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package cometbft import ( "fmt" "cosmossdk.io/store/rootmulti" cmtabci "github.com/cometbft/cometbft/abci/types" ) func (s *Service) commit( *cmtabci.CommitRequest, ) (*cmtabci.CommitResponse, error) { _, finalState, err := s.cachedStates.GetFinal() if err != nil { // This is unexpected since CometBFT should call Commit only // after FinalizeBlock has been called. Panic appeases nilaway. panic(fmt.Errorf("commit: %w", err)) } header := finalState.Context().BlockHeader() retainHeight := s.GetBlockRetentionHeight(header.Height) rms, ok := s.sm.GetCommitMultiStore().(*rootmulti.Store) if ok { rms.SetCommitHeader(header) } s.sm.GetCommitMultiStore().Commit() s.cachedStates.Reset() if s.blockDelay != nil { if err = s.sm.SaveBlockDelay(s.blockDelay.ToBytes()); err != nil { panic(fmt.Errorf("failed to save block delay: %w", err)) } } return &cmtabci.CommitResponse{ RetainHeight: retainHeight, }, nil } // GetBlockRetentionHeight returns the height for which all blocks below this // height // are pruned from CometBFT. Given a commitment height and a non-zero local // minRetainBlocks configuration, the retentionHeight is the smallest height // that // satisfies: // // - Unbonding (safety threshold) time: The block interval in which validators // can be economically punished for misbehavior. Blocks in this interval must be // auditable e.g. by the light client. // // - Logical store snapshot interval: The block interval at which the underlying // logical store database is persisted to disk, e.g. every 10000 heights. Blocks // since the last IAVL snapshot must be available for replay on application // restart. // // - State sync snapshots: Blocks since the oldest available snapshot must be // available for state sync nodes to catch up (oldest because a node may be // restoring an old snapshot while a new snapshot was taken). // // - Local (minRetainBlocks) config: Archive nodes may want to retain more or // all blocks, e.g. via a local config option min-retain-blocks. There may also // be a need to vary retention for other nodes, e.g. sentry nodes which do not // need historical blocks. func (s *Service) GetBlockRetentionHeight(commitHeight int64) int64 { // pruning is disabled if minRetainBlocks is zero if s.minRetainBlocks == 0 { return 0 } minNonZero := func(x, y int64) int64 { switch { case x == 0: return y case y == 0: return x case x < y: return x default: return y } } // Define retentionHeight as the minimum value that satisfies all non-zero // constraints. All blocks below (commitHeight-retentionHeight) are pruned // from CometBFT. var retentionHeight int64 // Define the number of blocks needed to protect against misbehaving // validators // which allows light clients to operate safely. Note, we piggy back of the // evidence parameters instead of computing an estimated number of blocks // based // on the unbonding period and block commitment time as the two should be // equivalent. if _, _, err := s.cachedStates.GetFinal(); err != nil { return 0 } cp := s.cmtConsensusParams.ToProto() if cp.Evidence != nil && cp.Evidence.MaxAgeNumBlocks > 0 { retentionHeight = commitHeight - cp.Evidence.MaxAgeNumBlocks } v := commitHeight - int64(s.minRetainBlocks) // #nosec G115 retentionHeight = minNonZero(retentionHeight, v) if retentionHeight <= 0 { // prune nothing in the case of a non-positive height return 0 } return retentionHeight } ================================================ FILE: consensus/cometbft/service/configs.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package cometbft import ( "errors" "fmt" "time" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/log" cmtcfg "github.com/cometbft/cometbft/config" cmttypes "github.com/cometbft/cometbft/types" ) const ( // appeases mnd // These timeouts are the ones we tested are necessary // at minimum to have a smooth network. We enforce that // these minima are respected. minTimeoutPropose = 2000 * time.Millisecond minTimeoutPrevote = 2000 * time.Millisecond minTimeoutPrecommit = 2000 * time.Millisecond maxBlockSize = 100 * 1024 * 1024 precision = 505 * time.Millisecond messageDelay = 15 * time.Second defaultMaxNumInboundPeers = 40 defaultMaxNumOutboundPeers = 10 ) var ( ErrInvalidaConfig = errors.New("invalid comet config for BeaconKit") ErrInvalidaConsensusParams = errors.New("invalid comet consensus params for BeaconKit") ) // DefaultConfig returns the default configuration for the CometBFT // consensus engine. It overrides a few values based on our own measurements // and development level of BeaconKit. Recall that these are node-specific // values (although they influence consensus). // This should be the only place in the entire BeaconKit codebase where // cmtcfg.DefaultConfig() is called. func DefaultConfig() *cmtcfg.Config { cfg := cmtcfg.DefaultConfig() // BeaconKit forces PebbleDB as the database backend. cfg.BaseConfig.DBBackend = "pebbledb" // These settings are set by default for performance reasons. cfg.P2P.MaxNumInboundPeers = defaultMaxNumInboundPeers cfg.P2P.MaxNumOutboundPeers = defaultMaxNumOutboundPeers cfg.Mempool.Type = "nop" cfg.Mempool.Recheck = false cfg.Mempool.RecheckTimeout = 0 cfg.Mempool.Broadcast = false cfg.Mempool.Size = 0 cfg.Mempool.MaxTxBytes = 0 cfg.Mempool.MaxTxsBytes = 0 cfg.Mempool.CacheSize = 0 // By default, we set timeouts to the minima we tested consensus := cfg.Consensus consensus.TimeoutPropose = minTimeoutPropose consensus.TimeoutPrevote = minTimeoutPrevote consensus.TimeoutPrecommit = minTimeoutPrecommit //nolint:staticcheck // setting to zero because it's deprecated consensus.TimeoutCommit = 0 cfg.Storage.DiscardABCIResponses = true cfg.TxIndex.Indexer = "null" cfg.Instrumentation.Prometheus = true cfg.Instrumentation.MaxOpenConnections = 800 // Disable profiling by default // cfg.RPC.PprofListenAddress = "localhost:6060" if err := cfg.ValidateBasic(); err != nil { panic(fmt.Errorf("invalid comet config: %w", err)) } return cfg } // DefaultConsensusParams returns the default consensus parameters // shared by every node in the network. Consensus parameters are // inscripted in genesis. func DefaultConsensusParams(consensusKeyAlgo string, cs chain.Spec) *cmttypes.ConsensusParams { res := cmttypes.DefaultConsensusParams() res.Validator.PubKeyTypes = []string{consensusKeyAlgo} // set max block size in order to accommodate max blobs size // This matches current cmttypes.MaxBlockSizeBytes but it's // explicitly hard coded for safety across deps upgrades. res.Block.MaxBytes = maxBlockSize // activate pbst and hard code values to // be safe across dependencies upgrades res.Feature.PbtsEnableHeight = 1 res.Synchrony.Precision = precision res.Synchrony.MessageDelay = messageDelay res.Feature.SBTEnableHeight = cs.SbtConsensusEnableHeight() if err := res.ValidateBasic(); err != nil { panic(fmt.Errorf("invalid default consensus parameters: %w", err)) } return res } func validateConfig(cfg *cmtcfg.Config) error { if cfg.Consensus.TimeoutPropose < minTimeoutPropose { return fmt.Errorf("%w, config timeout propose %v, min requested %v", ErrInvalidaConfig, cfg.Consensus.TimeoutPropose, minTimeoutPropose, ) } if cfg.Consensus.TimeoutPrevote < minTimeoutPrevote { return fmt.Errorf("%w, config timeout prevote %v, min requested %v", ErrInvalidaConfig, cfg.Consensus.TimeoutPrevote, minTimeoutPrevote, ) } if cfg.Consensus.TimeoutPrecommit < minTimeoutPrecommit { return fmt.Errorf("%w, config timeout propose %v, min requested %v", ErrInvalidaConfig, cfg.Consensus.TimeoutPrecommit, minTimeoutPrecommit, ) } return nil } func warnAboutConfigs( cmtCfg *cmtcfg.Config, logger log.Logger, ) { connectionsCap := defaultMaxNumInboundPeers + defaultMaxNumOutboundPeers if cmtCfg.P2P.MaxNumInboundPeers+cmtCfg.P2P.MaxNumOutboundPeers > connectionsCap { logger.Warn( "excessive peering", "max_num_inbound_peers", cmtCfg.P2P.MaxNumInboundPeers, "recommended max_num_inbound_peers", defaultMaxNumInboundPeers, "max_num_outbound_peers", cmtCfg.P2P.MaxNumOutboundPeers, "recommended max_num_outbound_peers", defaultMaxNumOutboundPeers, "recommended connections cap (inbound + outbound)", connectionsCap, ) } } // extractConsensusParams pull consensus parameters (not config) set in // genesis. They are mostly used to (not) update consensus parameters once // a block is finalized. func extractConsensusParams(cmtCfg *cmtcfg.Config) (*cmttypes.ConsensusParams, error) { genFunc := GetGenDocProvider(cmtCfg) genDoc, err := genFunc() if err != nil { return nil, fmt.Errorf("failed pulling consensus params: %w", err) } // Todo: add validation for genesis params by chainID cmtConsensusParams := genDoc.GenesisDoc.ConsensusParams return cmtConsensusParams, validateConsensusParams(cmtConsensusParams) } func validateConsensusParams(params *cmttypes.ConsensusParams) error { if params.Block.MaxBytes < maxBlockSize { return fmt.Errorf("%w, param max size %v, requested size %v", ErrInvalidaConsensusParams, params.Block.MaxBytes, maxBlockSize, ) } return nil } ================================================ FILE: consensus/cometbft/service/configs_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package cometbft_test import ( "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/primitives/crypto" cmttypes "github.com/cometbft/cometbft/types" "github.com/stretchr/testify/require" ) func TestSBTEnableHeightAlignedWithChainSpecs(t *testing.T) { t.Parallel() tests := []struct { name string getChainSpecs func(t *testing.T) chain.Spec }{ { name: "mainnet", getChainSpecs: func(t *testing.T) chain.Spec { t.Helper() cs, err := spec.MainnetChainSpec() require.NoError(t, err) return cs }, }, { name: "testnet", getChainSpecs: func(t *testing.T) chain.Spec { t.Helper() cs, err := spec.TestnetChainSpec() require.NoError(t, err) return cs }, }, { name: "devnet", getChainSpecs: func(t *testing.T) chain.Spec { t.Helper() cs, err := spec.DevnetChainSpec() require.NoError(t, err) return cs }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() cs := tt.getChainSpecs(t) var cp *cmttypes.ConsensusParams require.NotPanics(t, func() { cp = cometbft.DefaultConsensusParams(crypto.CometBLSType, cs) }) // Make sure that the Enable Height in consensus parameters matches with // chain spec one. This is relevant to make sure that consensus parameters // are well set when chain spec is modified and genesis is regenerated. require.Equal(t, cp.Feature.SBTEnableHeight, cs.SbtConsensusEnableHeight()) }) } } ================================================ FILE: consensus/cometbft/service/delay/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package delay import ( "math" "time" ) const ( // maxDelayBetweenBlocks is the maximum delay between two consecutive blocks. // If the last block time minus the previous block time is greater than // maxDelayBetweenBlocks, then we reset `FinalizeBlockResponse.NextBlockDelay` // to default. // // This is needed because the network may stall for a long time and we don't // want to rush in new blocks as the network resumes its operation. maxDelayBetweenBlocks = 5 * time.Minute // targetBlockTime is the desired block time. // // Note that it CAN'T be lower than the minimal (floor) block time in the // network, which is comprised of the time to a) propose a new block b) // gather 2/3+ prevotes c) gather 2/3+ precommits. targetBlockTime = 2 * time.Second // Delay to use before the upgrade to SBT. constBlockDelay = 500 * time.Millisecond // Height to enable SBT. Changes will be applied in the next block after this sbtEnableHeight = math.MaxInt64 // Height at which consensus params are upgraded to use SBT sbtConsensusParamUpdate = 0 // Until `timeout_commit` is removed from the CometBFT config, // `FinalizeBlockResponse.NextBlockDelay` can't be exactly 0. If it's set to // 0, then `timeout_commit` from the config will be used, which is not what // we want since we're trying to control the block time. noDelay = 1 * time.Microsecond ) type ConfigGetter interface { SbtMaxBlockDelay() time.Duration SbtTargetBlockTime() time.Duration SbtConstBlockDelay() time.Duration SbtConsensusUpdateHeight() int64 SbtConsensusEnableHeight() int64 } type Config struct { MaxBlockDelay time.Duration `mapstructure:"max-block-delay"` TargetBlockTime time.Duration `mapstructure:"target-block-time"` ConstBlockDelay time.Duration `mapstructure:"const-block-delay"` // ConsensusParamUpdate decides the height where we set the ConsensusEnableHeight // In turn ConsensusEnableHeight, initializes the BlockDelay struct which will then // be used to calculate block delay in the next height. ConsensusUpdateHeight int64 `mapstructure:"consensus-update-height"` ConsensusEnableHeight int64 `mapstructure:"consensus-enable-height"` } func DefaultConfig() Config { return Config{ MaxBlockDelay: maxDelayBetweenBlocks, TargetBlockTime: targetBlockTime, ConstBlockDelay: constBlockDelay, ConsensusUpdateHeight: sbtConsensusParamUpdate, ConsensusEnableHeight: sbtEnableHeight, } } func (c Config) SbtMaxBlockDelay() time.Duration { return c.MaxBlockDelay } func (c Config) SbtTargetBlockTime() time.Duration { return c.TargetBlockTime } func (c Config) SbtConstBlockDelay() time.Duration { return c.ConstBlockDelay } func (c Config) SbtConsensusUpdateHeight() int64 { return c.ConsensusUpdateHeight } func (c Config) SbtConsensusEnableHeight() int64 { return c.ConsensusEnableHeight } ================================================ FILE: consensus/cometbft/service/delay/delay.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package delay import ( "bytes" "encoding/binary" "fmt" "time" ) // BlockDelay is used to calculate the delay before proposing the next block. // // The general formula is: // // NextBlockTime = InitialTime + TargetBlockTime * (CurrentHeight - InitialHeight) // // Initial Time and Height are reset is the chain stops for too long. type BlockDelay struct { // InitialTime is a checkpoint in time from which we start calculating the // next block time. InitialTime time.Time // InitialHeight is a checkpoint in blockchain's height from which we start // calculating the next block time. InitialHeight int64 // PreviousBlockTime is the time of the previous block. PreviousBlockTime time.Time } // ComputeNext returns the duration to wait before proposing the next block. func (d *BlockDelay) ComputeNext(cfg ConfigGetter, curBlockTime time.Time, curBlockHeight int64) time.Duration { // Reset the initial time and height if the time between blocks is greater // than MaxDelayBetweenBlocks. This makes the current time and height the // initial one as if the upgrade happened just now. if curBlockTime.Sub(d.PreviousBlockTime) > cfg.SbtMaxBlockDelay() { d.InitialTime = curBlockTime d.InitialHeight = curBlockHeight d.PreviousBlockTime = curBlockTime return cfg.SbtTargetBlockTime() } d.PreviousBlockTime = curBlockTime t := d.InitialTime.Add(cfg.SbtTargetBlockTime() * time.Duration(curBlockHeight-d.InitialHeight)) if curBlockTime.Before(t) { nextBlockDelay := t.Sub(curBlockTime) return nextBlockDelay } return noDelay } // FromBytes converts the bytes to a blockDelay. // // Expected format: // // InitialTime (int64) | InitialHeight (int64) | PreviousBlockTime (int64) // (little endian) // // It returns ErrBlockDelayFromBytes if it fails to read from the buffer. func FromBytes(bz []byte) (*BlockDelay, error) { buf := bytes.NewReader(bz) var initialTime, prevBlockTime int64 var initialHeight int64 err := binary.Read(buf, binary.LittleEndian, &initialTime) if err != nil { return nil, &BlockDelayFromBytesError{ field: "InitialTime", err: err, } } err = binary.Read(buf, binary.LittleEndian, &initialHeight) if err != nil { return nil, &BlockDelayFromBytesError{ field: "InitialHeight", err: err, } } err = binary.Read(buf, binary.LittleEndian, &prevBlockTime) if err != nil { return nil, &BlockDelayFromBytesError{ field: "PreviousBlockTime", err: err, } } return &BlockDelay{ InitialTime: time.Unix(0, initialTime), InitialHeight: initialHeight, PreviousBlockTime: time.Unix(0, prevBlockTime), }, nil } // ToBytes converts the blockDelay to bytes. // // Format: // // InitialTime (int64) | InitialHeight (int64) | PreviousBlockTime (int64) // (little endian) // // Panics if it fails to write to the buffer. func (d *BlockDelay) ToBytes() []byte { buf := new(bytes.Buffer) err := binary.Write(buf, binary.LittleEndian, d.InitialTime.UnixNano()) if err != nil { panic(fmt.Sprintf("failed to write InitialTime: %v", err)) } err = binary.Write(buf, binary.LittleEndian, d.InitialHeight) if err != nil { panic(fmt.Sprintf("failed to write InitialHeight: %v", err)) } err = binary.Write(buf, binary.LittleEndian, d.PreviousBlockTime.UnixNano()) if err != nil { panic(fmt.Sprintf("failed to write PreviousBlockTime: %v", err)) } return buf.Bytes() } ================================================ FILE: consensus/cometbft/service/delay/delay_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package delay_test import ( "testing" "time" "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var testCfg = delay.Config{ MaxBlockDelay: 5 * time.Minute, TargetBlockTime: 2 * time.Second, ConstBlockDelay: 500 * time.Millisecond, } func TestBlockDelayFromBytes(t *testing.T) { t.Parallel() d1 := &delay.BlockDelay{ InitialTime: time.Now().Add(-10 * time.Minute), InitialHeight: 5, PreviousBlockTime: time.Now().Add(-5 * time.Minute), } b := d1.ToBytes() d2, err := delay.FromBytes(b) require.NoError(t, err) assert.Equal(t, d1.InitialTime.Unix(), d2.InitialTime.Unix()) assert.Equal(t, d1.InitialHeight, d2.InitialHeight) assert.Equal(t, d1.PreviousBlockTime.Unix(), d2.PreviousBlockTime.Unix()) } func TestBlockDelayNext_NoDelay(t *testing.T) { t.Parallel() genesisTime := time.Now() initialHeight := int64(1) d := &delay.BlockDelay{ InitialTime: genesisTime, InitialHeight: initialHeight, PreviousBlockTime: genesisTime, } curBlockTime := genesisTime.Add(10 * time.Second) curBlockHeight := int64(2) delay := d.ComputeNext(testCfg, curBlockTime, curBlockHeight) assert.Equal(t, 1*time.Microsecond, delay) // InitialTime/Height are not updated, PreviousBlockTime is updated assert.Equal(t, genesisTime, d.InitialTime) assert.Equal(t, initialHeight, d.InitialHeight) assert.Equal(t, curBlockTime, d.PreviousBlockTime) } func TestBlockDelayNext_WithDelay(t *testing.T) { t.Parallel() genesisTime := time.Now() initialHeight := int64(1) d := &delay.BlockDelay{ InitialTime: genesisTime, InitialHeight: initialHeight, PreviousBlockTime: genesisTime, } curBlockTime := genesisTime.Add(2 * time.Second) curBlockHeight := int64(3) delay := d.ComputeNext(testCfg, curBlockTime, curBlockHeight) assert.Equal(t, 2*time.Second, delay) // InitialTime/Height are not updated, PreviousBlockTime is updated assert.Equal(t, genesisTime, d.InitialTime) assert.Equal(t, initialHeight, d.InitialHeight) assert.Equal(t, curBlockTime, d.PreviousBlockTime) } func TestBlockDelayNext_ResetOnStall(t *testing.T) { t.Parallel() genesisTime := time.Now() initialHeight := int64(1) d := &delay.BlockDelay{ InitialTime: genesisTime, InitialHeight: initialHeight, PreviousBlockTime: genesisTime, } curBlockTime := genesisTime.Add(testCfg.MaxBlockDelay + 1*time.Minute) curBlockHeight := int64(10) nextBlockDelay := d.ComputeNext(testCfg, curBlockTime, curBlockHeight) assert.Equal(t, d.InitialTime, curBlockTime) assert.Equal(t, d.InitialHeight, curBlockHeight) assert.Equal(t, testCfg.TargetBlockTime, nextBlockDelay) } func TestBlockDelayNext_Catchup(t *testing.T) { t.Parallel() genesisTime := time.Now() initialHeight := int64(1) d := &delay.BlockDelay{ InitialTime: genesisTime, InitialHeight: initialHeight, PreviousBlockTime: genesisTime, } curBlockTime := genesisTime.Add(2 * time.Second) curBlockHeight := int64(3) delay := d.ComputeNext(testCfg, curBlockTime, curBlockHeight) assert.Equal(t, 2*time.Second, delay) // Ideal // height 4 -> 3*2 = 6 // height 5 -> 4*2 = 8 // height 6 -> 5*2 = 10 // height 7 -> 6*2 = 12 curBlockHeight++ curBlockTime = genesisTime.Add(8 * time.Second) // T(h4) = 8s // delay = 1us // T(h5 = 9s) // delay = 1us // T(h6) = 10s // delay = 1us // T(h7) = 11s // delay = 1 delay = d.ComputeNext(testCfg, curBlockTime, curBlockHeight) assert.Equal(t, 1*time.Microsecond, delay) for curBlockHeight++; curBlockHeight < 7; curBlockHeight++ { curBlockTime = curBlockTime.Add(1 * time.Second) delay = d.ComputeNext(testCfg, curBlockTime, curBlockHeight) assert.Equal(t, 1*time.Microsecond, delay) } curBlockTime = curBlockTime.Add(1 * time.Second) delay = d.ComputeNext(testCfg, curBlockTime, curBlockHeight) assert.Equal(t, 1*time.Second, delay) } ================================================ FILE: consensus/cometbft/service/delay/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package delay import "fmt" // BlockDelayFromBytesError is returned when the block delay can't be read from // the buffer. type BlockDelayFromBytesError struct { field string err error } func (e *BlockDelayFromBytesError) Error() string { return fmt.Sprintf("%s: %v", e.field, e.err) } func (e *BlockDelayFromBytesError) Unwrap() error { return e.err } ================================================ FILE: consensus/cometbft/service/encoding/encoding.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package encoding import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/ssz" ) // ExtractBlobsAndBlockFromRequest extracts the blobs and block from an ABCI // request. func ExtractBlobsAndBlockFromRequest( req ABCIRequest, beaconBlkIndex uint, blobSidecarsIndex uint, forkVersion common.Version, ) (*ctypes.SignedBeaconBlock, datypes.BlobSidecars, error) { if req == nil { return nil, nil, ErrNilABCIRequest } blk, err := UnmarshalBeaconBlockFromABCIRequest( req.GetTxs(), beaconBlkIndex, forkVersion, ) if err != nil { return nil, nil, err } blobs, err := UnmarshalBlobSidecarsFromABCIRequest( req.GetTxs(), blobSidecarsIndex, ) return blk, blobs, err } // UnmarshalBeaconBlockFromABCIRequest extracts a beacon block from an ABCI // request. func UnmarshalBeaconBlockFromABCIRequest( txs [][]byte, bzIndex uint, forkVersion common.Version, ) (*ctypes.SignedBeaconBlock, error) { var signedBlk *ctypes.SignedBeaconBlock lenTxs := uint(len(txs)) // Ensure there are transactions in the request and that the request is // valid. if txs == nil || lenTxs == 0 { return signedBlk, ErrNoBeaconBlockInRequest } if bzIndex >= lenTxs { return signedBlk, ErrBzIndexOutOfBounds } // Extract the beacon block from the ABCI request. blkBz := txs[bzIndex] if blkBz == nil { return signedBlk, ErrNilBeaconBlockInRequest } block, err := ctypes.NewEmptySignedBeaconBlockWithVersion(forkVersion) if err != nil { return nil, fmt.Errorf("attempt at building block with wrong version %s: %w", forkVersion, err) } if err = ssz.Unmarshal(blkBz, block); err != nil { return nil, err } return block, nil } // UnmarshalBlobSidecarsFromABCIRequest extracts blob sidecars from an ABCI // request. func UnmarshalBlobSidecarsFromABCIRequest( txs [][]byte, bzIndex uint, ) (datypes.BlobSidecars, error) { if len(txs) == 0 || bzIndex >= uint(len(txs)) { return nil, ErrNoBlobSidecarInRequest } sidecarBz := txs[bzIndex] if sidecarBz == nil { return nil, ErrNilBlobSidecarInRequest } var sidecars datypes.BlobSidecars if err := ssz.Unmarshal(sidecarBz, &sidecars); err != nil { return nil, err } return sidecars, nil } ================================================ FILE: consensus/cometbft/service/encoding/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package encoding import "github.com/berachain/beacon-kit/errors" var ( // ErrNilBeaconBlockInRequest is an error for when // the beacon block in an abci request is nil. ErrNilBeaconBlockInRequest = errors.New("nil beacon block in abci request") // ErrNoBeaconBlockInRequest is an error for when // there is no beacon block in an abci request. ErrNoBeaconBlockInRequest = errors.New("no beacon block in abci request") // ErrNilBlobSidecarInRequest is an error for when // the blob sidecar in an abci request is nil. ErrNilBlobSidecarInRequest = errors.New("nil blob sidecar in abci request") // ErrNoBlobSidecarInRequest is an error for when // there is no blob sidecar in an abci request. ErrNoBlobSidecarInRequest = errors.New("no blob sidecar in abci request") // ErrBzIndexOutOfBounds is an error for when the index // is out of bounds. ErrBzIndexOutOfBounds = errors.New("bzIndex out of bounds") // ErrNilABCIRequest is an error for when the abci request // is nil. ErrNilABCIRequest = errors.New("nil abci request") // ErrInvalidType is an error for when the type is invalid. ErrInvalidType = errors.New("invalid type") ) ================================================ FILE: consensus/cometbft/service/encoding/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package encoding import "time" // ABCIRequest represents the interface for an ABCI request. type ABCIRequest interface { // GetTxs returns the transactions included in the request. GetTxs() [][]byte GetTime() time.Time } ================================================ FILE: consensus/cometbft/service/finalize_block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "context" "errors" "fmt" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/cache" "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/transition" cmtabci "github.com/cometbft/cometbft/abci/types" "github.com/sourcegraph/conc/iter" ) func (s *Service) finalizeBlock( ctx context.Context, req *cmtabci.FinalizeBlockRequest, ) (*cmtabci.FinalizeBlockResponse, error) { if err := s.validateFinalizeBlockHeight(req); err != nil { return nil, err } // Check whether currently block hash is already available. If so // we may speed up block finalization. hash := string(req.Hash) switch cached, err := s.cachedStates.GetCached(hash); { case err == nil: // Block with height equal to initial height is special and we can't rely on its cache. // This is because Genesis state is cached but not committed (and purged from s.cachedStates) // We handle the case outside of this switch, via the s.Blockchain.FinalizeBlock below. if req.Height > s.initialHeight { if err = s.cachedStates.MarkAsFinal(hash); err != nil { return nil, fmt.Errorf("failed marking state as final, hash %s, height %d: %w", hash, req.Height, err) } finalState := cached.State var ( signedBlk *ctypes.SignedBeaconBlock sidecars datypes.BlobSidecars ) signedBlk, sidecars, err = s.Blockchain.ParseBeaconBlock(req) if err != nil { return nil, fmt.Errorf("finalize block: failed parsing block: %w", err) } blk := signedBlk.GetBeaconBlock() if err = s.Blockchain.FinalizeSidecars( finalState.Context(), req.SyncingToHeight, blk, sidecars, ); err != nil { return nil, fmt.Errorf("failed finalizing sidecars: %w", err) } if err = s.Blockchain.PostFinalizeBlockOps( finalState.Context(), blk, ); err != nil { return nil, fmt.Errorf("finalize block: failed post finalize block ops: %w", err) } return s.calculateFinalizeBlockResponse(req, cached.ValUpdates) } case errors.Is(err, cache.ErrStateNotFound): // this is a benign error, it just signal it's the first time we see the block being finalized // Keep processing below default: return nil, fmt.Errorf("failed checking cached state, hash %s, height %d: %w", hash, req.Height, err) } // Block has not been cached already, as it happens when we block sync. // Normally we would directly process it but first block post initial height // needs special handling. var finalState *cache.State cachedFinalHash, cachedFinalState, err := s.cachedStates.GetFinal() switch { case errors.Is(err, cache.ErrNoFinalState): hash = string(req.Hash) // not necessary but clarifies intent finalState = s.resetState(ctx) case err == nil: hash = cachedFinalHash finalState = cachedFinalState // Preserve the CosmosSDK context while using the correct base ctx. finalState.SetContext(finalState.Context().WithContext(ctx)) default: return nil, fmt.Errorf("failed checking cached final state, hash %s, height %d: %w", hash, req.Height, err) } valUpdates, err := s.Blockchain.FinalizeBlock(finalState.Context(), req) if err != nil { return nil, err } // Cache and mark state as final s.cachedStates.SetCached(hash, &cache.Element{ State: finalState, ValUpdates: valUpdates, }) if err = s.cachedStates.MarkAsFinal(hash); err != nil { return nil, fmt.Errorf("failed marking state as final, hash %s, height %d: %w", hash, req.Height, err) } return s.calculateFinalizeBlockResponse(req, valUpdates) } func (s *Service) nextBlockDelay(req *cmtabci.FinalizeBlockRequest) time.Duration { // c0. SBT is not enabled => use the old block delay. if s.cmtConsensusParams.Feature.SBTEnableHeight <= 0 { return s.delayCfg.SbtConstBlockDelay() } // c1. current height < SBTEnableHeight => wait for the upgrade. if req.Height < s.cmtConsensusParams.Feature.SBTEnableHeight { return s.delayCfg.SbtConstBlockDelay() } // c2. current height == SBTEnableHeight => initialize the block delay. if req.Height == s.cmtConsensusParams.Feature.SBTEnableHeight { s.blockDelay = &delay.BlockDelay{ InitialTime: req.Time, InitialHeight: req.Height, PreviousBlockTime: req.Time, } return s.delayCfg.SbtConstBlockDelay() } // c3. current height > SBTEnableHeight // c3.1 // // The upgrade was successfully applied and the block delay is set. if s.blockDelay != nil { prevBlkTime := s.blockDelay.PreviousBlockTime // note it down before ComputeNext changes it delay := s.blockDelay.ComputeNext(s.delayCfg, req.Time, req.Height) s.logger.Debug("Stable block time", "previous block time", prevBlkTime.String(), "current block time", req.Time.String(), "next delay", delay.String(), ) return delay } // c3.2 // // Looks like we've skipped SBTEnableHeight (probably restoring from the // snapshot) => panic. panic( fmt.Sprintf( "nil block delay at height %d past SBTEnableHeight %d. This is only possible w/ statesync, which is not supported by SBT atm", req.Height, s.cmtConsensusParams.Feature.SBTEnableHeight, ), ) } // workingHash gets the apphash that will be finalized in commit. // These writes will be persisted to the root multi-store // (s.smGet.CommitMultiStore()) and flushed to disk in the // Commit phase. This means when the ABCI client requests // Commit(), the application state transitions will be flushed // to disk and as a result, but we already have an application // Merkle root. func (s *Service) workingHash() []byte { // Write the FinalizeBlock state into branched storage and commit the // MultiStore. The write to the FinalizeBlock state writes all state // transitions to the root MultiStore (s.sm.GetCommitMultiStore()) // so when Commit() is called it persists those values. _, finalState, err := s.cachedStates.GetFinal() if err != nil { // this is unexpected since workingHash is called only after // internalFinalizeBlock. Panic appeases nilaway. panic(fmt.Errorf("workingHash: %w", err)) } finalState.Write() // Get the hash of all writes in order to return the apphash to the comet in // finalizeBlock. commitHash := s.sm.GetCommitMultiStore().WorkingHash() s.logger.Debug( "hash of all writes", "workingHash", fmt.Sprintf("%X", commitHash), ) return commitHash } func (s *Service) validateFinalizeBlockHeight(req *cmtabci.FinalizeBlockRequest) error { if req.Height < 1 { return fmt.Errorf( "finalizeBlock at height %v: %w", req.Height, errInvalidHeight, ) } lastBlockHeight := s.lastBlockHeight() // expectedHeight holds the expected height to validate var expectedHeight int64 if lastBlockHeight == 0 && s.initialHeight > 1 { // In this case, we're validating the first block of the chain, i.e no // previous commit. The height we're expecting is the initial height. expectedHeight = s.initialHeight } else { // This case can mean two things: // // - Either there was already a previous commit in the store, in which // case we increment the version from there. // - Or there was no previous commit, in which case we start at version // 1. expectedHeight = lastBlockHeight + 1 } if req.Height != expectedHeight { return fmt.Errorf( "invalid height: %d; expected: %d", req.Height, expectedHeight, ) } return nil } func (s *Service) calculateFinalizeBlockResponse( req *cmtabci.FinalizeBlockRequest, valUpdates transition.ValidatorUpdates, ) (*cmtabci.FinalizeBlockResponse, error) { // Update Stable block time related data if s.cmtConsensusParams.Feature.SBTEnableHeight == 0 && req.Height == s.delayCfg.SbtConsensusUpdateHeight() { s.cmtConsensusParams.Feature.SBTEnableHeight = s.delayCfg.SbtConsensusEnableHeight() } nextBlockTime := s.nextBlockDelay(req) // This result format is expected by Comet. That actual execution will happen as part of the state transition. txsLen := len(req.Txs) txResults := make([]*cmtabci.ExecTxResult, txsLen) for i := range txsLen { //nolint:mnd // its okay for now. txResults[i] = &cmtabci.ExecTxResult{ Codespace: "sdk", Code: 2, Log: "skip decoding", GasWanted: 0, GasUsed: 0, } } formattedValUpdates, err := iter.MapErr( valUpdates, convertValidatorUpdate[cmtabci.ValidatorUpdate], ) if err != nil { return nil, err } // update sync to height once FinalizeBlock cannot err anymore. s.syncingToHeight = req.SyncingToHeight cp := s.cmtConsensusParams.ToProto() return &cmtabci.FinalizeBlockResponse{ TxResults: txResults, ValidatorUpdates: formattedValUpdates, ConsensusParamUpdates: &cp, AppHash: s.workingHash(), NextBlockDelay: nextBlockTime, }, nil } ================================================ FILE: consensus/cometbft/service/genesis.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "bytes" "crypto/sha256" "encoding/hex" "fmt" "strings" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/json" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cometbft/cometbft/node" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) // DefaultGenesis returns the default genesis state for the application. func (s *Service) DefaultGenesis(spec chain.Spec) map[string]json.RawMessage { // Implement the default genesis state for the application. // This should return a map of module names to their respective default // genesis states. gen := make(map[string]json.RawMessage) defaultGenesis := types.DefaultGenesis(spec.GenesisForkVersion()) var err error gen["beacon"], err = json.Marshal(defaultGenesis) if err != nil { panic(err) } return gen } // ValidateGenesis validates the provided genesis state. func (s *Service) ValidateGenesis( genesisState map[string]json.RawMessage, ) error { // Implemented the validation logic for the provided genesis state. // This should validate the genesis state for each module in the // application. // Validate that required modules are present in genesis. Currently, // only the beacon module is required. beaconGenesisBz, ok := genesisState["beacon"] if !ok { return errors.New( "beacon module genesis state is required but was not found", ) } beaconGenesis := &types.Genesis{} if err := json.Unmarshal(beaconGenesisBz, &beaconGenesis); err != nil { return fmt.Errorf( "failed to unmarshal beacon genesis state: %w", err, ) } if !isValidForkVersion(beaconGenesis.GetForkVersion()) { return fmt.Errorf("invalid fork version format: %s", beaconGenesis.ForkVersion, ) } if err := validateDeposits(beaconGenesis.GetDeposits()); err != nil { return fmt.Errorf("invalid deposits: %w", err) } if err := validateExecutionHeader( beaconGenesis.GetExecutionPayloadHeader(), ); err != nil { return fmt.Errorf("invalid execution payload header: %w", err) } return nil } // validateDeposits performs validation of the provided deposits. // It ensures: // - At least one deposit is present // - No duplicate public keys // Returns an error with details if any validation fails. func validateDeposits(deposits []*types.Deposit) error { if len(deposits) == 0 { return errors.New("at least one deposit is required") } seenPubkeys := make(map[string]struct{}) // In genesis, we have 1:1 mapping between deposits and validators. Hence, // we check for duplicate public key. for i, deposit := range deposits { if deposit == nil { return fmt.Errorf("deposit %d is nil", i) } // Check for duplicate pubkeys pubkeyHex := hex.EncodeToString(deposit.Pubkey[:]) if _, seen := seenPubkeys[pubkeyHex]; seen { return fmt.Errorf("duplicate pubkey found in deposit %d", i) } seenPubkeys[pubkeyHex] = struct{}{} } return nil } // maxExtraDataSize defines the maximum allowed size in bytes for the ExtraData // field in the execution payload header. const maxExtraDataSize = 32 // validateExecutionHeader validates the provided execution payload header // for the genesis block. func validateExecutionHeader(header *types.ExecutionPayloadHeader) error { if header == nil { return errors.New("execution payload header cannot be nil") } // Check block number to be 0 if header.Number != 0 { return errors.New("block number must be 0 for genesis block") } if header.GasLimit == 0 { return errors.New("gas limit cannot be zero") } if header.GasUsed != 0 { return errors.New("gas used must be zero for genesis block") } if header.BaseFeePerGas == nil { return errors.New("base fee per gas cannot be nil") } // Additional Deneb-specific validations for blob gas if header.BlobGasUsed != 0 { return errors.New( "blob gas used must be zero for genesis block", ) } if header.ExcessBlobGas != 0 { return errors.New( "excess blob gas must be zero for genesis block", ) } if header.BlobGasUsed > header.GasLimit { return fmt.Errorf("blob gas used (%d) exceeds gas limit (%d)", header.BlobGasUsed, header.GasLimit, ) } // Validate hash fields are not zero zeroHash := common.ExecutionHash{} emptyTrieRoot := common.Bytes32( common.NewExecutionHashFromHex( "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", )) // For genesis block (when block number is 0), ParentHash must be zero if !bytes.Equal(header.ParentHash[:], zeroHash[:]) { return errors.New("parent hash must be zero for genesis block") } if header.ReceiptsRoot != emptyTrieRoot { return errors.New( "receipts root must be empty trie root for genesis block", ) } if bytes.Equal(header.BlockHash[:], zeroHash[:]) { return errors.New("block hash cannot be zero") } // Validate prevRandao is zero for genesis var zeroBytes32 common.Bytes32 if !bytes.Equal(header.Random[:], zeroBytes32[:]) { return errors.New("prevRandao must be zero for genesis block") } // Fee recipient can be zero in genesis block // No need to validate fee recipient for genesis // We don't validate LogsBloom as it can legitimately be // all zeros in a genesis block or in blocks with no logs // Extra data length check (max 32 bytes) if len(header.ExtraData) > maxExtraDataSize { return fmt.Errorf( "extra data too long: got %d bytes, max 32 bytes", len(header.ExtraData), ) } return nil } const expectedHexLength = 8 // isValidForkVersion returns true if the provided fork version is valid. // A valid fork version must: // - Start with "0x" // - Be followed by exactly 8 hexadecimal characters. func isValidForkVersion(forkVersion common.Version) bool { forkVersionStr := forkVersion.String() if !strings.HasPrefix(forkVersionStr, "0x") { return false } // Remove "0x" prefix and verify remaining characters hexPart := strings.TrimPrefix(forkVersionStr, "0x") // Should have exactly 8 characters after 0x prefix if len(hexPart) != expectedHexLength { return false } // Verify it's a valid hex number _, err := hex.DecodeString(hexPart) return err == nil } // GetGenDocProvider returns a function which returns the genesis doc from the // genesis file. func GetGenDocProvider( cfg *cmtcfg.Config, ) func() (node.ChecksummedGenesisDoc, error) { return func() (node.ChecksummedGenesisDoc, error) { appGenesis, err := genutiltypes.AppGenesisFromFile(cfg.GenesisFile()) if err != nil { return node.ChecksummedGenesisDoc{ Sha256Checksum: []byte{}, }, err } gen, err := appGenesis.ToGenesisDoc() if err != nil { return node.ChecksummedGenesisDoc{ Sha256Checksum: []byte{}, }, err } genbz, err := gen.AppState.MarshalJSON() if err != nil { return node.ChecksummedGenesisDoc{ Sha256Checksum: []byte{}, }, err } bz, err := json.Marshal(genbz) if err != nil { return node.ChecksummedGenesisDoc{ Sha256Checksum: []byte{}, }, err } sum := sha256.Sum256(bz) return node.ChecksummedGenesisDoc{ GenesisDoc: gen, Sha256Checksum: sum[:], }, nil } } ================================================ FILE: consensus/cometbft/service/init_chain.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "context" "fmt" "github.com/berachain/beacon-kit/consensus/cometbft/service/cache" "github.com/berachain/beacon-kit/primitives/encoding/json" cmtabci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/sourcegraph/conc/iter" ) func (s *Service) initChain( ctx context.Context, req *cmtabci.InitChainRequest, ) (*cmtabci.InitChainResponse, error) { if req.ChainId != s.chainID { return nil, fmt.Errorf( "invalid chain-id on InitChain; expected: %s, got: %s", s.chainID, req.ChainId, ) } // Enforce that request validators is zero. This is because Berachain derives the validators directly from // deposits in the genesis file and disregards the validators in genesis file, which is what Comet uses. if len(req.Validators) != 0 { return nil, fmt.Errorf("expected no validators in initChain request but got %d", len(req.Validators)) } var genesisState map[string]json.RawMessage if err := json.Unmarshal(req.AppStateBytes, &genesisState); err != nil { return nil, fmt.Errorf("failed to unmarshal genesis state: %w", err) } // Validate the genesis state. err := s.ValidateGenesis(genesisState) if err != nil { return nil, err } s.logger.Info( "InitChain", "initialHeight", req.InitialHeight, "chainID", req.ChainId, ) // Set the initial height, which will be used to determine if we are // proposing // or processing the first block or not. s.initialHeight = req.InitialHeight if s.initialHeight == 0 { s.initialHeight = 1 } // if req.InitialHeight is > 1, then we set the initial version on all // stores if req.InitialHeight > 1 { if err = s.sm.GetCommitMultiStore(). SetInitialVersion(req.InitialHeight); err != nil { return nil, err } } genesisHash := "" genesisFinalState := s.resetState(ctx) s.cachedStates.SetCached(genesisHash, &cache.Element{ State: genesisFinalState, }) if err = s.cachedStates.MarkAsFinal(genesisHash); err != nil { return nil, err } //nolint:contextcheck // ctx already passed via resetState resValidators, err := s.initChainer( genesisFinalState.Context(), req.AppStateBytes, ) if err != nil { return nil, err } // NOTE: We don't commit, but FinalizeBlock for block InitialHeight starts // from // this FinalizeBlockState. return &cmtabci.InitChainResponse{ ConsensusParams: req.ConsensusParams, Validators: resValidators, AppHash: s.sm.GetCommitMultiStore().LastCommitID().Hash, }, nil } // InitChainer initializes the chain. func (s *Service) initChainer( ctx sdk.Context, appStateBytes []byte, ) ([]cmtabci.ValidatorUpdate, error) { var genesisState map[string]json.RawMessage if err := json.Unmarshal(appStateBytes, &genesisState); err != nil { return nil, err } data := []byte(genesisState["beacon"]) valUpdates, err := s.Blockchain.ProcessGenesisData(ctx, data) if err != nil { return nil, err } return iter.MapErr( valUpdates, convertValidatorUpdate[cmtabci.ValidatorUpdate], ) } ================================================ FILE: consensus/cometbft/service/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "time" ) // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { // IncrementCounter increments a counter for the given key. IncrementCounter(key string, args ...string) // MeasureSince measures the time since the given time. MeasureSince(key string, start time.Time, args ...string) // SetGauge sets a gauge metric to the specified value. SetGauge(key string, value int64, args ...string) } ================================================ FILE: consensus/cometbft/service/log/cmt_logger.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package log import ( "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/phuslu" cmtlog "github.com/cometbft/cometbft/libs/log" ) type CometLogger struct { log.AdvancedLogger[*phuslu.Logger] } func WrapCometLogger(logger *phuslu.Logger) *CometLogger { return &CometLogger{ AdvancedLogger: logger, } } func (l *CometLogger) With(keyVals ...any) cmtlog.Logger { return &CometLogger{ AdvancedLogger: l.AdvancedLogger.With(keyVals...), } } func (l *CometLogger) Impl() any { return l.AdvancedLogger } ================================================ FILE: consensus/cometbft/service/log/sdk_logger.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package log import ( sdklog "cosmossdk.io/log" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/phuslu" ) type SDKLogger struct { log.AdvancedLogger[*phuslu.Logger] } func WrapSDKLogger(logger *phuslu.Logger) *SDKLogger { return &SDKLogger{ AdvancedLogger: logger, } } func (l *SDKLogger) With(keyVals ...any) sdklog.Logger { return &SDKLogger{ AdvancedLogger: l.AdvancedLogger.With(keyVals...), } } func (l *SDKLogger) Impl() any { return l.AdvancedLogger } ================================================ FILE: consensus/cometbft/service/node_api_support.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "fmt" errorsmod "cosmossdk.io/errors" servercmtlog "github.com/berachain/beacon-kit/consensus/cometbft/service/log" "github.com/berachain/beacon-kit/node-core/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) var ( ErrAppNotReady = fmt.Errorf("%s is not ready; please wait for first block", AppName) _ types.ConsensusService = (*Service)(nil) ) // IsAppReady is used mainly by node-apis to understand the chain state, // before loading data func (s *Service) IsAppReady() error { // use custom query multi-store if provided lastBlockHeight := s.sm.GetCommitMultiStore().LatestVersion() if lastBlockHeight == 0 { return ErrAppNotReady } return nil } // CreateQueryContext creates a new sdk.Context for a query, taking as args // the block height and whether the query needs a proof or not. func (s *Service) CreateQueryContext( height int64, prove bool, ) (sdk.Context, error) { // use custom query multi-store if provided lastBlockHeight := s.sm.GetCommitMultiStore().LatestVersion() if lastBlockHeight == 0 { return sdk.Context{}, ErrAppNotReady } if height > lastBlockHeight { return sdk.Context{}, errorsmod.Wrap( sdkerrors.ErrInvalidHeight, "cannot query with height in the future; please provide a valid height", ) } // when a client did not provide a query height, manually inject the latest if height == 0 { height = lastBlockHeight } if height <= 1 && prove { return sdk.Context{}, errorsmod.Wrap( sdkerrors.ErrInvalidRequest, "cannot query with proof when height <= 1; please provide a valid height", ) } cacheMS, err := s.sm.GetCommitMultiStore().CacheMultiStoreWithVersion(height) if err != nil { return sdk.Context{}, errorsmod.Wrapf( sdkerrors.ErrNotFound, "failed to load state at height %d; %s (latest height: %d)", height, err, lastBlockHeight, ) } return sdk.NewContext( cacheMS, true, servercmtlog.WrapSDKLogger(s.logger), ), nil } func (s *Service) GetSyncData() (int64, int64) { return s.lastBlockHeight(), s.syncingToHeight } ================================================ FILE: consensus/cometbft/service/options.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "fmt" pruningtypes "cosmossdk.io/store/pruning/types" storetypes "cosmossdk.io/store/types" ) // File for storing in-package cometbft optional functions, // for options that need access to non-exported fields of the Service // SetPruning sets a pruning option on the multistore associated with the s. func SetPruning(opts pruningtypes.PruningOptions) func(*Service) { return func(bs *Service) { if opts.Strategy == pruningtypes.PruningNothing { bs.logger.Warn( "enable state pruning to reduce memory footprint considerably", "strategy", pruningtypes.PruningOptionNothing, "recommended strategies", fmt.Sprintf("%s or %s", pruningtypes.PruningOptionEverything, pruningtypes.PruningOptionDefault, ), ) } bs.sm.GetCommitMultiStore().SetPruning(opts) } } // SetMinRetainBlocks returns a Service option function that sets the minimum // block retention height value when determining which heights to prune during // ABCI Commit. func SetMinRetainBlocks(minRetainBlocks uint64) func(*Service) { return func(bs *Service) { bs.setMinRetainBlocks(minRetainBlocks) } } // SetIAVLCacheSize provides a Service option function that sets the size of // IAVL cache. func SetIAVLCacheSize(size int) func(*Service) { return func(bs *Service) { bs.sm.GetCommitMultiStore().SetIAVLCacheSize(size) } } // SetIAVLDisableFastNode enables(false)/disables(true) fast node usage from the // IAVL store. func SetIAVLDisableFastNode(disable bool) func(*Service) { return func(bs *Service) { bs.sm.GetCommitMultiStore().SetIAVLDisableFastNode(disable) } } // SetInterBlockCache provides a Service option function that sets the // inter-block cache. func SetInterBlockCache(cache storetypes.MultiStorePersistentCache) func(*Service) { return func(s *Service) { s.setInterBlockCache(cache) } } // SetChainID sets the chain ID in cometbft. func SetChainID(chainID string) func(*Service) { return func(s *Service) { s.chainID = chainID } } ================================================ FILE: consensus/cometbft/service/prepare_proposal.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "context" "fmt" "time" "github.com/berachain/beacon-kit/consensus/types" "github.com/berachain/beacon-kit/primitives/math" cmtabci "github.com/cometbft/cometbft/abci/types" ) func (s *Service) prepareProposal( ctx context.Context, req *cmtabci.PrepareProposalRequest, ) (*cmtabci.PrepareProposalResponse, error) { startTime := time.Now() defer s.telemetrySink.MeasureSince( "beacon_kit.runtime.prepare_proposal_duration", startTime) // CometBFT must never call PrepareProposal with a height of 0. if req.Height < 1 { return nil, fmt.Errorf( "prepareProposal at height %v: %w", req.Height, errInvalidHeight, ) } // prepareProposalState is used for PrepareProposal, which is set based on // the previous block's state. This state is never committed. In case of // multiple consensus rounds, the state is always reset to the previous // block's state. Always reset state given that PrepareProposal can timeout // and be called again in a subsequent round. prepareProposalState := s.resetState(ctx) //nolint:contextcheck // ctx already passed via resetState prepareProposalState.SetContext( s.getContextForProposal( prepareProposalState.Context(), req.Height, ), ) slotData := types.NewSlotData( math.Slot(req.GetHeight()), // #nosec G115 nil, // no attestations nil, // no slashings req.GetProposerAddress(), req.GetTime(), ) //nolint:contextcheck // ctx already passed via resetState blkBz, sidecarsBz, err := s.BlockBuilder.BuildBlockAndSidecars( prepareProposalState.Context(), slotData, ) if err != nil { s.logger.Error( "failed to prepare proposal", "height", req.Height, "time", req.Time, "err", err, ) return &cmtabci.PrepareProposalResponse{Txs: [][]byte{}}, nil } return &cmtabci.PrepareProposalResponse{ Txs: [][]byte{blkBz, sidecarsBz}, }, nil } ================================================ FILE: consensus/cometbft/service/process_proposal.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "context" "fmt" "time" "github.com/berachain/beacon-kit/consensus/cometbft/service/cache" "github.com/berachain/beacon-kit/primitives/math" cmtabci "github.com/cometbft/cometbft/abci/types" ) func (s *Service) processProposal( ctx context.Context, req *cmtabci.ProcessProposalRequest, ) (*cmtabci.ProcessProposalResponse, error) { startTime := time.Now() defer s.telemetrySink.MeasureSince( "beacon_kit.runtime.process_proposal_duration", startTime) // CometBFT must never call ProcessProposal with a height of 0. if req.Height < 1 { return nil, fmt.Errorf( "processProposal at height %v: %w", req.Height, errInvalidHeight, ) } // processProposalState is used for ProcessProposal, which is set based on // the previous block's state. This state is never committed. In case of // multiple consensus rounds, the state is always reset to the previous // block's state. processProposalState := s.resetState(ctx) //nolint:contextcheck // ctx already passed via resetState processProposalState.SetContext( s.getContextForProposal( processProposalState.Context(), req.Height, ), ) // errors to consensus indicate that the node was not able to understand // whether the block was valid or not. Viceversa, we signal that a block // is invalid by its status, but we do return nil error in such a case. valUpdates, err := s.Blockchain.ProcessProposal( processProposalState.Context(), req, s.nodeAddress[:], ) if err != nil { status := cmtabci.PROCESS_PROPOSAL_STATUS_REJECT s.logger.Error( "failed to process proposal", "height", req.Height, "time", req.Time, "hash", fmt.Sprintf("%X", req.Hash), "err", err, ) return &cmtabci.ProcessProposalResponse{Status: status}, nil } // We must not cache execution of the first block post initialHeight // because its state must be handled in a different way // TODO: before Stable block time activation we keep caching off // to make sure chain does not get faster. Once activated, we can // active as if cache was always active. if cache.IsStateCachingActive(s.delayCfg, math.Slot(req.Height)) { stateHash := string(req.Hash) toCache := &cache.Element{ State: processProposalState, ValUpdates: valUpdates, } s.cachedStates.SetCached(stateHash, toCache) } status := cmtabci.PROCESS_PROPOSAL_STATUS_ACCEPT return &cmtabci.ProcessProposalResponse{Status: status}, nil } ================================================ FILE: consensus/cometbft/service/service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "context" "errors" "fmt" storetypes "cosmossdk.io/store/types" "github.com/berachain/beacon-kit/beacon/blockchain" "github.com/berachain/beacon-kit/beacon/validator" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/consensus/cometbft/service/cache" "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" servercmtlog "github.com/berachain/beacon-kit/consensus/cometbft/service/log" statem "github.com/berachain/beacon-kit/consensus/cometbft/service/state" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/storage" abci "github.com/cometbft/cometbft/api/cometbft/abci/v1" cmtcfg "github.com/cometbft/cometbft/config" cmtcrypto "github.com/cometbft/cometbft/crypto" "github.com/cometbft/cometbft/node" "github.com/cometbft/cometbft/p2p" pvm "github.com/cometbft/cometbft/privval" "github.com/cometbft/cometbft/proxy" cmttypes "github.com/cometbft/cometbft/types" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" ) const ( initialAppVersion uint64 = 0 AppName string = "beacond" maxCachedStates = 10 ) type Service struct { node *node.Node nodeAddress cmtcrypto.Address delayCfg delay.ConfigGetter // cmtConsensusParams are part of the blockchain state and // are agreed upon by all validators in the network. cmtConsensusParams *cmttypes.ConsensusParams // cmtCfg are node-specific settings that influence how // the consensus engine operates on a particular node. // Loaded from config file (config.toml), not part of state. cmtCfg *cmtcfg.Config telemetrySink TelemetrySink logger *phuslu.Logger sm *statem.Manager Blockchain blockchain.BlockchainI BlockBuilder validator.BlockBuilderI // cachedStates tracks in memory the post block states // of blocks which were successfully verified. It allows // finalizing without re-execution cachedStates cache.States interBlockCache storetypes.MultiStorePersistentCache // initialHeight is the initial height at which we start the node initialHeight int64 minRetainBlocks uint64 chainID string // ctx is the context passed in for the service. CometBFT currently does // not support context usage. It passes "context.TODO()" to apps that // implement the ABCI++ interface, and does not provide a context that is // a child context of the one the node originally provides to comet. // Thus the app cannot tell when the context as been cancelled or not. // TODO: We must use this as a workaround for now until CometBFT properly // generates contexts that inherit from the parent context we provide. ctx context.Context // calculates block delay for the next block // // NOTE: may be nil until either InitChain or FinalizeBlock is called. blockDelay *delay.BlockDelay // syncingToHeight is a helper to track node sync state and support node-apis. syncingToHeight int64 } func NewService( logger *phuslu.Logger, db dbm.DB, blockchain blockchain.BlockchainI, blockBuilder validator.BlockBuilderI, cs chain.Spec, cmtCfg *cmtcfg.Config, telemetrySink TelemetrySink, options ...func(*Service), ) *Service { if err := validateConfig(cmtCfg); err != nil { panic(err) } cmtConsensusParams, err := extractConsensusParams(cmtCfg) if err != nil { panic(err) } // some configs, while legit, causes issues if applied // carelessly. We warn about them log := servercmtlog.WrapSDKLogger(logger) warnAboutConfigs(cmtCfg, log) s := &Service{ logger: logger, sm: statem.NewManager(db, log), Blockchain: blockchain, BlockBuilder: blockBuilder, delayCfg: cs, cmtConsensusParams: cmtConsensusParams, cmtCfg: cmtCfg, telemetrySink: telemetrySink, cachedStates: cache.New(maxCachedStates, telemetrySink), } s.MountStore(storage.StoreKey, storetypes.StoreTypeIAVL) for _, option := range options { option(s) } if s.interBlockCache != nil { s.sm.GetCommitMultiStore().SetInterBlockCache(s.interBlockCache) } // Load latest height, once all stores have been set if err = s.sm.LoadLatestVersion(); err != nil { panic(fmt.Errorf("failed loading latest version: %w", err)) } lastBlockHeight := s.lastBlockHeight() s.syncingToHeight = lastBlockHeight // Make sure that SBT consensus parameters are duly set when the node restart. // Note that we can't rely on genesis.json having these parameters set right // because we introduced stable block time post (mainnet) genesis. if lastBlockHeight >= s.delayCfg.SbtConsensusUpdateHeight() { s.cmtConsensusParams.Feature.SBTEnableHeight = s.delayCfg.SbtConsensusEnableHeight() } // Load block delay. // // If not found, we will initialize it in FinalizeBlock once SBTEnableHeight // is reached. bz, err := s.sm.LoadBlockDelay() if err != nil { panic(fmt.Errorf("failed loading block delay: %w", err)) } if bz != nil { s.blockDelay, err = delay.FromBytes(bz) if err != nil { panic(fmt.Errorf("failed decoding block delay: %w", err)) } } // Clean up any orphaned blob sidecars from incomplete block finalization. if err = s.Blockchain.PruneOrphanedBlobs(lastBlockHeight); err != nil { panic(fmt.Errorf("failed pruning orphaned blobs: %w", err)) } return s } // TODO: Move nodeKey into being created within the function. func (s *Service) Start( ctx context.Context, ) error { cfg := s.cmtCfg nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile()) if err != nil { return err } privVal, err := pvm.LoadOrGenFilePV( cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile(), nil, ) if err != nil { return err } s.ResetAppCtx(ctx) s.node, err = node.NewNode( ctx, cfg, privVal, nodeKey, proxy.NewLocalClientCreator(s), GetGenDocProvider(cfg), cmtcfg.DefaultDBProvider, node.DefaultMetricsProvider(cfg.Instrumentation), servercmtlog.WrapCometLogger(s.logger), ) if err != nil { return err } pubKey, errPk := s.node.PrivValidator().GetPubKey() if errPk != nil { return fmt.Errorf("failed retrieving pub key: %w", err) } s.nodeAddress = pubKey.Address() started := make(chan struct{}) // we start the node in a goroutine since calling Start() can block if genesis // time is in the future causing us not to handle signals gracefully. go func() { err = s.node.Start() started <- struct{}{} }() select { case <-ctx.Done(): return ctx.Err() case <-started: } close(started) return err } func (s *Service) Stop() error { var errs []error if s.node != nil && s.node.IsRunning() { s.logger.Info("Stopping CometBFT Node") err := s.node.Stop() if err != nil { errs = append(errs, fmt.Errorf("failed to stop CometBFT Node: %w", err)) } s.logger.Info("Waiting for CometBFT Node to stop") s.node.Wait() } s.logger.Info("Closing application.db") if err := s.sm.Close(); err != nil { errs = append(errs, fmt.Errorf("failed to close application.id: %w", err)) } return errors.Join(errs...) } // ResetAppCtx sets the app ctx for the service. This is used // primarily for the mock service. func (s *Service) ResetAppCtx(ctx context.Context) { s.ctx = ctx } // SetNodeAddress sets the node address for the service. This is used // primarily for the mock service. func (s *Service) SetNodeAddress(addr cmtcrypto.Address) { s.nodeAddress = addr } // Name returns the name of the cometbft. func (s *Service) Name() string { return AppName } // CommitMultiStore returns the CommitMultiStore of the cometbft. // This needs to be exposed because it is used by commands like Rollback. func (s *Service) CommitMultiStore() storetypes.CommitMultiStore { return s.sm.GetCommitMultiStore() } // GetBlock returns the CometBFT block at the given height. func (s *Service) GetBlock(height int64) *cmttypes.Block { if s.node == nil { return nil } block, _ := s.node.BlockStore().LoadBlock(height) return block } // GetSignedHeader returns the CometBFT signed header (header + commit) at the given height. func (s *Service) GetSignedHeader(height int64) *cmttypes.SignedHeader { if s.node == nil { return nil } block, _ := s.node.BlockStore().LoadBlock(height) if block == nil { return nil } commit := s.node.BlockStore().LoadBlockCommit(height) if commit == nil { return nil } return &cmttypes.SignedHeader{ Header: &block.Header, Commit: commit, } } // AppVersion returns the application's protocol version. func (s *Service) AppVersion(_ context.Context) (uint64, error) { return s.appVersion() } func (s *Service) appVersion() (uint64, error) { cp := s.cmtConsensusParams.ToProto() return cp.Version.App, nil } // MountStore mounts a store to the provided key in the Service multistore, // using the default DB. func (s *Service) MountStore( key storetypes.StoreKey, typ storetypes.StoreType, ) { s.sm.GetCommitMultiStore().MountStoreWithDB(key, typ, nil) } // LastBlockHeight returns the last committed block height. func (s *Service) lastBlockHeight() int64 { return s.sm.GetCommitMultiStore().LastCommitID().Version } func (s *Service) setMinRetainBlocks(minRetainBlocks uint64) { s.minRetainBlocks = minRetainBlocks } func (s *Service) setInterBlockCache( cache storetypes.MultiStorePersistentCache, ) { s.interBlockCache = cache } // resetState provides a fresh state which can be used to reset // prepareProposal/processProposal/finalizeBlock State. // A state is explicitly returned to avoid false positives from // nilaway tool. func (s *Service) resetState(ctx context.Context) *cache.State { ms := s.sm.GetCommitMultiStore().CacheMultiStore() newCtx := sdk.NewContext( ms, false, servercmtlog.WrapSDKLogger(s.logger), ).WithContext(ctx) return cache.NewState(ms, newCtx) } // convertValidatorUpdate abstracts the conversion of a // transition.ValidatorUpdate to an appmodulev2.ValidatorUpdate. // TODO: this is so hood, bktypes -> sdktypes -> generic is crazy // maybe make this some kind of codec/func that can be passed in? func convertValidatorUpdate[ValidatorUpdateT any]( u **transition.ValidatorUpdate, ) (ValidatorUpdateT, error) { var valUpdate ValidatorUpdateT update := *u if update == nil { return valUpdate, errors.New("undefined validator update") } //nolint:errcheck // should be safe return any(abci.ValidatorUpdate{ PubKeyBytes: update.Pubkey[:], PubKeyType: crypto.CometBLSType, Power: int64(update.EffectiveBalance.Unwrap()), // #nosec G115 -- this is safe. }).(ValidatorUpdateT), nil } // getContextForProposal returns the correct Context for PrepareProposal and // ProcessProposal. We use finalizeBlockState on the first block to be able to // access any state changes made in InitChain. func (s *Service) getContextForProposal( ctx sdk.Context, height int64, ) sdk.Context { if height != s.initialHeight { return ctx } _, finalState, err := s.cachedStates.GetFinal() if err != nil { // this is unexpected since cometBFT won't call PrepareProposal // on initialHeight. Panic appeases nilaway. panic(fmt.Errorf("getContextForProposal: %w", err)) } newCtx, _ := finalState.Context().CacheContext() // Preserve the CosmosSDK context while using the correct base ctx. return newCtx.WithContext(ctx.Context()) } ================================================ FILE: consensus/cometbft/service/state/state.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package state import ( "fmt" "cosmossdk.io/log" "cosmossdk.io/store" storemetrics "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" dbm "github.com/cosmos/cosmos-db" ) type Manager struct { db dbm.DB cms storetypes.CommitMultiStore } // NewManager creates a new Manager. func NewManager( db dbm.DB, logger log.Logger, opts ...func(*Manager), ) *Manager { sm := &Manager{ db: db, cms: store.NewCommitMultiStore( db, logger, storemetrics.NewNoOpMetrics(), ), } for _, opt := range opts { opt(sm) } // TODO: Kill KVStoreService and register here. // sm.cms.MountStoreWithDB( // storetypes.NewKVStoreKey("beacon"), // storetypes.StoreTypeIAVL, // db, // ) return sm } func (sm *Manager) LoadVersion(version int64) error { err := sm.GetCommitMultiStore().LoadVersion(version) if err != nil { return fmt.Errorf("failed to load version %d: %w", version, err) } // Validate Pruning settings. return sm.GetCommitMultiStore().GetPruning().Validate() } func (sm *Manager) LoadLatestVersion() error { if err := sm.cms.LoadLatestVersion(); err != nil { return fmt.Errorf("failed to load latest version: %w", err) } // Validator pruning settings. return sm.cms.GetPruning().Validate() } func (sm *Manager) Close() error { return sm.db.Close() } // GetCommitMultiStore returns the CommitMultiStore of the Manager. func (sm *Manager) GetCommitMultiStore() storetypes.CommitMultiStore { return sm.cms } //nolint:gochecknoglobals // unexported key var blockDelayKey = []byte("blockDelay") // LoadBlockDelay loads the block delay bytes from the database. // // see next_block_delay.go func (sm *Manager) LoadBlockDelay() ([]byte, error) { return sm.db.Get(blockDelayKey) } // SaveBlockDelay saves the block delay bytes to the database. // // see next_block_delay.go func (sm *Manager) SaveBlockDelay(bz []byte) error { return sm.db.Set(blockDelayKey, bz) } ================================================ FILE: consensus/types/common.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import "github.com/berachain/beacon-kit/primitives/math" type commonConsensusData struct { // use to verify block builder proposerAddress []byte // used to build next block and validate current payload timestamp consensusTime math.U64 } // GetProposerAddress returns the address of the validator // selected by consensus to propose the block. func (c *commonConsensusData) GetProposerAddress() []byte { return c.proposerAddress } // GetConsensusTime returns the timestamp of current consensus request. // It is used to build next payload and to validate currentpayload. func (c *commonConsensusData) GetConsensusTime() math.U64 { return c.consensusTime } ================================================ FILE: consensus/types/consensus_block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "time" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/math" ) type ConsensusBlock struct { blk *types.BeaconBlock // some consensus data useful to build and verify the block *commonConsensusData } // New creates a new ConsensusBlock instance. func NewConsensusBlock( beaconBlock *types.BeaconBlock, proposerAddress []byte, consensusTime time.Time, ) *ConsensusBlock { return &ConsensusBlock{ blk: beaconBlock, commonConsensusData: &commonConsensusData{ proposerAddress: proposerAddress, consensusTime: math.U64(consensusTime.Unix()), // #nosec G115 }, } } func (b *ConsensusBlock) GetBeaconBlock() *types.BeaconBlock { return b.blk } ================================================ FILE: consensus/types/slot_data.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/math" ) // SlotData represents the data to be used to propose a block. type SlotData struct { // slot is the slot number of the incoming slot. slot math.Slot // attestationData is the attestation data of the incoming slot. attestationData []*ctypes.AttestationData // slashingInfo is the slashing info of the incoming slot. slashingInfo []*ctypes.SlashingInfo // some consensus data useful to build and verify the block *commonConsensusData } // NewSlotData creates a new SlotData instance. func NewSlotData( slot math.Slot, attestationData []*ctypes.AttestationData, slashingInfo []*ctypes.SlashingInfo, proposerAddress []byte, consensusTime time.Time, ) *SlotData { return &SlotData{ slot: slot, attestationData: attestationData, slashingInfo: slashingInfo, commonConsensusData: &commonConsensusData{ proposerAddress: proposerAddress, consensusTime: math.U64(consensusTime.Unix()), // #nosec G115 }, } } // GetSlot retrieves the slot of the SlotData. func (b *SlotData) GetSlot() math.Slot { return b.slot } // GetAttestationData retrieves the attestation data of the SlotData. func (b *SlotData) GetAttestationData() []*ctypes.AttestationData { return b.attestationData } // GetSlashingInfo retrieves the slashing info of the SlotData. func (b *SlotData) GetSlashingInfo() []*ctypes.SlashingInfo { return b.slashingInfo } // SetAttestationData sets the attestation data of the SlotData. func (b *SlotData) SetAttestationData( attestationData []*ctypes.AttestationData, ) { b.attestationData = attestationData } // SetSlashingInfo sets the slashing info of the SlotData. func (b *SlotData) SetSlashingInfo( slashingInfo []*ctypes.SlashingInfo, ) { b.slashingInfo = slashingInfo } ================================================ FILE: consensus-types/types/attestation_data.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // AttestationDataSize is the size of the AttestationData object in bytes. // 8 bytes for Slot + 8 bytes for Index + 32 bytes for BeaconBlockRoot. const AttestationDataSize = 48 var ( _ ssz.StaticObject = (*AttestationData)(nil) _ constraints.SSZMarshallableRootable = (*AttestationData)(nil) ) // AttestationData represents an attestation data. type AttestationData struct { // Slot is the slot number of the attestation data. Slot math.U64 `json:"slot"` // Index is the index of the validator. Index math.U64 `json:"index"` // BeaconBlockRoot is the root of the beacon block. BeaconBlockRoot common.Root `json:"beaconBlockRoot"` } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the AttestationData object in SSZ encoding. func (*AttestationData) SizeSSZ(*ssz.Sizer) uint32 { return AttestationDataSize } // DefineSSZ defines the SSZ encoding for the AttestationData object. func (a *AttestationData) DefineSSZ(codec *ssz.Codec) { ssz.DefineUint64(codec, &a.Slot) ssz.DefineUint64(codec, &a.Index) ssz.DefineStaticBytes(codec, &a.BeaconBlockRoot) } // HashTreeRoot computes the SSZ hash tree root of the AttestationData object. func (a *AttestationData) HashTreeRoot() common.Root { return ssz.HashSequential(a) } // MarshalSSZ marshals the AttestationData object to SSZ format. func (a *AttestationData) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(a)) return buf, ssz.EncodeToBytes(buf, a) } func (*AttestationData) ValidateAfterDecodingSSZ() error { return nil } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo marshals the AttestationData object into a pre-allocated byte // slice. func (a *AttestationData) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := a.MarshalSSZ() if err != nil { return nil, err } dst = append(dst, bz...) return dst, err } // HashTreeRootWith ssz hashes the AttestationData object with a hasher. func (a *AttestationData) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'Slot' hh.PutUint64(uint64(a.Slot)) // Field (1) 'Index' hh.PutUint64(uint64(a.Index)) // Field (2) 'BeaconBlockRoot' hh.PutBytes(a.BeaconBlockRoot[:]) hh.Merkleize(indx) return nil } // GetTree ssz hashes the AttestationData object. func (a *AttestationData) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(a) } /* -------------------------------------------------------------------------- */ /* Getters and Setters */ /* -------------------------------------------------------------------------- */ // GetSlot returns the slot of the attestation data. func (a *AttestationData) GetSlot() math.U64 { return a.Slot } // GetIndex returns the index of the attestation data. func (a *AttestationData) GetIndex() math.U64 { return a.Index } // GetBeaconBlockRoot returns the beacon block root of the attestation data. func (a *AttestationData) GetBeaconBlockRoot() common.Root { return a.BeaconBlockRoot } ================================================ FILE: consensus-types/types/attestation_data_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) func generateAttestationData() *types.AttestationData { return &types.AttestationData{ Slot: 12345, Index: 67890, BeaconBlockRoot: [32]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, }, } } func TestAttestationData_MarshalSSZ_UnmarshalSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string data *types.AttestationData expected *types.AttestationData err error }{ { name: "Valid AttestationData", data: generateAttestationData(), expected: generateAttestationData(), err: nil, }, { name: "Empty AttestationData", data: &types.AttestationData{ Slot: 0, Index: 0, BeaconBlockRoot: [32]byte{}, }, expected: &types.AttestationData{ Slot: 0, Index: 0, BeaconBlockRoot: [32]byte{}, }, err: nil, }, { name: "Invalid Buffer Size", data: generateAttestationData(), expected: nil, err: io.ErrUnexpectedEOF, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() data, err := tc.data.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(types.AttestationData) if tc.name == "Invalid Buffer Size" { err = ssz.Unmarshal(data[:32], unmarshalled) require.ErrorIs(t, err, tc.err) } else { err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, tc.expected, unmarshalled) var buf []byte buf, err = tc.data.MarshalSSZTo(buf) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) } }) } } func TestAttestationData_GetTree(t *testing.T) { t.Parallel() data := generateAttestationData() tree, err := data.GetTree() require.NoError(t, err) require.NotNil(t, tree) expectedRoot := data.HashTreeRoot() // Compare the tree root with the expected root actualRoot := tree.Hash() require.Equal(t, string(expectedRoot[:]), string(actualRoot)) } func TestAttestationData_Getters(t *testing.T) { t.Parallel() data := generateAttestationData() beaconBlockRoot := common.Root{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, } require.NotNil(t, data) require.Equal(t, math.U64(12345), data.GetSlot()) require.Equal(t, math.U64(67890), data.GetIndex()) require.Equal(t, beaconBlockRoot, data.GetBeaconBlockRoot()) } ================================================ FILE: consensus-types/types/attester_slashings.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // separate file for ease of future implementation package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure AttesterSlashing implements necessary interfaces. var ( _ ssz.StaticObject = (*AttesterSlashing)(nil) _ constraints.SSZMarshallableRootable = (*AttesterSlashing)(nil) _ common.UnusedEnforcer = (*AttesterSlashings)(nil) ) type ( AttesterSlashing = common.UnusedType AttesterSlashings []*AttesterSlashing ) // SizeSSZ returns the SSZ encoded size in bytes for the AttesterSlashings. func (ass AttesterSlashings) SizeSSZ(siz *ssz.Sizer, _ bool) uint32 { return ssz.SizeSliceOfStaticObjects(siz, ass) } // DefineSSZ defines the SSZ encoding for the AttesterSlashings object. func (ass AttesterSlashings) DefineSSZ(c *ssz.Codec) { c.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*AttesterSlashing)(&ass), constants.MaxAttesterSlashings) }) c.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*AttesterSlashing)(&ass), constants.MaxAttesterSlashings) }) c.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfStaticObjectsOffset(c, (*[]*AttesterSlashing)(&ass), constants.MaxAttesterSlashings) }) } // HashTreeRoot returns the hash tree root of the AttesterSlashings. func (ass AttesterSlashings) HashTreeRoot() common.Root { return ssz.HashSequential(ass) } // EnforceUnused return true if the length of the AttestererSlashings is 0. // As long as this type remains unimplemented and unvalidated by consensus, // we must enforce that it contains no data. func (ass AttesterSlashings) EnforceUnused() error { if len(ass) != 0 { return errors.New("AttesterSlashings must be unused") } return nil } ================================================ FILE: consensus-types/types/attestions.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // separate file for ease of future implementation package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure Attestation implements necessary interfaces. var ( _ ssz.StaticObject = (*Attestation)(nil) _ constraints.SSZMarshallableRootable = (*Attestation)(nil) _ common.UnusedEnforcer = (*Attestations)(nil) ) type ( Attestation = common.UnusedType Attestations []*Attestation ) // SizeSSZ returns the SSZ encoded size in bytes for the Attestations. func (as Attestations) SizeSSZ(siz *ssz.Sizer, _ bool) uint32 { return ssz.SizeSliceOfStaticObjects(siz, as) } // DefineSSZ defines the SSZ encoding for the Attestations object. func (as Attestations) DefineSSZ(c *ssz.Codec) { c.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*Attestation)(&as), constants.MaxAttestations) }) c.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*Attestation)(&as), constants.MaxAttestations) }) c.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfStaticObjectsOffset(c, (*[]*Attestation)(&as), constants.MaxAttestations) }) } // HashTreeRoot returns the hash tree root of the Attestations. func (as Attestations) HashTreeRoot() common.Root { return ssz.HashSequential(as) } // EnforceUnused return true if the length of the Attestations is 0. // As long as this type remains unimplemented and unvalidated by consensus, // we must enforce that it contains no data. func (as Attestations) EnforceUnused() error { if len(as) != 0 { return errors.New("Attestations must be unused") } return nil } ================================================ FILE: consensus-types/types/block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure BeaconBlock implements necessary interfaces. var ( _ ssz.DynamicObject = (*BeaconBlock)(nil) _ constraints.SSZVersionedMarshallableRootable = (*BeaconBlock)(nil) ) // BeaconBlock represents a block in the beacon chain. type BeaconBlock struct { constraints.Versionable `json:"-"` // Slot represents the position of the block in the chain. Slot math.Slot `json:"slot"` // ProposerIndex is the index of the validator who proposed the block. ProposerIndex math.ValidatorIndex `json:"proposer_index"` // ParentRoot is the hash of the parent block ParentRoot common.Root `json:"parent_root"` // StateRoot is the hash of the state at the block. StateRoot common.Root `json:"state_root"` // Body is the body of the BeaconBlock, containing the block's operations. Body *BeaconBlockBody `json:"body"` } // NewBeaconBlockWithVersion assembles a new beacon block from the given parameters. func NewBeaconBlockWithVersion( slot math.Slot, proposerIndex math.ValidatorIndex, parentBlockRoot common.Root, forkVersion common.Version, ) (*BeaconBlock, error) { switch forkVersion { case version.Deneb(), version.Deneb1(), version.Electra(), version.Electra1(), version.Fulu(): block := NewEmptyBeaconBlockWithVersion(forkVersion) block.Slot = slot block.ProposerIndex = proposerIndex block.ParentRoot = parentBlockRoot // StateRoot is left empty as it is not ready at this time. block.StateRoot = common.Root{} return block, nil default: // We return block here to appease nilaway. block := &BeaconBlock{} err := errors.Wrap(ErrForkVersionNotSupported, fmt.Sprintf("fork %d", forkVersion)) return block, err } } func NewEmptyBeaconBlockWithVersion(version common.Version) *BeaconBlock { return &BeaconBlock{ Versionable: NewVersionable(version), Body: NewEmptyBeaconBlockBodyWithVersion(version), } } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the BeaconBlock object in SSZ encoding. func (b *BeaconBlock) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { //nolint:mnd // todo fix. var size = uint32(8 + 8 + 32 + 32 + 4) if fixed { return size } size += ssz.SizeDynamicObject(siz, b.Body) return size } // DefineSSZ defines the SSZ encoding for the BeaconBlock object. func (b *BeaconBlock) DefineSSZ(codec *ssz.Codec) { // Define the static data (fields and dynamic offsets) ssz.DefineUint64(codec, &b.Slot) ssz.DefineUint64(codec, &b.ProposerIndex) ssz.DefineStaticBytes(codec, &b.ParentRoot) ssz.DefineStaticBytes(codec, &b.StateRoot) ssz.DefineDynamicObjectOffset(codec, &b.Body) // Define the dynamic data (fields) ssz.DefineDynamicObjectContent(codec, &b.Body) } // MarshalSSZ marshals the BeaconBlock object to SSZ format. func (b *BeaconBlock) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(b)) return buf, ssz.EncodeToBytes(buf, b) } func (b *BeaconBlock) ValidateAfterDecodingSSZ() error { return b.Body.ValidateAfterDecodingSSZ() } // HashTreeRoot computes the Merkleization of the BeaconBlock object. func (b *BeaconBlock) HashTreeRoot() common.Root { return ssz.HashConcurrent(b) } // GetSlot retrieves the slot of the BeaconBlockBase. func (b *BeaconBlock) GetSlot() math.Slot { return b.Slot } // GetProposerIndex retrieves the proposer index. func (b *BeaconBlock) GetProposerIndex() math.ValidatorIndex { return b.ProposerIndex } // GetParentBlockRoot retrieves the parent block root of the BeaconBlockBase. func (b *BeaconBlock) GetParentBlockRoot() common.Root { return b.ParentRoot } // SetParentBlockRoot sets the parent block root of the BeaconBlockBase. func (b *BeaconBlock) SetParentBlockRoot(parentBlockRoot common.Root) { b.ParentRoot = parentBlockRoot } // GetStateRoot retrieves the state root of the BeaconBlock. func (b *BeaconBlock) GetStateRoot() common.Root { return b.StateRoot } // SetStateRoot sets the state root of the BeaconBlock. func (b *BeaconBlock) SetStateRoot(root common.Root) { b.StateRoot = root } // GetBody retrieves the body of the BeaconBlock. func (b *BeaconBlock) GetBody() *BeaconBlockBody { return b.Body } // GetHeader builds a BeaconBlockHeader from the BeaconBlock. func (b *BeaconBlock) GetHeader() *BeaconBlockHeader { return &BeaconBlockHeader{ Slot: b.Slot, ProposerIndex: b.ProposerIndex, ParentBlockRoot: b.ParentRoot, StateRoot: b.StateRoot, BodyRoot: b.GetBody().HashTreeRoot(), } } // GetTimestamp retrieves the timestamp of the BeaconBlock from // the ExecutionPayload. func (b *BeaconBlock) GetTimestamp() math.U64 { return b.Body.ExecutionPayload.Timestamp } ================================================ FILE: consensus-types/types/block_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "testing" "testing/quick" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/testing/utils" "github.com/stretchr/testify/require" ) func TestBeaconBlockForDeneb(t *testing.T) { t.Parallel() deneb1 := version.Deneb1() block, err := types.NewBeaconBlockWithVersion( math.Slot(10), math.ValidatorIndex(5), common.Root{1, 2, 3, 4, 5}, // parent root deneb1, ) require.NoError(t, err) require.NotNil(t, block) require.Equal(t, deneb1, block.GetForkVersion()) require.Equal(t, deneb1, block.GetBody().GetForkVersion()) require.Equal(t, deneb1, block.GetBody().GetExecutionPayload().GetForkVersion()) } func TestBeaconBlock(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { block := utils.GenerateValidBeaconBlock(t, v) require.NotNil(t, block.Body) require.Equal(t, math.U64(10), block.GetTimestamp()) require.Equal(t, v, block.GetForkVersion()) require.NotNil(t, block) // Set a new state root and test the SetStateRoot and GetBody methods newStateRoot := [32]byte{1, 1, 1, 1, 1} block.SetStateRoot(newStateRoot) require.Equal(t, newStateRoot, [32]byte(block.StateRoot)) // Test the GetHeader method header := block.GetHeader() require.NotNil(t, header) require.Equal(t, block.Slot, header.Slot) require.Equal(t, block.ProposerIndex, header.ProposerIndex) require.Equal(t, block.ParentRoot, header.ParentBlockRoot) require.Equal(t, block.StateRoot, header.StateRoot) require.Equal(t, newStateRoot, [32]byte(block.GetStateRoot())) }) } func TestBeaconBlock_MarshalUnmarshalSSZ(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { block := utils.GenerateValidBeaconBlock(t, v) sszBlock, err := block.MarshalSSZ() require.NoError(t, err) require.NotNil(t, sszBlock) unmarshalledBlock := types.NewEmptyBeaconBlockWithVersion(v) err = ssz.Unmarshal(sszBlock, unmarshalledBlock) require.NoError(t, err) require.Equal(t, block, unmarshalledBlock) }) } func TestBeaconBlock_HashTreeRoot(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { block := utils.GenerateValidBeaconBlock(t, v) hashRoot := block.HashTreeRoot() require.NotNil(t, hashRoot) }) } func TestBeaconBlock_IsNil(t *testing.T) { t.Parallel() var block *types.BeaconBlock require.Nil(t, block) } func TestNewWithVersion(t *testing.T) { t.Parallel() slot := math.Slot(10) proposerIndex := math.ValidatorIndex(5) parentBlockRoot := common.Root{1, 2, 3, 4, 5} runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { block, err := types.NewBeaconBlockWithVersion( slot, proposerIndex, parentBlockRoot, v, ) require.NoError(t, err) require.NotNil(t, block) // Check the block's fields require.NotNil(t, block) require.Equal(t, slot, block.GetSlot()) require.Equal(t, proposerIndex, block.GetProposerIndex()) require.Equal(t, parentBlockRoot, block.GetParentBlockRoot()) require.Equal(t, v, block.GetForkVersion()) }) } func TestNewWithVersionInvalidForkVersion(t *testing.T) { t.Parallel() slot := math.Slot(10) proposerIndex := math.ValidatorIndex(5) parentBlockRoot := common.Root{1, 2, 3, 4, 5} _, err := types.NewBeaconBlockWithVersion( slot, proposerIndex, parentBlockRoot, common.Version{100, 0, 0, 0}, ) // 100 is an invalid fork version require.ErrorIs(t, err, types.ErrForkVersionNotSupported) } func TestPropertyBlockRootAndBlockHeaderRootEquivalence(t *testing.T) { t.Parallel() qc := &quick.Config{MaxCount: 100} runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { f := func( slot math.Slot, proposerIdx math.ValidatorIndex, parentBlockRoot common.Root, ) bool { blk, err := types.NewBeaconBlockWithVersion( slot, proposerIdx, parentBlockRoot, v, ) require.NoError(t, err) return blk.GetHeader().HashTreeRoot().Equals(blk.HashTreeRoot()) } require.NoError(t, quick.Check(f, qc)) }) } ================================================ FILE: consensus-types/types/bls_to_execution_changes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // separate file for ease of future implementation package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure BlsToExecutionChange implements necessary interfaces. var ( _ ssz.StaticObject = (*BlsToExecutionChange)(nil) _ constraints.SSZMarshallableRootable = (*BlsToExecutionChange)(nil) _ common.UnusedEnforcer = (*BlsToExecutionChanges)(nil) ) type ( BlsToExecutionChange = common.UnusedType BlsToExecutionChanges []*BlsToExecutionChange ) // SizeSSZ returns the SSZ encoded size in bytes for the BlsToExecutionChanges. func (bs BlsToExecutionChanges) SizeSSZ(siz *ssz.Sizer, _ bool) uint32 { return ssz.SizeSliceOfStaticObjects(siz, bs) } // DefineSSZ defines the SSZ encoding for the BlsToExecutionChanges object. func (bs BlsToExecutionChanges) DefineSSZ(c *ssz.Codec) { c.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*BlsToExecutionChange)(&bs), constants.MaxBlsToExecutionChanges) }) c.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*BlsToExecutionChange)(&bs), constants.MaxBlsToExecutionChanges) }) c.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfStaticObjectsOffset(c, (*[]*BlsToExecutionChange)(&bs), constants.MaxBlsToExecutionChanges) }) } // HashTreeRoot returns the hash tree root of the BlsToExecutionChanges. func (bs BlsToExecutionChanges) HashTreeRoot() common.Root { return ssz.HashSequential(bs) } // EnforceUnused return true if the length of the BlsToExecutionChanges is 0. // As long as this type remains unimplemented and unvalidated by consensus, // we must enforce that it contains no data. func (bs BlsToExecutionChanges) EnforceUnused() error { if len(bs) != 0 { return errors.New("BlsToExecutionChanges must be unused") } return nil } ================================================ FILE: consensus-types/types/body.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/version" "github.com/karalabe/ssz" ) const ( // BodyLengthDeneb is the number of fields in the BeaconBlockBody struct for Deneb. BodyLengthDeneb uint64 = 12 // BodyLengthElectra is the number of fields in the BeaconBlockBody struct for Electra. BodyLengthElectra uint64 = 13 // KZGPosition is the position of BlobKzgCommitments in the block body. KZGPosition uint64 = 11 // KZGGeneralizedIndex is the index of the KZG commitment root's parent. // (1 << log2ceil(KZGPosition)) | KZGPosition. KZGGeneralizedIndex = 27 // KZGRootIndex is the merkle index of BlobKzgCommitments' root // in the merkle tree built from the block body. // 2 * KZGGeneralizedIndex. KZGRootIndex = KZGGeneralizedIndex * 2 // KZGInclusionProofDepth is the // Log2Floor(KZGGeneralizedIndex) + // Log2Ceil(MaxBlobCommitmentsPerBlock) + 1 KZGInclusionProofDepth = 17 // KZGOffset is the offset of the KZG commitments in the serialized block body. KZGOffset = KZGRootIndex * constants.MaxBlobCommitmentsPerBlock ) // Compile-time assertions to ensure BeaconBlockBody implements necessary interfaces. var ( _ ssz.DynamicObject = (*BeaconBlockBody)(nil) _ constraints.SSZVersionedMarshallableRootable = (*BeaconBlockBody)(nil) ) // BeaconBlockBody represents the body of a beacon block. type BeaconBlockBody struct { // Must be available within the object to satisfy signature required for SizeSSZ and DefineSSZ. constraints.Versionable `json:"-"` // RandaoReveal is the reveal of the RANDAO. RandaoReveal crypto.BLSSignature // Eth1Data is the data from the Eth1 chain. Eth1Data *Eth1Data // Graffiti is for a fun message or meme. Graffiti [32]byte // proposerSlashings is unused but left for compatibility. proposerSlashings []*ProposerSlashing // attesterSlashings is unused but left for compatibility. attesterSlashings []*AttesterSlashing // attestations is unused but left for compatibility. attestations []*Attestation // Deposits is the list of deposits included in the body. Deposits []*Deposit // voluntaryExits is unused but left for compatibility. voluntaryExits []*VoluntaryExit // syncAggregate is unused but left for compatibility. syncAggregate *SyncAggregate // ExecutionPayload is the execution payload of the body. ExecutionPayload *ExecutionPayload // blsToExecutionChanges is unused but left for compatibility. blsToExecutionChanges []*BlsToExecutionChange // BlobKzgCommitments is the list of KZG commitments for the EIP-4844 blobs. BlobKzgCommitments []eip4844.KZGCommitment // executionRequests is introduced in Electra. We keep this private so that it must go through Getter/Setter // which does a forkVersion check. executionRequests *ExecutionRequests } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the BeaconBlockBody in SSZ. func (b *BeaconBlockBody) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { var size = 96 + 72 + 32 + 4 + 4 + 4 + 4 + 4 + b.syncAggregate.SizeSSZ(siz) + 4 + 4 + 4 includeExecRequest := version.EqualsOrIsAfter(b.GetForkVersion(), version.Electra()) if includeExecRequest { // Add 4 for the offset of dynamic field ExecutionRequests size += constants.SSZOffsetSize } if fixed { return size } size += ssz.SizeSliceOfStaticObjects(siz, b.proposerSlashings) size += ssz.SizeSliceOfStaticObjects(siz, b.attesterSlashings) size += ssz.SizeSliceOfStaticObjects(siz, b.attestations) size += ssz.SizeSliceOfStaticObjects(siz, b.Deposits) size += ssz.SizeSliceOfStaticObjects(siz, b.voluntaryExits) size += ssz.SizeDynamicObject(siz, b.ExecutionPayload) size += ssz.SizeSliceOfStaticObjects(siz, b.blsToExecutionChanges) size += ssz.SizeSliceOfStaticBytes(siz, b.BlobKzgCommitments) if includeExecRequest { size += ssz.SizeDynamicObject(siz, b.executionRequests) } return size } // DefineSSZ defines the SSZ serialization of the BeaconBlockBody. // //nolint:mnd // TODO: get from accessible chainspec field params func (b *BeaconBlockBody) DefineSSZ(codec *ssz.Codec) { // Define the static data (fields and dynamic offsets) ssz.DefineStaticBytes(codec, &b.RandaoReveal) ssz.DefineStaticObject(codec, &b.Eth1Data) ssz.DefineStaticBytes(codec, &b.Graffiti) ssz.DefineSliceOfStaticObjectsOffset(codec, &b.proposerSlashings, constants.MaxProposerSlashings) ssz.DefineSliceOfStaticObjectsOffset(codec, &b.attesterSlashings, constants.MaxAttesterSlashings) ssz.DefineSliceOfStaticObjectsOffset(codec, &b.attestations, constants.MaxAttestations) ssz.DefineSliceOfStaticObjectsOffset(codec, &b.Deposits, constants.MaxDeposits) ssz.DefineSliceOfStaticObjectsOffset(codec, &b.voluntaryExits, constants.MaxVoluntaryExits) ssz.DefineStaticObject(codec, &b.syncAggregate) ssz.DefineDynamicObjectOffset(codec, &b.ExecutionPayload) ssz.DefineSliceOfStaticObjectsOffset(codec, &b.blsToExecutionChanges, constants.MaxBlsToExecutionChanges) ssz.DefineSliceOfStaticBytesOffset(codec, &b.BlobKzgCommitments, 4096) includeExecRequest := version.EqualsOrIsAfter(b.GetForkVersion(), version.Electra()) if includeExecRequest { ssz.DefineDynamicObjectOffset(codec, &b.executionRequests) } // Define the dynamic data (fields) ssz.DefineSliceOfStaticObjectsContent(codec, &b.proposerSlashings, constants.MaxProposerSlashings) ssz.DefineSliceOfStaticObjectsContent(codec, &b.attesterSlashings, constants.MaxAttesterSlashings) ssz.DefineSliceOfStaticObjectsContent(codec, &b.attestations, constants.MaxAttestations) ssz.DefineSliceOfStaticObjectsContent(codec, &b.Deposits, constants.MaxDeposits) ssz.DefineSliceOfStaticObjectsContent(codec, &b.voluntaryExits, constants.MaxVoluntaryExits) ssz.DefineDynamicObjectContent(codec, &b.ExecutionPayload) ssz.DefineSliceOfStaticObjectsContent(codec, &b.blsToExecutionChanges, constants.MaxBlsToExecutionChanges) ssz.DefineSliceOfStaticBytesContent(codec, &b.BlobKzgCommitments, 4096) if includeExecRequest { ssz.DefineDynamicObjectContent(codec, &b.executionRequests) } } // MarshalSSZ serializes the BeaconBlockBody to SSZ-encoded bytes. func (b *BeaconBlockBody) MarshalSSZ() ([]byte, error) { err := common.EnforceAllUnused( b.GetProposerSlashings(), b.GetAttesterSlashings(), b.GetAttestations(), b.GetVoluntaryExits(), b.GetSyncAggregate(), b.GetBlsToExecutionChanges(), ) if err != nil { return []byte{}, err } buf := make([]byte, ssz.Size(b)) return buf, ssz.EncodeToBytes(buf, b) } func NewEmptyBeaconBlockBodyWithVersion(version common.Version) *BeaconBlockBody { return &BeaconBlockBody{ Versionable: NewVersionable(version), Eth1Data: NewEmptyEth1Data(), ExecutionPayload: NewEmptyExecutionPayloadWithVersion(version), syncAggregate: &SyncAggregate{}, } } func (b *BeaconBlockBody) ValidateAfterDecodingSSZ() error { errUnused := common.EnforceAllUnused( b.GetProposerSlashings(), b.GetAttesterSlashings(), b.GetAttestations(), b.GetVoluntaryExits(), b.GetSyncAggregate(), b.GetBlsToExecutionChanges(), ) return errors.Join( b.ExecutionPayload.ValidateAfterDecodingSSZ(), errUnused, ) } // HashTreeRoot returns the SSZ hash tree root of the BeaconBlockBody. func (b *BeaconBlockBody) HashTreeRoot() common.Root { return ssz.HashConcurrent(b) } /* -------------------------------------------------------------------------- */ /* Getters/Setters */ /* -------------------------------------------------------------------------- */ // GetTopLevelRoots returns the top-level roots of the BeaconBlockBody. func (b *BeaconBlockBody) GetTopLevelRoots() ([]common.Root, error) { tlrs := []common.Root{ common.Root(b.GetRandaoReveal().HashTreeRoot()), b.Eth1Data.HashTreeRoot(), common.Root(b.GetGraffiti().HashTreeRoot()), b.GetProposerSlashings().HashTreeRoot(), b.GetAttesterSlashings().HashTreeRoot(), b.GetAttestations().HashTreeRoot(), b.GetDeposits().HashTreeRoot(), b.GetVoluntaryExits().HashTreeRoot(), b.syncAggregate.HashTreeRoot(), b.GetExecutionPayload().HashTreeRoot(), b.GetBlsToExecutionChanges().HashTreeRoot(), // KzgCommitments intentionally left blank - included separately for inclusion proof {}, } if version.EqualsOrIsAfter(b.GetForkVersion(), version.Electra()) { er, err := b.GetExecutionRequests() if err != nil { return nil, err } tlrs = append(tlrs, er.HashTreeRoot()) } // Ensure that the length returned is correct according to the fork version. if uint64(len(tlrs)) != b.Length() { return nil, fmt.Errorf( "top-level roots length (%d) does not match expected body length (%d)", len(tlrs), b.Length(), ) } return tlrs, nil } // Length returns the number of fields in the BeaconBlockBody struct // according to the fork version. func (b *BeaconBlockBody) Length() uint64 { if version.IsBefore(b.GetForkVersion(), version.Electra()) { return BodyLengthDeneb } return BodyLengthElectra } func (b *BeaconBlockBody) GetRandaoReveal() crypto.BLSSignature { return b.RandaoReveal } func (b *BeaconBlockBody) SetRandaoReveal(reveal crypto.BLSSignature) { b.RandaoReveal = reveal } func (b *BeaconBlockBody) GetEth1Data() *Eth1Data { return b.Eth1Data } func (b *BeaconBlockBody) SetEth1Data(eth1Data *Eth1Data) { b.Eth1Data = eth1Data } func (b *BeaconBlockBody) GetGraffiti() common.Bytes32 { return b.Graffiti } func (b *BeaconBlockBody) SetGraffiti(graffiti common.Bytes32) { b.Graffiti = graffiti } func (b *BeaconBlockBody) GetProposerSlashings() ProposerSlashings { return b.proposerSlashings } func (b *BeaconBlockBody) SetProposerSlashings(ps ProposerSlashings) { b.proposerSlashings = ps } func (b *BeaconBlockBody) GetAttesterSlashings() AttesterSlashings { return b.attesterSlashings } func (b *BeaconBlockBody) SetAttesterSlashings(ps AttesterSlashings) { b.attesterSlashings = ps } func (b *BeaconBlockBody) GetVoluntaryExits() VoluntaryExits { return b.voluntaryExits } func (b *BeaconBlockBody) SetVoluntaryExits(exits VoluntaryExits) { b.voluntaryExits = exits } func (b *BeaconBlockBody) GetDeposits() Deposits { return b.Deposits } func (b *BeaconBlockBody) SetDeposits(deposits Deposits) { b.Deposits = deposits } func (b *BeaconBlockBody) GetAttestations() Attestations { return b.attestations } func (b *BeaconBlockBody) SetAttestations(attestations Attestations) { b.attestations = attestations } func (b *BeaconBlockBody) GetSyncAggregate() *SyncAggregate { return b.syncAggregate } func (b *BeaconBlockBody) SetSyncAggregate(syncAggregate *SyncAggregate) { b.syncAggregate = syncAggregate } func (b *BeaconBlockBody) GetExecutionPayload() *ExecutionPayload { return b.ExecutionPayload } func (b *BeaconBlockBody) SetExecutionPayload(executionData *ExecutionPayload) { b.ExecutionPayload = executionData } func (b *BeaconBlockBody) GetBlsToExecutionChanges() BlsToExecutionChanges { return b.blsToExecutionChanges } func (b *BeaconBlockBody) SetBlsToExecutionChanges(blsChanges BlsToExecutionChanges) { b.blsToExecutionChanges = blsChanges } func (b *BeaconBlockBody) GetBlobKzgCommitments() eip4844.KZGCommitments[common.ExecutionHash] { return b.BlobKzgCommitments } func (b *BeaconBlockBody) SetBlobKzgCommitments(commitments eip4844.KZGCommitments[common.ExecutionHash]) { b.BlobKzgCommitments = commitments } func (b *BeaconBlockBody) GetExecutionRequests() (*ExecutionRequests, error) { if version.IsBefore(b.GetForkVersion(), version.Electra()) { return nil, errors.Wrapf(ErrFieldNotSupportedOnFork, "block version %d", b.GetForkVersion()) } if b.executionRequests == nil { return nil, errors.New("retrieved execution requests is nil") } return b.executionRequests, nil } func (b *BeaconBlockBody) SetExecutionRequests(executionRequest *ExecutionRequests) error { if executionRequest == nil { return errors.New("cannot set execution requests to nil") } if version.IsBefore(b.GetForkVersion(), version.Electra()) { return errors.Wrapf(ErrFieldNotSupportedOnFork, "block version %d", b.GetForkVersion()) } b.executionRequests = executionRequest return nil } ================================================ FILE: consensus-types/types/body_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "testing" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" sszutil "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/math/log" "github.com/berachain/beacon-kit/primitives/version" "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) func generateBeaconBlockBody(t *testing.T, v common.Version) types.BeaconBlockBody { versionable := types.NewVersionable(v) body := types.BeaconBlockBody{ Versionable: versionable, RandaoReveal: [96]byte{1, 2, 3}, Eth1Data: &types.Eth1Data{}, Graffiti: [32]byte{4, 5, 6}, Deposits: []*types.Deposit{}, ExecutionPayload: &types.ExecutionPayload{ Versionable: versionable, BaseFeePerGas: math.NewU256(0), }, BlobKzgCommitments: []eip4844.KZGCommitment{}, } body.SetProposerSlashings(types.ProposerSlashings{}) body.SetAttesterSlashings(types.AttesterSlashings{}) body.SetAttestations(types.Attestations{}) body.SetSyncAggregate(&types.SyncAggregate{}) body.SetVoluntaryExits(types.VoluntaryExits{}) body.SetBlsToExecutionChanges(types.BlsToExecutionChanges{}) if version.EqualsOrIsAfter(v, version.Electra()) { require.NoError(t, body.SetExecutionRequests(&types.ExecutionRequests{})) } return body } func TestBeaconBlockBodyBase(t *testing.T) { t.Parallel() body := types.BeaconBlockBody{ RandaoReveal: [96]byte{1, 2, 3}, Eth1Data: &types.Eth1Data{}, Graffiti: [32]byte{4, 5, 6}, Deposits: []*types.Deposit{}, } require.Equal(t, bytes.B96{1, 2, 3}, body.GetRandaoReveal()) require.NotNil(t, body.GetEth1Data()) newGraffiti := [32]byte{7, 8, 9} body.SetGraffiti(newGraffiti) require.Equal(t, newGraffiti, [32]byte(body.GetGraffiti())) require.NotNil(t, body.GetDeposits()) } func TestBeaconBlockBody(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { versionable := types.NewVersionable(v) body := types.BeaconBlockBody{ Versionable: versionable, RandaoReveal: [96]byte{1, 2, 3}, Eth1Data: &types.Eth1Data{}, Graffiti: [32]byte{4, 5, 6}, Deposits: []*types.Deposit{}, ExecutionPayload: &types.ExecutionPayload{ Versionable: versionable, BaseFeePerGas: math.NewU256(0), }, BlobKzgCommitments: []eip4844.KZGCommitment{}, } require.NotNil(t, body.GetExecutionPayload()) require.NotNil(t, body.GetBlobKzgCommitments()) if version.EqualsOrIsAfter(v, version.Electra()) { require.Equal(t, types.BodyLengthElectra, body.Length()) } else { require.Equal(t, types.BodyLengthDeneb, body.Length()) } }) } func TestBeaconBlockBody_SetBlobKzgCommitments(t *testing.T) { t.Parallel() body := types.BeaconBlockBody{} commitments := eip4844.KZGCommitments[common.ExecutionHash]{} body.SetBlobKzgCommitments(commitments) require.Equal(t, commitments, body.GetBlobKzgCommitments()) } func TestBeaconBlockBody_SetRandaoReveal(t *testing.T) { t.Parallel() body := types.BeaconBlockBody{} randaoReveal := crypto.BLSSignature{1, 2, 3} body.SetRandaoReveal(randaoReveal) require.Equal(t, randaoReveal, body.GetRandaoReveal()) } func TestBeaconBlockBody_SetEth1Data(t *testing.T) { t.Parallel() body := types.BeaconBlockBody{} eth1Data := &types.Eth1Data{} body.SetEth1Data(eth1Data) require.Equal(t, eth1Data, body.GetEth1Data()) } func TestBeaconBlockBody_SetDeposits(t *testing.T) { t.Parallel() body := types.BeaconBlockBody{} deposits := types.Deposits{} body.SetDeposits(deposits) require.Equal(t, deposits, body.GetDeposits()) } func TestBeaconBlockBody_MarshalSSZ(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { body := types.BeaconBlockBody{ Versionable: types.NewVersionable(v), RandaoReveal: [96]byte{1, 2, 3}, Eth1Data: &types.Eth1Data{}, Graffiti: [32]byte{4, 5, 6}, Deposits: []*types.Deposit{}, ExecutionPayload: &types.ExecutionPayload{}, BlobKzgCommitments: []eip4844.KZGCommitment{}, } data, err := body.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) }) } func TestBeaconBlockBody_GetTopLevelRoots(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { body := generateBeaconBlockBody(t, v) roots, err := body.GetTopLevelRoots() require.NoError(t, err) require.NotNil(t, roots) if version.EqualsOrIsAfter(v, version.Electra()) { require.Equal(t, types.BodyLengthElectra, uint64(len(roots))) } else { require.Equal(t, types.BodyLengthDeneb, uint64(len(roots))) } }) } func TestBeaconBlockBody_Empty(t *testing.T) { t.Parallel() body := types.BeaconBlockBody{} require.NotNil(t, body) } // Ensure that the ProposerSlashings field cannot be unmarshaled with data in it, // enforcing that it's unused. func TestBeaconBlockBody_UnusedProposerSlashingsEnforcement(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { blockBody := types.BeaconBlockBody{ Versionable: types.NewVersionable(v), } unused := common.UnusedType(1) blockBody.SetProposerSlashings(types.ProposerSlashings{&unused}) _, err := blockBody.MarshalSSZ() require.Error(t, err) buf := make([]byte, ssz.Size(&blockBody)) err = ssz.EncodeToBytes(buf, &blockBody) require.NoError(t, err) unmarshalledBody := types.NewEmptyBeaconBlockBodyWithVersion(v) err = sszutil.Unmarshal(buf, unmarshalledBody) require.ErrorContains(t, err, "must be unused") }) } // Ensure that the AttesterSlashings field cannot be unmarshaled with data in it, // enforcing that it's unused. func TestBeaconBlockBody_UnusedAttesterSlashingsEnforcement(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { blockBody := types.BeaconBlockBody{ Versionable: types.NewVersionable(v), } unused := common.UnusedType(1) blockBody.SetAttesterSlashings(types.AttesterSlashings{&unused}) _, err := blockBody.MarshalSSZ() require.Error(t, err) buf := make([]byte, ssz.Size(&blockBody)) err = ssz.EncodeToBytes(buf, &blockBody) require.NoError(t, err) unmarshalledBody := types.NewEmptyBeaconBlockBodyWithVersion(v) err = sszutil.Unmarshal(buf, unmarshalledBody) require.ErrorContains(t, err, "must be unused") }) } // Ensure that the Attestations field cannot be unmarshaled with data in it, // enforcing that it's unused. func TestBeaconBlockBody_UnusedAttestationsEnforcement(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { blockBody := types.BeaconBlockBody{ Versionable: types.NewVersionable(v), } unused := common.UnusedType(1) blockBody.SetAttestations(types.Attestations{&unused}) _, err := blockBody.MarshalSSZ() require.Error(t, err) buf := make([]byte, ssz.Size(&blockBody)) err = ssz.EncodeToBytes(buf, &blockBody) require.NoError(t, err) unmarshalledBody := types.NewEmptyBeaconBlockBodyWithVersion(v) err = sszutil.Unmarshal(buf, unmarshalledBody) require.ErrorContains(t, err, "must be unused") }) } // Ensure that the VoluntaryExits field cannot be unmarshaled with data in it, // enforcing that it's unused. func TestBeaconBlockBody_UnusedVoluntaryExitsEnforcement(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { blockBody := types.BeaconBlockBody{ Versionable: types.NewVersionable(v), } unused := common.UnusedType(1) blockBody.SetVoluntaryExits(types.VoluntaryExits{&unused}) _, err := blockBody.MarshalSSZ() require.Error(t, err) buf := make([]byte, ssz.Size(&blockBody)) err = ssz.EncodeToBytes(buf, &blockBody) require.NoError(t, err) unmarshalledBody := types.NewEmptyBeaconBlockBodyWithVersion(v) err = sszutil.Unmarshal(buf, unmarshalledBody) require.ErrorContains(t, err, "must be unused") }) } // Ensure that the BlsToExecutionChanges field cannot be unmarshaled with data in it, // enforcing that it's unused. func TestBeaconBlockBody_UnusedBlsToExecutionChangesEnforcement(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { blockBody := types.BeaconBlockBody{ Versionable: types.NewVersionable(v), } unused := common.UnusedType(1) blockBody.SetBlsToExecutionChanges(types.BlsToExecutionChanges{&unused}) _, err := blockBody.MarshalSSZ() require.Error(t, err) buf := make([]byte, ssz.Size(&blockBody)) err = ssz.EncodeToBytes(buf, &blockBody) require.NoError(t, err) unmarshalledBody := types.NewEmptyBeaconBlockBodyWithVersion(v) err = sszutil.Unmarshal(buf, unmarshalledBody) require.ErrorContains(t, err, "must be unused") }) } func TestBeaconBlockBody_RoundTrip_HashTreeRoot(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { body := generateBeaconBlockBody(t, v) data, err := body.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalledBody := types.NewEmptyBeaconBlockBodyWithVersion(v) err = sszutil.Unmarshal(data, unmarshalledBody) require.NoError(t, err) require.Equal(t, body.HashTreeRoot(), unmarshalledBody.HashTreeRoot()) }) } // This test explains the calculation of the KZG commitment' inclusion proof depth. func Test_KZGCommitmentInclusionProofDepth(t *testing.T) { t.Parallel() maxUint8 := uint64(^uint8(0)) cs, err := spec.DevnetChainSpec() require.NoError(t, err) // Depth of the partial BeaconBlockBody merkle tree. This is partial // because we only include as much as we need to prove the inclusion of // the KZG commitments. blockBodyMerkleDepth := uint64(log.ILog2Floor(uint64(types.KZGGeneralizedIndex))) require.Less(t, blockBodyMerkleDepth, maxUint8) // The depth of the merkle tree of the KZG Commitments, including the +1 // for the length mixin. commitmentProofMerkleDepth := uint64(log.ILog2Ceil(cs.MaxBlobCommitmentsPerBlock())) + 1 require.Less(t, commitmentProofMerkleDepth, maxUint8) // InclusionProofDepth is the combined depth of all of these things. expectedInclusionProofDepth := blockBodyMerkleDepth + commitmentProofMerkleDepth require.Less(t, expectedInclusionProofDepth, maxUint8) // Grab the inclusionProofDepth from beacon-kit. actualInclusionProofDepth := types.KZGInclusionProofDepth require.Less(t, uint64(actualInclusionProofDepth), maxUint8) require.Equal(t, uint8(expectedInclusionProofDepth), uint8(actualInclusionProofDepth)) } ================================================ FILE: consensus-types/types/consolidation_request.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" sszutil "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/karalabe/ssz" ) const sszConsolidationRequestSize = 116 // Compile-time check to ensure ConsolidationRequest implements the necessary interfaces. var ( _ ssz.StaticObject = (*ConsolidationRequest)(nil) _ constraints.SSZMarshallable = (*ConsolidationRequest)(nil) ) // ConsolidationRequest is introduced in Pectra but not used by us. // We keep it so we can maintain parity tests with other SSZ implementations. type ConsolidationRequest struct { SourceAddress common.ExecutionAddress SourcePubKey crypto.BLSPubkey TargetPubKey crypto.BLSPubkey } /* -------------------------------------------------------------------------- */ /* Consolidation Request SSZ */ /* -------------------------------------------------------------------------- */ func (c *ConsolidationRequest) ValidateAfterDecodingSSZ() error { return nil } func (c *ConsolidationRequest) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticBytes(codec, &c.SourceAddress) ssz.DefineStaticBytes(codec, &c.SourcePubKey) ssz.DefineStaticBytes(codec, &c.TargetPubKey) } func (c *ConsolidationRequest) SizeSSZ(_ *ssz.Sizer) uint32 { return sszConsolidationRequestSize } func (c *ConsolidationRequest) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(c)) return buf, ssz.EncodeToBytes(buf, c) } // HashTreeRoot returns the hash tree root of the Deposits. func (c *ConsolidationRequest) HashTreeRoot() common.Root { return ssz.HashSequential(c) } /* -------------------------------------------------------------------------- */ /* Consolidation Requests SSZ */ /* -------------------------------------------------------------------------- */ // Compile-time check to ensure ConsolidationRequests implements the necessary interfaces. var _ constraints.SSZMarshaler = (*ConsolidationRequests)(nil) // ConsolidationRequests is used for SSZ unmarshalling a list of ConsolidationRequest type ConsolidationRequests []*ConsolidationRequest // MarshalSSZ marshals the ConsolidationRequests object to SSZ format by encoding each consolidation request individually. func (cr ConsolidationRequests) MarshalSSZ() ([]byte, error) { return sszutil.MarshalItemsEIP7685(cr) } // ValidateAfterDecodingSSZ validates the ConsolidationRequests object after decoding. func (cr ConsolidationRequests) ValidateAfterDecodingSSZ() error { if len(cr) > constants.MaxConsolidationRequestsPerPayload { return fmt.Errorf( "invalid number of consolidation requests, got %d max %d", len(cr), constants.MaxConsolidationRequestsPerPayload, ) } return nil } // DecodeConsolidationRequests decodes SSZ data by decoding each request individually. func DecodeConsolidationRequests(data []byte) (ConsolidationRequests, error) { maxSize := constants.MaxConsolidationRequestsPerPayload * sszConsolidationRequestSize if len(data) > maxSize { return nil, fmt.Errorf( "invalid consolidation requests SSZ size, requests should not be more than the "+ "max per payload, got %d max %d", len(data), maxSize, ) } if len(data) < sszConsolidationRequestSize { return nil, fmt.Errorf( "invalid consolidation requests SSZ size, got %d expected at least %d", len(data), sszConsolidationRequestSize, ) } if len(data)%sszConsolidationRequestSize != 0 { return nil, fmt.Errorf( "invalid data length: %d is not a multiple of consolidation request size %d", len(data), sszConsolidationRequestSize, ) } // Use the EIP-7685 unmarshalItems helper. return sszutil.UnmarshalItemsEIP7685( data, sszConsolidationRequestSize, func() *ConsolidationRequest { return new(ConsolidationRequest) }, ) } ================================================ FILE: consensus-types/types/consolidation_request_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "fmt" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/ssz" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" "github.com/stretchr/testify/require" ) func TestConsolidationRequest_ValidValuesSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string consolidationRequest *types.ConsolidationRequest }{ { name: "basic", consolidationRequest: &types.ConsolidationRequest{ // 20-byte execution address for SourceAddress SourceAddress: common.ExecutionAddress{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, }, // 48-byte public key for SourcePubKey SourcePubKey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, // 48-byte public key for TargetPubKey TargetPubKey: crypto.BLSPubkey{ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, }, }, }, { name: "max values", consolidationRequest: &types.ConsolidationRequest{ SourceAddress: common.ExecutionAddress{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, SourcePubKey: crypto.BLSPubkey{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, TargetPubKey: crypto.BLSPubkey{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, }, }, { name: "random-ish values", consolidationRequest: &types.ConsolidationRequest{ SourceAddress: common.ExecutionAddress{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, }, SourcePubKey: crypto.BLSPubkey{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, }, TargetPubKey: crypto.BLSPubkey{ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, }, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // Marshal the original consolidation request. crBytes, err := tc.consolidationRequest.MarshalSSZ() require.NoError(t, err) // Unmarshal into a Prysm consolidation request. var prysmCR enginev1.ConsolidationRequest err = prysmCR.UnmarshalSSZ(crBytes) require.NoError(t, err) prysmHTR, err := prysmCR.HashTreeRoot() require.NoError(t, err) crHTR := tc.consolidationRequest.HashTreeRoot() // Compare the HashTreeRoots. This effectively tests that all fields were encoded correctly. require.Equal(t, crHTR[:], prysmHTR[:]) // Marshal the Prysm consolidation request. prysmCRBytes, err := prysmCR.MarshalSSZ() require.NoError(t, err) // Unmarshal back into a new ConsolidationRequest. var recomputedCR types.ConsolidationRequest err = ssz.Unmarshal(prysmCRBytes, &recomputedCR) require.NoError(t, err) // Compare that the original and recomputed consolidation requests match. require.Equal(t, *tc.consolidationRequest, recomputedCR) }) } } //nolint:paralleltest // Invalid SSZ values cannot be run in parallel due to zeroalloc, which is global shared memory. func TestConsolidationRequest_InvalidValuesUnmarshalSSZ(t *testing.T) { // Build a valid consolidation request to get a baseline valid payload. validConsolidation := &types.ConsolidationRequest{ SourceAddress: common.ExecutionAddress{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, }, SourcePubKey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, TargetPubKey: crypto.BLSPubkey{ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, }, } validBytes, err := validConsolidation.MarshalSSZ() require.NoError(t, err) // Build a slice of invalid payloads. invalidPayloads := [][]byte{ nil, // nil slice {}, // empty slice []byte("this is not ssz"), // arbitrary non-SSZ data {0x00, 0x01, 0x02}, // too short to be valid // A truncated valid payload. func() []byte { if len(validBytes) > 5 { return validBytes[:len(validBytes)-5] } return validBytes }(), // A valid payload with extra trailing bytes. func() []byte { extra := []byte{0xAA, 0xBB, 0xCC, 0xDD} return append(validBytes, extra...) }(), } for i, payload := range invalidPayloads { i, payload := i, payload // capture loop variables t.Run(fmt.Sprintf("invalidConsolidation_%d", i), func(t *testing.T) { // Ensure that calling UnmarshalSSZ does not panic and returns an error. require.NotPanics(t, func() { var c types.ConsolidationRequest err = ssz.Unmarshal(payload, &c) require.Error(t, err, "expected error for payload %v", payload) }) }) } } ================================================ FILE: consensus-types/types/deposit.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // depositSize is the size of the SSZ encoding of a Deposit. const depositSize = 192 // 48 + 32 + 8 + 96 + 8 // Compile-time assertions to ensure Deposit implements necessary interfaces. var ( _ ssz.StaticObject = (*Deposit)(nil) _ constraints.SSZMarshallableRootable = (*Deposit)(nil) ) // Deposit into the consensus layer from the deposit contract in the execution // layer. type Deposit struct { // Public key of the validator specified in the deposit. Pubkey crypto.BLSPubkey `json:"pubkey"` // A staking credentials with // 1 byte prefix + 11 bytes padding + 20 bytes address = 32 bytes. Credentials WithdrawalCredentials `json:"credentials"` // Deposit amount in gwei. Amount math.Gwei `json:"amount"` // Signature of the deposit data. Signature crypto.BLSSignature `json:"signature"` // Index of the deposit in the deposit contract. Index uint64 `json:"index"` } func NewEmptyDeposit() *Deposit { return &Deposit{} } // Equals returns true if the Deposit is equal to the other. func (d *Deposit) Equals(o *Deposit) bool { return d.Pubkey == o.Pubkey && d.Credentials == o.Credentials && d.Amount == o.Amount && d.Signature == o.Signature && d.Index == o.Index } // VerifySignature verifies the deposit data and signature. func (d *Deposit) VerifySignature( forkData *ForkData, domainType common.DomainType, signatureVerificationFn func( pubkey crypto.BLSPubkey, message []byte, signature crypto.BLSSignature, ) error, ) error { return (&DepositMessage{ Pubkey: d.Pubkey, Credentials: d.Credentials, Amount: d.Amount, }).VerifyCreateValidator( forkData, d.Signature, domainType, signatureVerificationFn, ) } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // DefineSSZ defines the SSZ encoding for the Deposit object. func (d *Deposit) DefineSSZ(c *ssz.Codec) { ssz.DefineStaticBytes(c, &d.Pubkey) ssz.DefineStaticBytes(c, &d.Credentials) ssz.DefineUint64(c, &d.Amount) ssz.DefineStaticBytes(c, &d.Signature) ssz.DefineUint64(c, &d.Index) } // MarshalSSZ marshals the Deposit object to SSZ format. func (d *Deposit) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(d)) return buf, ssz.EncodeToBytes(buf, d) } func (*Deposit) ValidateAfterDecodingSSZ() error { return nil } // SizeSSZ returns the SSZ encoded size of the Deposit object. func (d *Deposit) SizeSSZ(*ssz.Sizer) uint32 { return depositSize } // HashTreeRoot computes the Merkleization of the Deposit object. func (d *Deposit) HashTreeRoot() common.Root { return ssz.HashSequential(d) } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo marshals the Deposit object into a pre-allocated byte slice. func (d *Deposit) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := d.MarshalSSZ() if err != nil { return nil, err } dst = append(dst, bz...) return dst, nil } // HashTreeRootWith ssz hashes the Deposit object with a hasher. func (d *Deposit) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'Pubkey' hh.PutBytes(d.Pubkey[:]) // Field (1) 'Credentials' hh.PutBytes(d.Credentials[:]) // Field (2) 'Amount' hh.PutUint64(uint64(d.Amount)) // Field (3) 'Signature' hh.PutBytes(d.Signature[:]) // Field (4) 'Index' hh.PutUint64(d.Index) hh.Merkleize(indx) return nil } // GetTree ssz hashes the Deposit object. func (d *Deposit) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(d) } /* -------------------------------------------------------------------------- */ /* Getters and Setters */ /* -------------------------------------------------------------------------- */ // GetAmount returns the deposit amount in gwei. func (d *Deposit) GetAmount() math.Gwei { return d.Amount } // GetPubkey returns the public key of the validator specified in the deposit. func (d *Deposit) GetPubkey() crypto.BLSPubkey { return d.Pubkey } // GetIndex returns the index of the deposit in the deposit contract. func (d *Deposit) GetIndex() math.U64 { return math.U64(d.Index) } // GetSignature returns the signature of the deposit data. func (d *Deposit) GetSignature() crypto.BLSSignature { return d.Signature } // GetWithdrawalCredentials returns the staking credentials of the deposit. func (d *Deposit) GetWithdrawalCredentials() WithdrawalCredentials { return d.Credentials } // HasEth1WithdrawalCredentials as defined in the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/validator.md#eth1_address_withdrawal_prefix func (d *Deposit) HasEth1WithdrawalCredentials() bool { return d.Credentials.IsValidEth1WithdrawalCredentials() } ================================================ FILE: consensus-types/types/deposit_message.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/karalabe/ssz" ) // DepositMessage represents a deposit message as defined in the Ethereum 2.0 // specification. // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#depositmessage type DepositMessage struct { // Public key of the validator specified in the deposit. Pubkey crypto.BLSPubkey `json:"pubkey"` // A staking credentials with // 1 byte prefix + 11 bytes padding + 20 bytes address = 32 bytes. Credentials WithdrawalCredentials `json:"credentials"` // Deposit amount in gwei. Amount math.Gwei `json:"amount"` } // CreateAndSignDepositMessage constructs and signs a deposit message. func CreateAndSignDepositMessage( forkData *ForkData, domainType common.DomainType, signer crypto.BLSSigner, credentials WithdrawalCredentials, amount math.Gwei, ) (*DepositMessage, crypto.BLSSignature, error) { domain := forkData.ComputeDomain(domainType) depositMessage := &DepositMessage{ Pubkey: signer.PublicKey(), Credentials: credentials, Amount: amount, } signingRoot := ComputeSigningRoot(depositMessage, domain) signature, err := signer.Sign(signingRoot[:]) if err != nil { return nil, crypto.BLSSignature{}, err } return depositMessage, signature, nil } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the DepositMessage object in SSZ encoding. func (*DepositMessage) SizeSSZ(*ssz.Sizer) uint32 { //nolint:mnd // 48 + 32 + 8 = 88. return 88 } // DefineSSZ defines the SSZ encoding for the DepositMessage object. func (dm *DepositMessage) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticBytes(codec, &dm.Pubkey) ssz.DefineStaticBytes(codec, &dm.Credentials) ssz.DefineUint64(codec, &dm.Amount) } // HashTreeRoot computes the SSZ hash tree root of the DepositMessage object. func (dm *DepositMessage) HashTreeRoot() common.Root { return ssz.HashSequential(dm) } // MarshalSSZTo marshals the DepositMessage object to SSZ format into the // provided // buffer. func (dm *DepositMessage) MarshalSSZTo(buf []byte) ([]byte, error) { return buf, ssz.EncodeToBytes(buf, dm) } // MarshalSSZ marshals the DepositMessage object to SSZ format. func (dm *DepositMessage) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(dm)) return dm.MarshalSSZTo(buf) } // UnmarshalSSZ unmarshals the DepositMessage object from SSZ format. func (dm *DepositMessage) UnmarshalSSZ(buf []byte) error { return ssz.DecodeFromBytes(buf, dm) } // VerifyCreateValidator verifies the deposit data when attempting to create a // new validator from a given deposit. func (dm *DepositMessage) VerifyCreateValidator( forkData *ForkData, signature crypto.BLSSignature, domainType common.DomainType, signatureVerificationFn func( pubkey crypto.BLSPubkey, message []byte, signature crypto.BLSSignature, ) error, ) error { signingRoot := ComputeSigningRoot( dm, forkData.ComputeDomain(domainType)) if err := signatureVerificationFn( dm.Pubkey, signingRoot[:], signature, ); err != nil { return errors.Join(err, ErrDepositMessage) } return nil } ================================================ FILE: consensus-types/types/deposit_message_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" types "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/crypto/mocks" "github.com/berachain/beacon-kit/primitives/math" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestCreateAndSignDepositMessage(t *testing.T) { t.Parallel() forkData := &types.ForkData{ CurrentVersion: common.Version{0x00, 0x00, 0x00, 0x04}, GenesisValidatorsRoot: common.Root{0x00, 0x00, 0x00, 0x00}, } domainType := common.DomainType{ 0x01, 0x00, 0x00, 0x00, } mocksSigner := &mocks.Blssigner{} mocksSigner.On("PublicKey").Return(crypto.BLSPubkey{}) mocksSigner.On("Sign", mock.Anything).Return(crypto.BLSSignature{}, nil) credentials := types.WithdrawalCredentials{} amount := math.Gwei(32) depositMessage, signature, err := types.CreateAndSignDepositMessage( forkData, domainType, mocksSigner, credentials, amount, ) require.NoError(t, err) require.NotNil(t, depositMessage) require.NotNil(t, signature) } func TestDepositMessage_MarshalUnmarshalSSZ(t *testing.T) { t.Parallel() original := &types.DepositMessage{ Pubkey: crypto.BLSPubkey{}, Credentials: types.WithdrawalCredentials{}, Amount: math.Gwei(1000), } data, err := original.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) var unmarshalled types.DepositMessage err = unmarshalled.UnmarshalSSZ(data) require.NoError(t, err) require.Equal(t, original, &unmarshalled) } func TestDepositMessage_MarshalSSZTo(t *testing.T) { t.Parallel() original := &types.DepositMessage{ Pubkey: crypto.BLSPubkey{}, Credentials: types.WithdrawalCredentials{}, Amount: math.Gwei(1000), } buf := make([]byte, karalabessz.Size(original)) data, err := original.MarshalSSZTo(buf) require.NoError(t, err) var unmarshalled types.DepositMessage err = unmarshalled.UnmarshalSSZ(data) require.NoError(t, err) require.Equal(t, original, &unmarshalled) } func TestDepositMessage_UnmarshalSSZ_ErrSize(t *testing.T) { t.Parallel() buf := make([]byte, 10) // size less than 88 var unmarshalledDepositMessage types.DepositMessage err := unmarshalledDepositMessage.UnmarshalSSZ(buf) require.ErrorIs(t, err, io.ErrUnexpectedEOF) } func TestDepositMessage_VerifyCreateValidator_Error(t *testing.T) { t.Parallel() original := &types.DepositMessage{ Pubkey: crypto.BLSPubkey{}, Credentials: types.WithdrawalCredentials{}, Amount: math.Gwei(1000), } forkData := &types.ForkData{ CurrentVersion: common.Version{0, 0, 0, 0}, GenesisValidatorsRoot: common.Root{}, } signature := crypto.BLSSignature{} // Define a signature verification function that always returns an error signatureVerificationFn := func( _ crypto.BLSPubkey, _ []byte, _ crypto.BLSSignature, ) error { return errors.New("signature verification failed") } domainType := common.DomainType{ 0x01, 0x00, 0x00, 0x00, } err := original.VerifyCreateValidator( forkData, signature, domainType, signatureVerificationFn, ) require.ErrorIs(t, err, types.ErrDepositMessage) } ================================================ FILE: consensus-types/types/deposit_request.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/encoding/ssz" ) // DepositRequest is introduced in EIP6110 which is currently not processed. type DepositRequest = Deposit // Compile-time check to ensure DepositRequests implements the necessary interfaces. var _ constraints.SSZMarshaler = (*DepositRequests)(nil) // DepositRequests is used for SSZ unmarshalling a list of DepositRequest type DepositRequests []*DepositRequest // MarshalSSZ marshals the Deposits object to SSZ format by encoding each deposit individually. func (dr DepositRequests) MarshalSSZ() ([]byte, error) { return ssz.MarshalItemsEIP7685(dr) } // ValidateAfterDecodingSSZ validates the DepositRequests object after decoding. func (dr DepositRequests) ValidateAfterDecodingSSZ() error { if len(dr) > constants.MaxDepositRequestsPerPayload { return fmt.Errorf( "invalid number of deposit requests, got %d max %d", len(dr), constants.MaxDepositRequestsPerPayload, ) } return nil } // DecodeDepositRequests decodes SSZ data by decoding each request individually. func DecodeDepositRequests(data []byte) (DepositRequests, error) { maxSize := constants.MaxDepositRequestsPerPayload * depositSize if len(data) > maxSize { return nil, fmt.Errorf( "invalid deposit requests SSZ size, requests should not be more than the max per "+ "payload, got %d max %d", len(data), maxSize, ) } if len(data) < depositSize { return nil, fmt.Errorf( "invalid deposit requests SSZ size, got %d expected at least %d", len(data), depositSize, ) } // Use the EIP-7685 unmarshalItems helper. return ssz.UnmarshalItemsEIP7685( data, depositSize, func() *DepositRequest { return new(DepositRequest) }, ) } ================================================ FILE: consensus-types/types/deposit_request_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "fmt" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" "github.com/stretchr/testify/require" ) func TestDepositRequest_ValidValuesSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string depositRequest *types.DepositRequest }{ { name: "basic", depositRequest: &types.DepositRequest{ // 48-byte public key Pubkey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, // 32-byte withdrawal credentials Credentials: [32]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, }, Amount: 1000, // 96-byte BLS signature Signature: crypto.BLSSignature{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, }, Index: 1, }, }, { name: "zero amount", depositRequest: &types.DepositRequest{ Pubkey: crypto.BLSPubkey{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, Credentials: [32]byte{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, }, Amount: 0, Signature: crypto.BLSSignature{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, }, Index: 2, }, }, { name: "max values", depositRequest: &types.DepositRequest{ Pubkey: crypto.BLSPubkey{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, Credentials: [32]byte{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, Amount: 1<<64 - 1, Signature: crypto.BLSSignature{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, Index: 3, }, }, { name: "random-ish values", depositRequest: &types.DepositRequest{ Pubkey: crypto.BLSPubkey{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, }, Credentials: [32]byte{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, }, Amount: 54321, Signature: crypto.BLSSignature{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, }, Index: 4, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // Marshal the original deposit request. depositRequestBytes, err := tc.depositRequest.MarshalSSZ() require.NoError(t, err) // Unmarshal into a Prysm deposit request. var prysmDeposit enginev1.DepositRequest err = prysmDeposit.UnmarshalSSZ(depositRequestBytes) require.NoError(t, err) // Compare the HashTreeRoots: first compute the HTRs. prysmHTR, err := prysmDeposit.HashTreeRoot() require.NoError(t, err) depositHTR := tc.depositRequest.HashTreeRoot() // Compare the HashTreeRoots to ensure all fields were correctly interpreted. require.Equal(t, depositHTR[:], prysmHTR[:]) // Marshal the Prysm deposit request. prysmDepositBytes, err := prysmDeposit.MarshalSSZ() require.NoError(t, err) // Unmarshal back into a new DepositRequest. var recomputedDepositRequest types.DepositRequest err = ssz.Unmarshal(prysmDepositBytes, &recomputedDepositRequest) require.NoError(t, err) // Compare that the original and recomputed deposit requests match. require.Equal(t, *tc.depositRequest, recomputedDepositRequest) }) } } //nolint:paralleltest // Invalid SSZ values cannot be run in parallel due to zeroalloc, which is global shared memory. func TestDepositRequest_InvalidValuesUnmarshalSSZ(t *testing.T) { // Build a valid deposit request and marshal it to obtain a baseline valid payload. validDeposit := &types.DepositRequest{ // 48-byte public key Pubkey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, // 32-byte withdrawal credentials Credentials: [32]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, }, Amount: 1000, // 96-byte BLS signature Signature: crypto.BLSSignature{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, }, Index: 1, } validBytes, err := validDeposit.MarshalSSZ() require.NoError(t, err) // Build a slice of invalid payloads. invalidPayloads := [][]byte{ nil, // nil slice {}, // empty slice []byte("this is not ssz"), // arbitrary non-SSZ data {0x00, 0x01, 0x02}, // too short to be valid // A truncated valid payload. func() []byte { if len(validBytes) > 5 { return validBytes[:len(validBytes)-5] } return validBytes }(), // A valid payload with extra trailing bytes. func() []byte { extra := []byte{0xAA, 0xBB, 0xCC, 0xDD} return append(validBytes, extra...) }(), } // Iterate over each invalid payload. for i, payload := range invalidPayloads { i, payload := i, payload // capture range variables t.Run(fmt.Sprintf("invalidPayload_%d", i), func(t *testing.T) { require.NotPanics(t, func() { var d types.DepositRequest err = ssz.Unmarshal(payload, &d) // We expect an error for every invalid payload. require.Error(t, err, "expected error for payload %v", payload) }) }) } } func TestDepositRequests_ValidValuesSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string depositRequest types.DepositRequests }{ { name: "basic", depositRequest: []*types.DepositRequest{ { // 48-byte public key Pubkey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, // 32-byte withdrawal credentials Credentials: [32]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, }, Amount: 1000, // 96-byte BLS signature Signature: crypto.BLSSignature{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, }, Index: 1, }, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // Marshal the original deposit request. depositRequestBytes, err := tc.depositRequest.MarshalSSZ() require.NoError(t, err) // Unmarshal back into a new DepositRequest. recomputedDepositRequest, err := types.DecodeDepositRequests(depositRequestBytes) require.NoError(t, err) // Compare that the original and recomputed deposit requests match. require.Equal(t, tc.depositRequest, recomputedDepositRequest) }) } } // Tests below are adapted from Prysm // https://github.com/prysmaticlabs/prysm/blob/develop/proto/engine/v1/electra_test.go#L198-L240 const depositRequestsSSZHex = "0x706b000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000077630000000000000000000000000000000000000000000000000000000000007b00000000000000736967000000000000000" + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000c801000000000000706b000000000000000000000000000000000" + "0000000000000000000000000000000000000000000000000000000000077630000000000000000000000000000000000000000000000000" + "000000000009001000000000000736967000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020" + "00000000000000" func TestUnmarshalItems_OK(t *testing.T) { t.Parallel() drb, err := hexutil.Decode(depositRequestsSSZHex) require.NoError(t, err) exampleRequest := &types.DepositRequest{} depositRequests, err := ssz.UnmarshalItemsEIP7685( drb, int(exampleRequest.SizeSSZ(nil)), func() *types.DepositRequest { return &types.DepositRequest{} }) require.NoError(t, err) exampleRequest1 := &types.DepositRequest{ Pubkey: crypto.BLSPubkey(bytesutil.PadTo([]byte("pk"), 48)), Credentials: types.WithdrawalCredentials(bytesutil.PadTo([]byte("wc"), 32)), Amount: 123, Signature: crypto.BLSSignature(bytesutil.PadTo([]byte("sig"), 96)), Index: 456, } exampleRequest2 := &types.DepositRequest{ Pubkey: crypto.BLSPubkey(bytesutil.PadTo([]byte("pk"), 48)), Credentials: types.WithdrawalCredentials(bytesutil.PadTo([]byte("wc"), 32)), Amount: 400, Signature: crypto.BLSSignature(bytesutil.PadTo([]byte("sig"), 96)), Index: 32, } require.Equal(t, []*types.DepositRequest{exampleRequest1, exampleRequest2}, depositRequests) } func TestMarshalItems_OK(t *testing.T) { t.Parallel() exampleRequest1 := &types.DepositRequest{ Pubkey: crypto.BLSPubkey(bytesutil.PadTo([]byte("pk"), 48)), Credentials: types.WithdrawalCredentials(bytesutil.PadTo([]byte("wc"), 32)), Amount: 123, Signature: crypto.BLSSignature(bytesutil.PadTo([]byte("sig"), 96)), Index: 456, } exampleRequest2 := &types.DepositRequest{ Pubkey: crypto.BLSPubkey(bytesutil.PadTo([]byte("pk"), 48)), Credentials: types.WithdrawalCredentials(bytesutil.PadTo([]byte("wc"), 32)), Amount: 400, Signature: crypto.BLSSignature(bytesutil.PadTo([]byte("sig"), 96)), Index: 32, } drbs, err := ssz.MarshalItemsEIP7685([]*types.DepositRequest{exampleRequest1, exampleRequest2}) require.NoError(t, err) require.Equal(t, depositRequestsSSZHex, hexutil.Encode(drbs)) } ================================================ FILE: consensus-types/types/deposit_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) // generateValidDeposit generates a valid deposit for testing purposes. func generateValidDeposit() *types.Deposit { var pubKey crypto.BLSPubkey var signature crypto.BLSSignature var credentials types.WithdrawalCredentials amount := math.Gwei(32) index := uint64(1) return &types.Deposit{ Pubkey: pubKey, Credentials: credentials, Amount: amount, Signature: signature, Index: index, } } func TestDeposit_Equals(t *testing.T) { t.Parallel() // Create base deposit deposit1 := generateValidDeposit() // Test equal deposits deposit2 := &types.Deposit{ Pubkey: deposit1.Pubkey, Credentials: deposit1.Credentials, Amount: deposit1.Amount, Signature: deposit1.Signature, Index: deposit1.Index, } require.True(t, deposit1.Equals(deposit2)) // Test different pubkey differentPubkey := deposit2 differentPubkey.Pubkey[0] = 0x01 require.False(t, deposit1.Equals(differentPubkey)) // Test different credentials differentCreds := deposit2 differentCreds.Credentials[0] = 0x01 require.False(t, deposit1.Equals(differentCreds)) // Test different amount differentAmount := deposit2 differentAmount.Amount = math.Gwei(16) require.False(t, deposit1.Equals(differentAmount)) // Test different signature differentSig := deposit2 differentSig.Signature[0] = 0x01 require.False(t, deposit1.Equals(differentSig)) // Test different index differentIndex := deposit2 differentIndex.Index = 2 require.False(t, deposit1.Equals(differentIndex)) } func TestDeposit_MarshalUnmarshalSSZ(t *testing.T) { t.Parallel() originalDeposit := generateValidDeposit() // Marshal the original deposit to SSZ sszDeposit, err := originalDeposit.MarshalSSZ() require.NoError(t, err) require.NotNil(t, sszDeposit) unmarshalledDeposit := new(types.Deposit) err = ssz.Unmarshal(sszDeposit, unmarshalledDeposit) require.NoError(t, err) require.Equal(t, originalDeposit, unmarshalledDeposit) } func TestDeposit_MarshalSSZTo(t *testing.T) { t.Parallel() deposit := generateValidDeposit() buf := make([]byte, karalabessz.Size(deposit)) target, err := deposit.MarshalSSZTo(buf) require.NoError(t, err) require.NotNil(t, target) } func TestDeposit_HashTreeRoot(t *testing.T) { t.Parallel() deposit := generateValidDeposit() require.NotPanics(t, func() { _ = deposit.HashTreeRoot() }) } func TestDeposit_SizeSSZ(t *testing.T) { t.Parallel() deposit := generateValidDeposit() require.Equal(t, uint32(192), karalabessz.Size(deposit)) } func TestDeposit_HashTreeRootWith(t *testing.T) { t.Parallel() deposit := generateValidDeposit() require.NotNil(t, deposit) hasher := fastssz.NewHasher() require.NotNil(t, hasher) err := deposit.HashTreeRootWith(hasher) require.NoError(t, err) } func TestDeposit_GetTree(t *testing.T) { t.Parallel() deposit := generateValidDeposit() _, err := deposit.GetTree() require.NoError(t, err) } func TestDeposit_UnmarshalSSZ_ErrSize(t *testing.T) { t.Parallel() // Create a byte slice of incorrect size buf := make([]byte, 10) // size less than 192 var unmarshalledDeposit types.Deposit err := ssz.Unmarshal(buf, &unmarshalledDeposit) require.ErrorIs(t, err, io.ErrUnexpectedEOF) } func TestDeposit_VerifySignature(t *testing.T) { t.Parallel() deposit := generateValidDeposit() forkData := &types.ForkData{ CurrentVersion: common.Version{0x00, 0x00, 0x00, 0x04}, GenesisValidatorsRoot: common.Root{0x00, 0x00, 0x00, 0x00}, } signatureVerificationFn := func( _ crypto.BLSPubkey, _ []byte, _ crypto.BLSSignature, ) error { return nil } errVerify := deposit.VerifySignature(forkData, common.DomainType{ 0x01, 0x00, 0x00, 0x00, }, signatureVerificationFn) require.NoError(t, errVerify) } func TestDeposit_Getters(t *testing.T) { t.Parallel() deposit := generateValidDeposit() require.Equal(t, deposit.Pubkey, deposit.GetPubkey()) require.Equal(t, deposit.Credentials, deposit.GetWithdrawalCredentials()) require.Equal(t, deposit.Amount, deposit.GetAmount()) require.Equal(t, deposit.Signature, deposit.GetSignature()) require.Equal(t, math.U64(deposit.Index), deposit.GetIndex()) } ================================================ FILE: consensus-types/types/deposits.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // False positive detected. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/karalabe/ssz" ) // Deposits is a type alias for a SSZ list of Deposit containers. type Deposits []*Deposit /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the SSZ encoded size in bytes for the Deposits. func (ds Deposits) SizeSSZ(siz *ssz.Sizer, _ bool) uint32 { return ssz.SizeSliceOfStaticObjects(siz, ([]*Deposit)(ds)) } // DefineSSZ defines the SSZ encoding for the Deposits object. // TODO: get from accessible chainspec field params. func (ds Deposits) DefineSSZ(c *ssz.Codec) { c.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*Deposit)(&ds), constants.MaxDeposits) }) c.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*Deposit)(&ds), constants.MaxDeposits) }) c.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfStaticObjectsOffset(c, (*[]*Deposit)(&ds), constants.MaxDeposits) }) } // HashTreeRoot returns the hash tree root of the Deposits. func (ds Deposits) HashTreeRoot() common.Root { // TODO: determine if using HashConcurrent optimizes performance. return ssz.HashSequential(ds) } ================================================ FILE: consensus-types/types/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import "github.com/berachain/beacon-kit/errors" var ( // ErrDepositMessage is an error for when the deposit signature doesn't // match. ErrDepositMessage = errors.New("invalid deposit message") // ErrInvalidWithdrawalCredentials is an error for when the. ErrInvalidWithdrawalCredentials = errors.New( "invalid withdrawal credentials", ) // ErrForkVersionNotSupported is an error for when the fork // version is not supported. ErrForkVersionNotSupported = errors.New("fork version not supported") // ErrNilValue is an error for when a getter returns nil on a value // It should generally not occur unless we have a bug in our code and is used for defensive programming. ErrNilValue = errors.New("unexpected nil value") // ErrInclusionProofDepthExceeded is an error for when the // KZG_COMMITMENT_INCLUSION_PROOF_DEPTH calculation overflows. ErrInclusionProofDepthExceeded = errors.New("inclusion proof depth exceeded") // ErrNilPayloadHeader is an error for when the payload header is nil. ErrNilPayloadHeader = errors.New("nil payload header") // ErrInvalidValidatorStatus is an error for when the validator status is invalid. ErrInvalidValidatorStatus = errors.New("invalid validator status") // ErrFieldNotSupportedOnFork occurs when attempting to retrieve a field on a fork on which it is not supported ErrFieldNotSupportedOnFork = errors.New("field not supported on fork") ) ================================================ FILE: consensus-types/types/eth1data.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // Eth1DataSize is the size of the Eth1Data object in bytes. // 32 bytes for DepositRoot + 8 bytes for DepositCount + 8 bytes for BlockHash. const Eth1DataSize = 72 var ( _ ssz.StaticObject = (*Eth1Data)(nil) _ constraints.SSZMarshallableRootable = (*Eth1Data)(nil) ) type Eth1Data struct { // DepositRoot is the root of the deposit tree. DepositRoot common.Root `json:"depositRoot"` // DepositCount is the number of deposits in the deposit tree. DepositCount math.U64 `json:"depositCount"` // BlockHash is the hash of the block corresponding to the Eth1Data. BlockHash common.ExecutionHash `json:"blockHash"` } /* -------------------------------------------------------------------------- */ /* Constructor */ /* -------------------------------------------------------------------------- */ func NewEth1Data(depositRoot common.Root) *Eth1Data { return &Eth1Data{ DepositRoot: depositRoot, } } func NewEmptyEth1Data() *Eth1Data { return &Eth1Data{} } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the Eth1Data object in SSZ encoding. func (*Eth1Data) SizeSSZ(*ssz.Sizer) uint32 { return Eth1DataSize } // DefineSSZ defines the SSZ encoding for the Eth1Data object. func (e *Eth1Data) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticBytes(codec, &e.DepositRoot) ssz.DefineUint64(codec, &e.DepositCount) ssz.DefineStaticBytes(codec, &e.BlockHash) } // HashTreeRoot computes the SSZ hash tree root of the Eth1Data object. func (e *Eth1Data) HashTreeRoot() common.Root { return ssz.HashSequential(e) } // MarshalSSZ marshals the Eth1Data object to SSZ format. func (e *Eth1Data) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(e)) return buf, ssz.EncodeToBytes(buf, e) } func (*Eth1Data) ValidateAfterDecodingSSZ() error { return nil } // MarshalSSZTo marshals the Eth1Data object into a pre-allocated byte slice. func (e *Eth1Data) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := e.MarshalSSZ() if err != nil { return nil, err } return append(dst, bz...), err } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // HashTreeRootWith ssz hashes the Eth1Data object with a hasher. func (e *Eth1Data) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'DepositRoot' hh.PutBytes(e.DepositRoot[:]) // Field (1) 'DepositCount' hh.PutUint64(uint64(e.DepositCount)) // Field (2) 'BlockHash' hh.PutBytes(e.BlockHash[:]) hh.Merkleize(indx) return nil } // GetTree ssz hashes the Eth1Data object. func (e *Eth1Data) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(e) } // GetDepositCount returns the deposit count. func (e *Eth1Data) GetDepositCount() math.U64 { return e.DepositCount } ================================================ FILE: consensus-types/types/eth1data_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/ssz" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) func TestEth1Data_Serialization(t *testing.T) { t.Parallel() original := types.NewEth1Data(common.Root{}) data, err := original.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(types.Eth1Data) err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, original, unmarshalled) var buf []byte buf, err = original.MarshalSSZTo(buf) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) } func TestEth1Data_UnmarshalError(t *testing.T) { t.Parallel() var unmarshalled types.Eth1Data err := ssz.Unmarshal([]byte{}, &unmarshalled) require.ErrorIs(t, err, io.ErrUnexpectedEOF) } func TestEth1Data_SizeSSZ(t *testing.T) { t.Parallel() eth1Data := types.NewEth1Data(common.Root{}) size := karalabessz.Size(eth1Data) require.Equal(t, uint32(72), size) } func TestEth1Data_HashTreeRoot(t *testing.T) { t.Parallel() eth1Data := types.NewEth1Data(common.Root{}) require.NotPanics(t, func() { _ = eth1Data.HashTreeRoot() }) } func TestEth1Data_GetTree(t *testing.T) { t.Parallel() eth1Data := types.NewEth1Data(common.Root{}) tree, err := eth1Data.GetTree() require.NoError(t, err) require.NotNil(t, tree) } func TestEth1Data_GetDepositCount(t *testing.T) { t.Parallel() eth1Data := &types.Eth1Data{ DepositRoot: common.Root{}, DepositCount: 10, BlockHash: common.ExecutionHash{}, } count := eth1Data.GetDepositCount() require.Equal(t, uint64(10), count.Unwrap()) } ================================================ FILE: consensus-types/types/execution_requests.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" sszutil "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/karalabe/ssz" ) // 3 since three dynamic objects (Deposits, Withdrawals, Consolidations) const dynamicFieldsInExecutionRequests = 3 // Compile-time check to ensure ExecutionRequests implements the necessary interfaces. var ( _ ssz.DynamicObject = (*ExecutionRequests)(nil) _ constraints.SSZMarshallableRootable = (*ExecutionRequests)(nil) ) // EncodedExecutionRequest is the result of GetExecutionRequestsList which is spec defined. type EncodedExecutionRequest = bytes.Bytes type ExecutionRequests struct { Deposits []*DepositRequest Withdrawals []*WithdrawalRequest Consolidations []*ConsolidationRequest } func (e *ExecutionRequests) ValidateAfterDecodingSSZ() error { return errors.Join( DepositRequests(e.Deposits).ValidateAfterDecodingSSZ(), WithdrawalRequests(e.Withdrawals).ValidateAfterDecodingSSZ(), ConsolidationRequests(e.Consolidations).ValidateAfterDecodingSSZ(), ) } // GetExecutionRequestsList introduced in pectra from the consensus spec // https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-get_execution_requests_list func GetExecutionRequestsList(er *ExecutionRequests) ([]EncodedExecutionRequest, error) { if er == nil { return nil, errors.New("nil execution requests") } result := make([]EncodedExecutionRequest, 0) // Process deposit requests if non-empty. if len(er.Deposits) > 0 { depositBytes, err := sszutil.MarshalItemsEIP7685(er.Deposits) if err != nil { return nil, err } combined := append([]byte{constants.DepositRequestType}, depositBytes...) result = append(result, combined) } // Process withdrawal requests if non-empty. if len(er.Withdrawals) > 0 { withdrawalBytes, err := sszutil.MarshalItemsEIP7685(er.Withdrawals) if err != nil { return nil, err } combined := append([]byte{constants.WithdrawalRequestType}, withdrawalBytes...) result = append(result, combined) } // Process consolidation requests if non-empty. if len(er.Consolidations) > 0 { consolidationBytes, err := sszutil.MarshalItemsEIP7685(er.Consolidations) if err != nil { return nil, err } combined := append([]byte{constants.ConsolidationRequestType}, consolidationBytes...) result = append(result, combined) } return result, nil } // DecodeExecutionRequests is used to decode the result from GetPayload into an ExecutionRequests. func DecodeExecutionRequests(encodedRequests [][]byte) (*ExecutionRequests, error) { var ( result ExecutionRequests prevType *uint8 err error ) // Iterate over each encoded request group. for _, encoded := range encodedRequests { if len(encoded) < 1 { return nil, errors.New("invalid execution request, length less than 1") } // The first byte indicates the request type. reqType := encoded[0] // Enforce that request types are in strictly increasing order. if prevType != nil && *prevType >= reqType { return nil, errors.New("requests should be in sorted order and unique") } prevType = &reqType // The remaining bytes are the SSZ serialization for this group. data := encoded[1:] // Switch based on the request type. switch reqType { case constants.DepositRequestType: if result.Deposits, err = DecodeDepositRequests(data); err != nil { return nil, err } case constants.WithdrawalRequestType: if result.Withdrawals, err = DecodeWithdrawalRequests(data); err != nil { return nil, err } case constants.ConsolidationRequestType: if result.Consolidations, err = DecodeConsolidationRequests(data); err != nil { return nil, err } default: return nil, fmt.Errorf("unsupported request type %d", reqType) } } return &result, nil } /* -------------------------------------------------------------------------- */ /* Execution Requests SSZ */ /* -------------------------------------------------------------------------- */ func (e *ExecutionRequests) DefineSSZ(codec *ssz.Codec) { ssz.DefineSliceOfStaticObjectsOffset(codec, &e.Deposits, constants.MaxDepositRequestsPerPayload) ssz.DefineSliceOfStaticObjectsOffset(codec, &e.Withdrawals, constants.MaxWithdrawalRequestsPerPayload) ssz.DefineSliceOfStaticObjectsOffset(codec, &e.Consolidations, constants.MaxConsolidationRequestsPerPayload) ssz.DefineSliceOfStaticObjectsContent(codec, &e.Deposits, constants.MaxDepositRequestsPerPayload) ssz.DefineSliceOfStaticObjectsContent(codec, &e.Withdrawals, constants.MaxWithdrawalRequestsPerPayload) ssz.DefineSliceOfStaticObjectsContent(codec, &e.Consolidations, constants.MaxConsolidationRequestsPerPayload) } func (e *ExecutionRequests) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { size := constants.SSZOffsetSize * dynamicFieldsInExecutionRequests if fixed { return size } size += ssz.SizeSliceOfStaticObjects(siz, e.Deposits) size += ssz.SizeSliceOfStaticObjects(siz, e.Withdrawals) size += ssz.SizeSliceOfStaticObjects(siz, e.Consolidations) return size } func (e *ExecutionRequests) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(e)) return buf, ssz.EncodeToBytes(buf, e) } // HashTreeRoot returns the hash tree root of the Deposits. func (e *ExecutionRequests) HashTreeRoot() common.Root { return ssz.HashSequential(e) } ================================================ FILE: consensus-types/types/execution_requests_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "fmt" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/prysmaticlabs/prysm/v5/config/params" "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" "github.com/stretchr/testify/require" ) func TestExecutionRequests_ValidValuesSSZ(t *testing.T) { t.Parallel() // Create a few helper instances to reuse in test cases. // You can reuse your existing tests' values for deposit, withdrawal, and consolidation. depositBasic := &types.DepositRequest{ // 48-byte public key Pubkey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, Credentials: [32]byte{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, }, Amount: 1000, Signature: crypto.BLSSignature{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, }, Index: 1, } withdrawalBasic := &types.WithdrawalRequest{ SourceAddress: common.ExecutionAddress{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, }, ValidatorPubKey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, Amount: 1000, } consolidationBasic := &types.ConsolidationRequest{ SourceAddress: common.ExecutionAddress{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, }, SourcePubKey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, TargetPubKey: crypto.BLSPubkey{ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, }, } // Define test cases. We vary the content of each slice. testCases := []struct { name string executionRequests *types.ExecutionRequests }{ { name: "all basic", executionRequests: &types.ExecutionRequests{ Deposits: []*types.DepositRequest{depositBasic}, Withdrawals: []*types.WithdrawalRequest{withdrawalBasic}, Consolidations: []*types.ConsolidationRequest{consolidationBasic}, }, }, { name: "empty slices", executionRequests: &types.ExecutionRequests{ Deposits: []*types.DepositRequest{}, Withdrawals: []*types.WithdrawalRequest{}, Consolidations: []*types.ConsolidationRequest{}, }, }, { name: "multiple entries", executionRequests: &types.ExecutionRequests{ Deposits: []*types.DepositRequest{depositBasic, depositBasic}, Withdrawals: []*types.WithdrawalRequest{withdrawalBasic, withdrawalBasic, withdrawalBasic}, Consolidations: []*types.ConsolidationRequest{consolidationBasic, consolidationBasic}, }, }, { name: "random-ish values", executionRequests: &types.ExecutionRequests{ Deposits: []*types.DepositRequest{ { Pubkey: crypto.BLSPubkey{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, }, Credentials: [32]byte{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, }, Amount: 54321, Signature: crypto.BLSSignature{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, }, Index: 4, }, }, Withdrawals: []*types.WithdrawalRequest{ { SourceAddress: common.ExecutionAddress{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, }, ValidatorPubKey: crypto.BLSPubkey{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, }, Amount: 54321, }, }, Consolidations: []*types.ConsolidationRequest{ { SourceAddress: common.ExecutionAddress{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, }, SourcePubKey: crypto.BLSPubkey{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, }, TargetPubKey: crypto.BLSPubkey{ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, }, }, }, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // Marshal the original ExecutionRequests. execReqBytes, err := tc.executionRequests.MarshalSSZ() require.NoError(t, err) // Unmarshal into a Prysm ExecutionRequests. var prysmER enginev1.ExecutionRequests err = prysmER.UnmarshalSSZ(execReqBytes) require.NoError(t, err) prysmHTR, err := prysmER.HashTreeRoot() require.NoError(t, err) execReqHTR := tc.executionRequests.HashTreeRoot() // Compare the HashTreeRoots to ensure encoding was correct. require.Equal(t, execReqHTR[:], prysmHTR[:]) // Marshal the Prysm ExecutionRequests. prysmERBytes, err := prysmER.MarshalSSZ() require.NoError(t, err) // Unmarshal back into a new ExecutionRequests. var recomputedER types.ExecutionRequests err = ssz.Unmarshal(prysmERBytes, &recomputedER) require.NoError(t, err) // Compare that the original and recomputed ExecutionRequests match. require.Equal(t, *tc.executionRequests, recomputedER) }) } } // TestExecutionRequests_InvalidValuesUnmarshalSSZ ensures that Unmarshal must never panic. // //nolint:paralleltest // Invalid SSZ values cannot be run in parallel due to zeroalloc, which is global shared memory. func TestExecutionRequests_InvalidValuesUnmarshalSSZ(t *testing.T) { // Define several invalid payloads. invalidPayloads := [][]byte{ nil, // nil slice {}, // empty slice []byte("invalid data"), // arbitrary string data {0x00, 0x01}, // too short to be valid // A random 50-byte slice (likely invalid) func() []byte { b := make([]byte, 50) for i := range b { b[i] = byte((i * 3) % 256) } return b }(), // A truncated valid payload: marshal a valid empty ExecutionRequests and drop last 4 bytes. func() []byte { er := types.ExecutionRequests{ Deposits: []*types.DepositRequest{}, Withdrawals: []*types.WithdrawalRequest{}, Consolidations: []*types.ConsolidationRequest{}, } validBytes, err := er.MarshalSSZ() require.NoError(t, err) if len(validBytes) > 4 { return validBytes[:len(validBytes)-4] } return validBytes }(), // A valid payload with extra trailing bytes. func() []byte { er := types.ExecutionRequests{ Deposits: []*types.DepositRequest{}, Withdrawals: []*types.WithdrawalRequest{}, Consolidations: []*types.ConsolidationRequest{}, } validBytes, err := er.MarshalSSZ() require.NoError(t, err) // Append extra bytes that should make the payload invalid. extra := []byte{0xFF, 0xEE, 0xDD, 0xCC} return append(validBytes, extra...) }(), } for i, payload := range invalidPayloads { i, payload := i, payload // capture loop variables t.Run(fmt.Sprintf("invalidPayload_%d", i), func(t *testing.T) { var er types.ExecutionRequests // Ensure that calling UnmarshalSSZ with an invalid payload does not panic // and returns a non-nil error. require.NotPanics(t, func() { err := ssz.Unmarshal(payload, &er) require.Error(t, err, "Expected error for payload %v", payload) }) }) } } // Tests below are adapted from Prysm // https://github.com/prysmaticlabs/prysm/blob/develop/proto/engine/v1/electra_test.go#L15-L196 func TestDecodeExecutionRequests(t *testing.T) { t.Parallel() t.Run("All requests decode successfully", func(t *testing.T) { depositRequestBytes, err := hexutil.Decode("0x610000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000" + "620000000000000000000000000000000000000000000000000000000000000000" + "40597307000000630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "00000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) withdrawalRequestBytes, err := hexutil.Decode("0x6400000000000000000000000000000000000000" + "6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040597307000000") require.NoError(t, err) consolidationRequestBytes, err := hexutil.Decode("0x6600000000000000000000000000000000000000" + "670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{append([]byte{uint8(enginev1.DepositRequestType)}, depositRequestBytes...), append([]byte{uint8(enginev1.WithdrawalRequestType)}, withdrawalRequestBytes...), append([]byte{uint8(enginev1.ConsolidationRequestType)}, consolidationRequestBytes...)}, } requests, err := types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.NoError(t, err) require.Len(t, requests.Deposits, 1) require.Len(t, requests.Withdrawals, 1) require.Len(t, requests.Consolidations, 1) }) t.Run("Excluded requests still decode successfully when one request is missing", func(t *testing.T) { depositRequestBytes, err := hexutil.Decode("0x610000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000" + "620000000000000000000000000000000000000000000000000000000000000000" + "405973070000006300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) consolidationRequestBytes, err := hexutil.Decode("0x6600000000000000000000000000000000000000" + "670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{uint8(enginev1.DepositRequestType)}, depositRequestBytes...), append([]byte{uint8(enginev1.ConsolidationRequestType)}, consolidationRequestBytes...), }, } requests, err := types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.NoError(t, err) require.Len(t, requests.Deposits, 1) require.Empty(t, requests.Withdrawals) require.Len(t, requests.Consolidations, 1) }) t.Run("Decode execution requests should fail if ordering is not sorted", func(t *testing.T) { depositRequestBytes, err := hexutil.Decode("0x61000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000" + "620000000000000000000000000000000000000000000000000000000000000000" + "405973070000006300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) consolidationRequestBytes, err := hexutil.Decode("0x6600000000000000000000000000000000000000" + "670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{uint8(enginev1.ConsolidationRequestType)}, consolidationRequestBytes...), append([]byte{uint8(enginev1.DepositRequestType)}, depositRequestBytes...), }, } _, err = types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.ErrorContains(t, err, "requests should be in sorted order and unique") }) t.Run("Requests should error if the request type is shorter than 1 byte", func(t *testing.T) { consolidationRequestBytes, err := hexutil.Decode("0x6600000000000000000000000000000000000000" + "670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{}, []byte{}...), append([]byte{uint8(enginev1.ConsolidationRequestType)}, consolidationRequestBytes...), }, } _, err = types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.ErrorContains(t, err, "invalid execution request, length less than 1") }) t.Run("a duplicate request should fail", func(t *testing.T) { withdrawalRequestBytes, err := hexutil.Decode("0x6400000000000000000000000000000000000000" + "6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040597307000000") require.NoError(t, err) withdrawalRequestBytes2, err := hexutil.Decode("0x6400000000000000000000000000000000000000" + "6500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040597307000000") require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{uint8(enginev1.WithdrawalRequestType)}, withdrawalRequestBytes...), append([]byte{uint8(enginev1.WithdrawalRequestType)}, withdrawalRequestBytes2...), }, } _, err = types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.ErrorContains(t, err, "requests should be in sorted order and unique") }) t.Run("a duplicate withdrawals ( non 0 request type )request should fail", func(t *testing.T) { depositRequestBytes, err := hexutil.Decode("0x61000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000" + "620000000000000000000000000000000000000000000000000000000000000000" + "4059730700000063000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) depositRequestBytes2, err := hexutil.Decode("0x61000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000" + "620000000000000000000000000000000000000000000000000000000000000000" + "405973070000006300000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000000000000" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{uint8(enginev1.DepositRequestType)}, depositRequestBytes...), append([]byte{uint8(enginev1.DepositRequestType)}, depositRequestBytes2...), }, } _, err = types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.ErrorContains(t, err, "requests should be in sorted order and unique") }) t.Run("If a request type is provided, but the request list is shorter than the ssz of 1 request we error", func(t *testing.T) { consolidationRequestBytes, err := hexutil.Decode("0x6600000000000000000000000000000000000000" + "670000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + "680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{uint8(enginev1.DepositRequestType)}, []byte{}...), append([]byte{uint8(enginev1.ConsolidationRequestType)}, consolidationRequestBytes...), }, } _, err = types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.ErrorContains(t, err, "invalid deposit requests SSZ size, got 0 expected at least 192") }) t.Run("If deposit requests are over the max allowed per payload then we should error", func(t *testing.T) { requests := make([]*enginev1.DepositRequest, constants.MaxDepositRequestsPerPayload+1) for i := range requests { requests[i] = &enginev1.DepositRequest{ Pubkey: bytesutil.PadTo([]byte("pk"), 48), WithdrawalCredentials: bytesutil.PadTo([]byte("wc"), 32), Amount: 123, Signature: bytesutil.PadTo([]byte("sig"), 96), Index: 456, } } by, err := ssz.MarshalItemsEIP7685(requests) require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{uint8(enginev1.DepositRequestType)}, by...), }, } _, err = types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.ErrorContains(t, err, "invalid deposit requests SSZ size, requests should not be more than the max per payload") }) t.Run("If withdrawal requests are over the max allowed per payload then we should error", func(t *testing.T) { requests := make([]*enginev1.WithdrawalRequest, params.BeaconConfig().MaxWithdrawalRequestsPerPayload+1) for i := range requests { requests[i] = &enginev1.WithdrawalRequest{ SourceAddress: bytesutil.PadTo([]byte("sa"), 20), ValidatorPubkey: bytesutil.PadTo([]byte("pk"), 48), Amount: 55555, } } by, err := ssz.MarshalItemsEIP7685(requests) require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{uint8(enginev1.WithdrawalRequestType)}, by...), }, } _, err = types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.ErrorContains(t, err, "invalid withdrawal requests SSZ size, requests should not be more than the max per payload") }) t.Run("If consolidation requests are over the max allowed per payload then we should error", func(t *testing.T) { requests := make([]*enginev1.ConsolidationRequest, params.BeaconConfig().MaxConsolidationsRequestsPerPayload+1) for i := range requests { requests[i] = &enginev1.ConsolidationRequest{ SourceAddress: bytesutil.PadTo([]byte("sa"), 20), SourcePubkey: bytesutil.PadTo([]byte("pk"), 48), TargetPubkey: bytesutil.PadTo([]byte("pk"), 48), } } by, err := ssz.MarshalItemsEIP7685(requests) require.NoError(t, err) ebe := &enginev1.ExecutionBundleElectra{ ExecutionRequests: [][]byte{ append([]byte{uint8(enginev1.ConsolidationRequestType)}, by...), }, } _, err = types.DecodeExecutionRequests(ebe.GetExecutionRequests()) require.ErrorContains(t, err, "invalid consolidation requests SSZ size, requests should not be more than the max per payload") }) } func TestGetExecutionRequestsList(t *testing.T) { t.Parallel() t.Run("Empty execution requests should return an empty response and not nil", func(t *testing.T) { ebe := &types.ExecutionRequests{} b, err := types.GetExecutionRequestsList(ebe) require.NoError(t, err) require.NotNil(t, b) require.Empty(t, b) }) } ================================================ FILE: consensus-types/types/fork.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // ForkSize is the size of the Fork object in bytes. // 4 bytes for PreviousVersion + 4 bytes for CurrentVersion + 8 bytes for Epoch. const ForkSize = 16 var ( _ ssz.StaticObject = (*Fork)(nil) _ constraints.SSZMarshallableRootable = (*Fork)(nil) ) // Fork as defined in the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#fork type Fork struct { // PreviousVersion is the last version before the fork. PreviousVersion common.Version `json:"previous_version"` // CurrentVersion is the first version after the fork. CurrentVersion common.Version `json:"current_version"` // Epoch is the epoch at which the fork occurred. Epoch math.Epoch `json:"epoch"` } /* -------------------------------------------------------------------------- */ /* Constructor */ /* -------------------------------------------------------------------------- */ // New creates a new fork. func NewFork( previousVersion common.Version, currentVersion common.Version, epoch math.Epoch, ) *Fork { return &Fork{ PreviousVersion: previousVersion, CurrentVersion: currentVersion, Epoch: epoch, } } func NewEmptyFork() *Fork { return &Fork{} } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the SSZ encoded size of the Fork object in bytes. func (f *Fork) SizeSSZ(*ssz.Sizer) uint32 { return ForkSize } // DefineSSZ defines the SSZ encoding for the Fork object. func (f *Fork) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticBytes(codec, &f.PreviousVersion) ssz.DefineStaticBytes(codec, &f.CurrentVersion) ssz.DefineUint64(codec, &f.Epoch) } // MarshalSSZ marshals the Fork object to SSZ format. func (f *Fork) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(f)) return buf, ssz.EncodeToBytes(buf, f) } func (*Fork) ValidateAfterDecodingSSZ() error { return nil } // HashTreeRoot computes the SSZ hash tree root of the Fork object. func (f *Fork) HashTreeRoot() common.Root { return ssz.HashSequential(f) } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo ssz marshals the Fork object to a target array. func (f *Fork) MarshalSSZTo(buf []byte) ([]byte, error) { bz, err := f.MarshalSSZ() if err != nil { return nil, err } return append(buf, bz...), nil } // HashTreeRootWith ssz hashes the Fork object with a hasher. func (f *Fork) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'PreviousVersion' hh.PutBytes(f.PreviousVersion[:]) // Field (1) 'CurrentVersion' hh.PutBytes(f.CurrentVersion[:]) // Field (2) 'Epoch' hh.PutUint64(uint64(f.Epoch)) hh.Merkleize(indx) return nil } // GetTree ssz hashes the Fork object. func (f *Fork) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(f) } ================================================ FILE: consensus-types/types/fork_data.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure ForkData implements necessary interfaces. var ( _ ssz.StaticObject = (*ForkData)(nil) _ constraints.SSZMarshallableRootable = (*ForkData)(nil) ) // ForkData as defined in the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#forkdata type ForkData struct { // CurrentVersion is the current version of the fork. CurrentVersion common.Version // GenesisValidatorsRoot is the root of the genesis validators. GenesisValidatorsRoot common.Root } // NewForkData creates a new ForkData struct. func NewForkData( currentVersion common.Version, genesisValidatorsRoot common.Root, ) *ForkData { return &ForkData{ CurrentVersion: currentVersion, GenesisValidatorsRoot: genesisValidatorsRoot, } } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the SigningData object in SSZ encoding. func (*ForkData) SizeSSZ(*ssz.Sizer) uint32 { //nolint:mnd // 32+4 = 36. return 36 } // DefineSSZ defines the SSZ encoding for the ForkData object. func (fd *ForkData) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticBytes(codec, &fd.CurrentVersion) ssz.DefineStaticBytes(codec, &fd.GenesisValidatorsRoot) } // HashTreeRoot computes the SSZ hash tree root of the ForkData object. func (fd *ForkData) HashTreeRoot() common.Root { return ssz.HashSequential(fd) } // MarshalSSZTo marshals the ForkData object to SSZ format into the provided // buffer. func (fd *ForkData) MarshalSSZTo(buf []byte) ([]byte, error) { return buf, ssz.EncodeToBytes(buf, fd) } // MarshalSSZ marshals the ForkData object to SSZ format. func (fd *ForkData) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(fd)) return fd.MarshalSSZTo(buf) } func (*ForkData) ValidateAfterDecodingSSZ() error { return nil } // ComputeDomain as defined in the Ethereum 2.0 specification. // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_domain func (fd *ForkData) ComputeDomain( domainType common.DomainType, ) common.Domain { forkDataRoot := fd.HashTreeRoot() return common.Domain( append( domainType[:], forkDataRoot[:28]...), ) } // ComputeRandaoSigningRoot computes the randao signing root. func (fd *ForkData) ComputeRandaoSigningRoot( domainType common.DomainType, epoch math.Epoch, ) common.Root { return ComputeSigningRootUInt64( epoch.Unwrap(), fd.ComputeDomain(domainType), ) } ================================================ FILE: consensus-types/types/fork_data_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) func TestForkData_Serialization(t *testing.T) { t.Parallel() original := &types.ForkData{ CurrentVersion: common.Version{}, GenesisValidatorsRoot: common.Root{}, } data, err := original.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(types.ForkData) err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, original, unmarshalled) } func TestForkData_Unmarshal(t *testing.T) { t.Parallel() unmarshalled := new(types.ForkData) err := ssz.Unmarshal([]byte{}, unmarshalled) require.ErrorIs(t, err, io.ErrUnexpectedEOF) } func TestForkData_SizeSSZ(t *testing.T) { t.Parallel() forkData := &types.ForkData{ CurrentVersion: common.Version{}, GenesisValidatorsRoot: common.Root{}, } size := karalabessz.Size(forkData) require.Equal(t, uint32(36), size) } func TestForkData_HashTreeRoot(t *testing.T) { t.Parallel() forkData := &types.ForkData{ CurrentVersion: common.Version{}, GenesisValidatorsRoot: common.Root{}, } require.NotPanics(t, func() { _ = forkData.HashTreeRoot() }) } func TestForkData_ComputeDomain(t *testing.T) { t.Parallel() forkData := &types.ForkData{ CurrentVersion: common.Version{}, GenesisValidatorsRoot: common.Root{}, } domainType := common.DomainType{ 0x01, 0x00, 0x00, 0x00, } require.NotPanics(t, func() { _ = forkData.ComputeDomain(domainType) }) } func TestForkData_ComputeRandaoSigningRoot(t *testing.T) { t.Parallel() fd := &types.ForkData{ CurrentVersion: common.Version{}, GenesisValidatorsRoot: common.Root{}, } domainType := common.DomainType{0, 0, 0, 0} epoch := math.Epoch(1) require.NotPanics(t, func() { fd.ComputeRandaoSigningRoot(domainType, epoch) }) } func TestNewForkData(t *testing.T) { t.Parallel() currentVersion := common.Version{} genesisValidatorsRoot := common.Root{} forkData := types.NewForkData(currentVersion, genesisValidatorsRoot) require.Equal(t, currentVersion, forkData.CurrentVersion) require.Equal(t, genesisValidatorsRoot, forkData.GenesisValidatorsRoot) } func TestNew(t *testing.T) { t.Parallel() currentVersion := common.Version{} genesisValidatorsRoot := common.Root{} newForkData := types.NewForkData(currentVersion, genesisValidatorsRoot) require.Equal(t, currentVersion, newForkData.CurrentVersion) require.Equal(t, genesisValidatorsRoot, newForkData.GenesisValidatorsRoot) } ================================================ FILE: consensus-types/types/fork_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) func TestFork_Serialization(t *testing.T) { t.Parallel() original := types.NewFork( common.Version{1, 2, 3, 4}, common.Version{5, 6, 7, 8}, math.Epoch(1000), ) data, err := original.MarshalSSZ() require.NotNil(t, data) require.NoError(t, err) unmarshalled := new(types.Fork) err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, original, unmarshalled) var buf []byte buf, err = original.MarshalSSZTo(buf) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) } func TestFork_SizeSSZ(t *testing.T) { t.Parallel() fork := &types.Fork{ PreviousVersion: common.Version{1, 2, 3, 4}, CurrentVersion: common.Version{5, 6, 7, 8}, Epoch: math.Epoch(1000), } size := karalabessz.Size(fork) require.Equal(t, uint32(16), size) } func TestFork_HashTreeRoot(t *testing.T) { t.Parallel() fork := &types.Fork{ PreviousVersion: common.Version{1, 2, 3, 4}, CurrentVersion: common.Version{5, 6, 7, 8}, Epoch: math.Epoch(1000), } require.NotPanics(t, func() { _ = fork.HashTreeRoot() }) } func TestFork_GetTree(t *testing.T) { t.Parallel() fork := &types.Fork{ PreviousVersion: common.Version{1, 2, 3, 4}, CurrentVersion: common.Version{5, 6, 7, 8}, Epoch: math.Epoch(1000), } tree, err := fork.GetTree() require.NoError(t, err) require.NotNil(t, tree) } func TestFork_UnmarshalSSZ_ErrSize(t *testing.T) { t.Parallel() buf := make([]byte, 10) // size less than 16 unmarshalled := new(types.Fork) err := ssz.Unmarshal(buf, unmarshalled) require.ErrorIs(t, err, io.ErrUnexpectedEOF) } ================================================ FILE: consensus-types/types/genesis.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "math/big" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/berachain/beacon-kit/primitives/math" ) const ( defaultGasLimit = math.U64(30000000) defaultBaseFeePerGas = int64(3906250) ) // Genesis is a struct that contains the genesis information // need to start the beacon chain. type Genesis struct { // ForkVersion is the fork version of the genesis slot. ForkVersion common.Version `json:"fork_version"` // Deposits represents the deposits in the genesis. Deposits are // used to initialize the validator set. Deposits []*Deposit `json:"deposits"` // ExecutionPayloadHeader is the header of the execution payload // in the genesis. ExecutionPayloadHeader *ExecutionPayloadHeader `json:"execution_payload_header"` } // GetForkVersion returns the fork version in the genesis. func (g *Genesis) GetForkVersion() common.Version { return g.ForkVersion } // GetDeposits returns the deposits in the genesis. func (g *Genesis) GetDeposits() []*Deposit { return g.Deposits } // GetExecutionPayloadHeader returns the execution payload header. func (g *Genesis) GetExecutionPayloadHeader() *ExecutionPayloadHeader { return g.ExecutionPayloadHeader } // UnmarshalJSON for Genesis. func (g *Genesis) UnmarshalJSON( data []byte, ) error { type genesisMarshalable[Deposit any] struct { ForkVersion common.Version `json:"fork_version"` Deposits []*Deposit `json:"deposits"` ExecutionPayloadHeader json.RawMessage `json:"execution_payload_header"` } var g2 genesisMarshalable[Deposit] if err := json.Unmarshal(data, &g2); err != nil { return err } payloadHeader := NewEmptyExecutionPayloadHeaderWithVersion(g2.ForkVersion) if err := json.Unmarshal(g2.ExecutionPayloadHeader, payloadHeader); err != nil { return err } g.Deposits = g2.Deposits g.ForkVersion = g2.ForkVersion g.ExecutionPayloadHeader = payloadHeader return nil } // DefaultGenesis returns the default genesis. func DefaultGenesis(v common.Version) *Genesis { defaultHeader, err := DefaultGenesisExecutionPayloadHeader(v) if err != nil { panic(err) } return &Genesis{ ForkVersion: v, Deposits: make([]*Deposit, 0), ExecutionPayloadHeader: defaultHeader, } } // DefaultGenesisExecutionPayloadHeader returns a default ExecutionPayloadHeader. func DefaultGenesisExecutionPayloadHeader(v common.Version) (*ExecutionPayloadHeader, error) { stateRoot, err := bytes.ToBytes32( hex.MustToBytes( "0x12965ab9cbe2d2203f61d23636eb7e998f167cb79d02e452f532535641e35bcc", ), ) if err != nil { return nil, fmt.Errorf("failed generating state root: %w", err) } receiptsRoot, err := bytes.ToBytes32( hex.MustToBytes( "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", ), ) if err != nil { return nil, fmt.Errorf("failed generating receipts root: %w", err) } baseFeePerGas, err := math.NewU256FromBigInt( big.NewInt(defaultBaseFeePerGas), ) if err != nil { return nil, fmt.Errorf("failed setting base fee per gas: %w", err) } return &ExecutionPayloadHeader{ Versionable: NewVersionable(v), ParentHash: common.ExecutionHash{}, FeeRecipient: common.ExecutionAddress{}, StateRoot: stateRoot, ReceiptsRoot: receiptsRoot, LogsBloom: [256]byte{}, Random: common.Bytes32{}, Number: 0, GasLimit: defaultGasLimit, GasUsed: 0, Timestamp: 0, ExtraData: make([]byte, constants.ExtraDataLength), BaseFeePerGas: baseFeePerGas, BlockHash: common.NewExecutionHashFromHex( "0xcfff92cd918a186029a847b59aca4f83d3941df5946b06bca8de0861fc5d0850", ), TransactionsRoot: engineprimitives.Transactions(nil). HashTreeRoot(), WithdrawalsRoot: engineprimitives.Withdrawals(nil).HashTreeRoot(), BlobGasUsed: 0, ExcessBlobGas: 0, }, nil } ================================================ FILE: consensus-types/types/genesis_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:lll // long strings. package types_test import ( "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) func TestDefaultGenesis(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { g := types.DefaultGenesis(v) if !version.Equals(g.ForkVersion, v) { t.Errorf( "Expected fork version %v, but got %v", v, g.ForkVersion, ) } if len(g.Deposits) != 0 { t.Errorf("Expected no deposits, but got %v", len(g.Deposits)) } // add assertions for ExecutionPayloadHeader require.NotNil(t, g.ExecutionPayloadHeader, "Expected ExecutionPayloadHeader to be non-nil") require.Equal(t, common.ExecutionHash{}, g.ExecutionPayloadHeader.GetParentHash(), "Unexpected ParentHash") require.Equal(t, common.ExecutionAddress{}, g.ExecutionPayloadHeader.GetFeeRecipient(), "Unexpected FeeRecipient") require.Equal(t, math.U64(30000000), g.ExecutionPayloadHeader.GetGasLimit(), "Unexpected GasLimit") require.Equal(t, math.U64(0), g.ExecutionPayloadHeader.GetGasUsed(), "Unexpected GasUsed") require.Equal(t, math.U64(0), g.ExecutionPayloadHeader.GetTimestamp(), "Unexpected Timestamp") }) } func TestDefaultGenesisExecutionPayloadHeader(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { header, err := types.DefaultGenesisExecutionPayloadHeader(v) require.NoError(t, err) require.NotNil(t, header) }) } func TestGenesisGetForkVersion(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { g := types.DefaultGenesis(v) forkVersion := g.GetForkVersion() require.Equal(t, v, forkVersion) }) } func TestGenesisGetDeposits(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { g := types.DefaultGenesis(v) deposits := g.GetDeposits() require.Empty(t, deposits) }) } func TestGenesisGetExecutionPayloadHeader(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { g := types.DefaultGenesis(v) header := g.GetExecutionPayloadHeader() require.NotNil(t, header) }) } func TestDefaultGenesisPanics(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { require.NotPanics(t, func() { types.DefaultGenesis(v) }) }) } func TestGenesisUnmarshalJSON(t *testing.T) { t.Parallel() t.Helper() testCases := []struct { name string jsonInput string expectedError bool expectedFork bytes.B4 expectedDepositsLen int }{ { name: "Valid JSON with empty deposits", jsonInput: `{ "fork_version": "0x04000000", "deposits": [], "execution_payload_header": { "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000", "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "receiptsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x0", "gasLimit": "0x0", "gasUsed": "0x0", "timestamp": "0x0", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", "baseFeePerGas": "0x0", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "withdrawalsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "blobGasUsed": "0x0", "excessBlobGas": "0x0" } }`, expectedError: false, expectedFork: bytes.B4{0x4, 0x0, 0x0, 0x0}, expectedDepositsLen: 0, }, { name: "Valid JSON with non-empty deposits", jsonInput: `{ "fork_version": "0x04000000", "deposits": [{"key": "value"}], "execution_payload_header": { "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000", "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "receiptsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x0", "gasLimit": "0x0", "gasUsed": "0x0", "timestamp": "0x0", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", "baseFeePerGas": "0x0", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "withdrawalsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "blobGasUsed": "0x0", "excessBlobGas": "0x0" } }`, expectedError: false, expectedFork: bytes.B4{0x4, 0x0, 0x0, 0x0}, expectedDepositsLen: 1, }, { name: "Invalid JSON input", jsonInput: `{ "fork_version": 12345, "deposits": [], "execution_payload_header": { } }`, expectedError: true, }, { name: "Missing fields in JSON input", jsonInput: `{ "fork_version": "0x04000000", "deposits": [{"key": "value"}], "execution_payload_header": { "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000", "stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "receiptsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", "gasUsed": "0x0", "timestamp": "0x0", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000", "baseFeePerGas": "0x3b9aca", "blockHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "transactionsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "withdrawalsRoot": "0x0000000000000000000000000000000000000000000000000000000000000000", "blobGasUsed": "0x0", "excessBlobGas": "0x0" } }`, expectedError: true, }, } for _, tc := range testCases { runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { t.Run(tc.name, func(t *testing.T) { t.Parallel() g := types.DefaultGenesis(v) err := g.UnmarshalJSON([]byte(tc.jsonInput)) if tc.expectedError { require.Error(t, err, "Expected error but got none") } else { require.NoError(t, err, "Unexpected error") require.Equal(t, tc.expectedFork, g.ForkVersion, "Unexpected ForkVersion") require.Len(t, g.Deposits, tc.expectedDepositsLen, "Unexpected number of deposits") require.NotNil(t, g.ExecutionPayloadHeader, "Expected ExecutionPayloadHeader to be non-nil") } }) }) } } ================================================ FILE: consensus-types/types/header.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // BeaconBlockHeaderSize is the size of the BeaconBlockHeader object in bytes. // // Total size: Slot (8) + ProposerIndex (8) + // ParentBlockRoot (32) + StateRoot (32) + BodyRoot (32). const BeaconBlockHeaderSize = 112 var ( _ ssz.StaticObject = (*BeaconBlockHeader)(nil) _ constraints.SSZMarshallableRootable = (*BeaconBlockHeader)(nil) ) // BeaconBlockHeader represents the base of a beacon block header. type BeaconBlockHeader struct { // Slot represents the position of the block in the chain. Slot math.Slot `json:"slot"` // ProposerIndex is the index of the validator who proposed the block. ProposerIndex math.ValidatorIndex `json:"proposer_index"` // ParentBlockRoot is the hash of the parent block ParentBlockRoot common.Root `json:"parent_block_root"` // StateRoot is the hash of the state at the block. StateRoot common.Root `json:"state_root"` // BodyRoot is the root of the block body. BodyRoot common.Root `json:"body_root"` } /* -------------------------------------------------------------------------- */ /* Constructor */ /* -------------------------------------------------------------------------- */ // NewBeaconBlockHeader creates a new BeaconBlockHeader. func NewBeaconBlockHeader( slot math.Slot, proposerIndex math.ValidatorIndex, parentBlockRoot common.Root, stateRoot common.Root, bodyRoot common.Root, ) *BeaconBlockHeader { return &BeaconBlockHeader{ Slot: slot, ProposerIndex: proposerIndex, ParentBlockRoot: parentBlockRoot, StateRoot: stateRoot, BodyRoot: bodyRoot, } } func NewEmptyBeaconBlockHeader() *BeaconBlockHeader { return &BeaconBlockHeader{} } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the BeaconBlockHeader object in SSZ encoding. func (b *BeaconBlockHeader) SizeSSZ(*ssz.Sizer) uint32 { return BeaconBlockHeaderSize } // DefineSSZ defines the SSZ encoding for the BeaconBlockHeader object. func (b *BeaconBlockHeader) DefineSSZ(codec *ssz.Codec) { ssz.DefineUint64(codec, &b.Slot) ssz.DefineUint64(codec, &b.ProposerIndex) ssz.DefineStaticBytes(codec, &b.ParentBlockRoot) ssz.DefineStaticBytes(codec, &b.StateRoot) ssz.DefineStaticBytes(codec, &b.BodyRoot) } // MarshalSSZ marshals the BeaconBlockBody object to SSZ format. func (b *BeaconBlockHeader) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(b)) return buf, ssz.EncodeToBytes(buf, b) } func (*BeaconBlockHeader) ValidateAfterDecodingSSZ() error { return nil } // HashTreeRoot computes the SSZ hash tree root of the BeaconBlockHeader object. func (b *BeaconBlockHeader) HashTreeRoot() common.Root { return ssz.HashSequential(b) } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo marshals the BeaconBlockHeader object to SSZ format. func (b *BeaconBlockHeader) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := b.MarshalSSZ() if err != nil { return nil, err } dst = append(dst, bz...) return dst, nil } // HashTreeRootWith ssz hashes the BeaconBlockHeader object with a hasher. func (b *BeaconBlockHeader) HashTreeRootWith( hh fastssz.HashWalker, ) error { indx := hh.Index() // Field (0) 'Slot' hh.PutUint64(uint64(b.Slot)) // Field (1) 'ProposerIndex' hh.PutUint64(uint64(b.ProposerIndex)) // Field (2) 'ParentBlockRoot' hh.PutBytes(b.ParentBlockRoot[:]) // Field (3) 'StateRoot' hh.PutBytes(b.StateRoot[:]) // Field (4) 'BodyRoot' hh.PutBytes(b.BodyRoot[:]) hh.Merkleize(indx) return nil } // GetTree ssz hashes the BeaconBlockHeader object. func (b *BeaconBlockHeader) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(b) } /* -------------------------------------------------------------------------- */ /* Getters and Setters */ /* -------------------------------------------------------------------------- */ // Equals returns true if the Withdrawal is equal to the other. func (b *BeaconBlockHeader) Equals(rhs *BeaconBlockHeader) bool { switch { case b == nil && rhs == nil: return true case b != nil && rhs != nil: return b.Slot == rhs.Slot && b.ProposerIndex == rhs.ProposerIndex && b.ParentBlockRoot == rhs.ParentBlockRoot && b.StateRoot == rhs.StateRoot && b.BodyRoot == rhs.BodyRoot default: return false } } // GetSlot retrieves the slot of the BeaconBlockHeader. func (b *BeaconBlockHeader) GetSlot() math.Slot { return b.Slot } // SetSlot sets the slot of the BeaconBlockHeader. func (b *BeaconBlockHeader) SetSlot(slot math.Slot) { b.Slot = slot } // GetProposerIndex retrieves the proposer index of the BeaconBlockHeader. func (b *BeaconBlockHeader) GetProposerIndex() math.ValidatorIndex { return b.ProposerIndex } // SetProposerIndex sets the proposer index of the BeaconBlockHeader. func (b *BeaconBlockHeader) SetProposerIndex( proposerIndex math.ValidatorIndex, ) { b.ProposerIndex = proposerIndex } // GetParentBlockRoot retrieves the parent block root of the BeaconBlockHeader. func (b *BeaconBlockHeader) GetParentBlockRoot() common.Root { return b.ParentBlockRoot } // SetParentBlockRoot sets the parent block root of the BeaconBlockHeader. func (b *BeaconBlockHeader) SetParentBlockRoot(parentBlockRoot common.Root) { b.ParentBlockRoot = parentBlockRoot } // GetStateRoot retrieves the state root of the BeaconBlockHeader. func (b *BeaconBlockHeader) GetStateRoot() common.Root { return b.StateRoot } // SetStateRoot sets the state root of the BeaconBlockHeader. func (b *BeaconBlockHeader) SetStateRoot(stateRoot common.Root) { b.StateRoot = stateRoot } // GetBodyRoot retrieves the body root of the BeaconBlockHeader. func (b *BeaconBlockHeader) GetBodyRoot() common.Root { return b.BodyRoot } // SetBodyRoot sets the body root of the BeaconBlockHeader. func (b *BeaconBlockHeader) SetBodyRoot(bodyRoot common.Root) { b.BodyRoot = bodyRoot } ================================================ FILE: consensus-types/types/header_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) func TestBeaconBlockHeader_Equals(t *testing.T) { t.Parallel() var ( slot = math.Slot(100) valIdx = math.ValidatorIndex(200) parentBlockRoot = common.Root{1} stateRoot = common.Root{2} bodyRoot = common.Root{3} lhs = types.NewBeaconBlockHeader( slot, valIdx, parentBlockRoot, stateRoot, bodyRoot, ) ) tests := []struct { name string rhs *types.BeaconBlockHeader want bool }{ { name: "equal", rhs: types.NewBeaconBlockHeader( slot, valIdx, parentBlockRoot, stateRoot, bodyRoot, ), want: true, }, { name: "slot differs", rhs: types.NewBeaconBlockHeader( 2*slot, valIdx, parentBlockRoot, stateRoot, bodyRoot, ), want: false, }, { name: "validator index differs", rhs: types.NewBeaconBlockHeader( slot, 2*valIdx, parentBlockRoot, stateRoot, bodyRoot, ), want: false, }, { name: "parent block root differs", rhs: types.NewBeaconBlockHeader( slot, valIdx, common.Root{0xff}, stateRoot, bodyRoot, ), want: false, }, { name: "state root differs", rhs: types.NewBeaconBlockHeader( slot, valIdx, parentBlockRoot, common.Root{0xff}, bodyRoot, ), want: false, }, { name: "body root differs", rhs: types.NewBeaconBlockHeader( slot, valIdx, parentBlockRoot, stateRoot, common.Root{0xff}, ), want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got1 := lhs.Equals(tt.rhs) require.Equal(t, tt.want, got1) // check commutativity as well got2 := tt.rhs.Equals(lhs) require.Equal(t, got1, got2) // copies stays equal/disequal rhsCopy := &types.BeaconBlockHeader{} *rhsCopy = *tt.rhs got3 := rhsCopy.Equals(lhs) require.Equal(t, got1, got3) }) } } func TestBeaconBlockHeader_Serialization(t *testing.T) { t.Parallel() original := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) data, err := original.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(types.BeaconBlockHeader) err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, original, unmarshalled) var buf []byte buf, err = original.MarshalSSZTo(buf) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) } func TestBeaconBlockHeader_SizeSSZ(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) size := karalabessz.Size(header) require.Equal(t, uint32(112), size) } func TestBeaconBlockHeader_HashTreeRoot(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) _ = header.HashTreeRoot() } func TestBeaconBlockHeader_GetTree(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) tree, err := header.GetTree() require.NoError(t, err) require.NotNil(t, tree) } func TestBeaconBlockHeader_SetStateRoot(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) newStateRoot := common.Root{} header.SetStateRoot(newStateRoot) require.Equal(t, newStateRoot, header.GetStateRoot()) } func TestBeaconBlockHeader_SetSlot(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) newSlot := math.Slot(101) header.SetSlot(newSlot) require.Equal(t, newSlot, header.GetSlot()) } func TestBeaconBlockHeader_SetProposerIndex(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) newProposerIndex := math.ValidatorIndex(201) header.SetProposerIndex(newProposerIndex) require.Equal(t, newProposerIndex, header.GetProposerIndex()) } func TestBeaconBlockHeader_SetParentBlockRoot(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) newParentBlockRoot := common.Root{} header.SetParentBlockRoot(newParentBlockRoot) require.Equal(t, newParentBlockRoot, header.GetParentBlockRoot()) } func TestBeaconBlockHeader_SetBodyRoot(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{}, common.Root{}, common.Root{}, ) newBodyRoot := common.Root{} header.SetBodyRoot(newBodyRoot) require.Equal(t, newBodyRoot, header.GetBodyRoot()) } func TestBeaconBlockHeader_UnmarshalSSZ_ErrSize(t *testing.T) { t.Parallel() buf := make([]byte, 100) // Incorrect size unmarshalled := new(types.BeaconBlockHeader) err := ssz.Unmarshal(buf, unmarshalled) require.ErrorIs(t, err, io.ErrUnexpectedEOF) } ================================================ FILE: consensus-types/types/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import "github.com/berachain/beacon-kit/primitives/common" type ProposerDomain interface { // DomainTypeProposer returns the domain for proposer signatures. DomainTypeProposer() common.DomainType } ================================================ FILE: consensus-types/types/mocks/blobs_bundle.mock.go ================================================ // Code generated by mockery v2.49.0. DO NOT EDIT. package mocks import ( bytes "github.com/berachain/beacon-kit/primitives/bytes" eip4844 "github.com/berachain/beacon-kit/primitives/eip4844" mock "github.com/stretchr/testify/mock" ) // BlobsBundle is an autogenerated mock type for the BlobsBundle type type BlobsBundle struct { mock.Mock } type BlobsBundle_Expecter struct { mock *mock.Mock } func (_m *BlobsBundle) EXPECT() *BlobsBundle_Expecter { return &BlobsBundle_Expecter{mock: &_m.Mock} } // GetBlobs provides a mock function with given fields: func (_m *BlobsBundle) GetBlobs() []*eip4844.Blob { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetBlobs") } var r0 []*eip4844.Blob if rf, ok := ret.Get(0).(func() []*eip4844.Blob); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*eip4844.Blob) } } return r0 } // BlobsBundle_GetBlobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlobs' type BlobsBundle_GetBlobs_Call struct { *mock.Call } // GetBlobs is a helper method to define mock.On call func (_e *BlobsBundle_Expecter) GetBlobs() *BlobsBundle_GetBlobs_Call { return &BlobsBundle_GetBlobs_Call{Call: _e.mock.On("GetBlobs")} } func (_c *BlobsBundle_GetBlobs_Call) Run(run func()) *BlobsBundle_GetBlobs_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BlobsBundle_GetBlobs_Call) Return(_a0 []*eip4844.Blob) *BlobsBundle_GetBlobs_Call { _c.Call.Return(_a0) return _c } func (_c *BlobsBundle_GetBlobs_Call) RunAndReturn(run func() []*eip4844.Blob) *BlobsBundle_GetBlobs_Call { _c.Call.Return(run) return _c } // GetCommitments provides a mock function with given fields: func (_m *BlobsBundle) GetCommitments() []eip4844.KZGCommitment { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetCommitments") } var r0 []eip4844.KZGCommitment if rf, ok := ret.Get(0).(func() []eip4844.KZGCommitment); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]eip4844.KZGCommitment) } } return r0 } // BlobsBundle_GetCommitments_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCommitments' type BlobsBundle_GetCommitments_Call struct { *mock.Call } // GetCommitments is a helper method to define mock.On call func (_e *BlobsBundle_Expecter) GetCommitments() *BlobsBundle_GetCommitments_Call { return &BlobsBundle_GetCommitments_Call{Call: _e.mock.On("GetCommitments")} } func (_c *BlobsBundle_GetCommitments_Call) Run(run func()) *BlobsBundle_GetCommitments_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BlobsBundle_GetCommitments_Call) Return(_a0 []eip4844.KZGCommitment) *BlobsBundle_GetCommitments_Call { _c.Call.Return(_a0) return _c } func (_c *BlobsBundle_GetCommitments_Call) RunAndReturn(run func() []eip4844.KZGCommitment) *BlobsBundle_GetCommitments_Call { _c.Call.Return(run) return _c } // GetProofs provides a mock function with given fields: func (_m *BlobsBundle) GetProofs() []bytes.B48 { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetProofs") } var r0 []bytes.B48 if rf, ok := ret.Get(0).(func() []bytes.B48); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]bytes.B48) } } return r0 } // BlobsBundle_GetProofs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProofs' type BlobsBundle_GetProofs_Call struct { *mock.Call } // GetProofs is a helper method to define mock.On call func (_e *BlobsBundle_Expecter) GetProofs() *BlobsBundle_GetProofs_Call { return &BlobsBundle_GetProofs_Call{Call: _e.mock.On("GetProofs")} } func (_c *BlobsBundle_GetProofs_Call) Run(run func()) *BlobsBundle_GetProofs_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BlobsBundle_GetProofs_Call) Return(_a0 []bytes.B48) *BlobsBundle_GetProofs_Call { _c.Call.Return(_a0) return _c } func (_c *BlobsBundle_GetProofs_Call) RunAndReturn(run func() []bytes.B48) *BlobsBundle_GetProofs_Call { _c.Call.Return(run) return _c } // NewBlobsBundle creates a new instance of BlobsBundle. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBlobsBundle(t interface { mock.TestingT Cleanup(func()) }) *BlobsBundle { mock := &BlobsBundle{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: consensus-types/types/mocks/built_execution_payload_env.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( types "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" math "github.com/berachain/beacon-kit/primitives/math" mock "github.com/stretchr/testify/mock" ) // BuiltExecutionPayloadEnv is an autogenerated mock type for the BuiltExecutionPayloadEnv type type BuiltExecutionPayloadEnv struct { mock.Mock } type BuiltExecutionPayloadEnv_Expecter struct { mock *mock.Mock } func (_m *BuiltExecutionPayloadEnv) EXPECT() *BuiltExecutionPayloadEnv_Expecter { return &BuiltExecutionPayloadEnv_Expecter{mock: &_m.Mock} } // GetBlobsBundle provides a mock function with no fields func (_m *BuiltExecutionPayloadEnv) GetBlobsBundle() engineprimitives.BlobsBundle { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetBlobsBundle") } var r0 engineprimitives.BlobsBundle if rf, ok := ret.Get(0).(func() engineprimitives.BlobsBundle); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(engineprimitives.BlobsBundle) } } return r0 } // BuiltExecutionPayloadEnv_GetBlobsBundle_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlobsBundle' type BuiltExecutionPayloadEnv_GetBlobsBundle_Call struct { *mock.Call } // GetBlobsBundle is a helper method to define mock.On call func (_e *BuiltExecutionPayloadEnv_Expecter) GetBlobsBundle() *BuiltExecutionPayloadEnv_GetBlobsBundle_Call { return &BuiltExecutionPayloadEnv_GetBlobsBundle_Call{Call: _e.mock.On("GetBlobsBundle")} } func (_c *BuiltExecutionPayloadEnv_GetBlobsBundle_Call) Run(run func()) *BuiltExecutionPayloadEnv_GetBlobsBundle_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BuiltExecutionPayloadEnv_GetBlobsBundle_Call) Return(_a0 engineprimitives.BlobsBundle) *BuiltExecutionPayloadEnv_GetBlobsBundle_Call { _c.Call.Return(_a0) return _c } func (_c *BuiltExecutionPayloadEnv_GetBlobsBundle_Call) RunAndReturn(run func() engineprimitives.BlobsBundle) *BuiltExecutionPayloadEnv_GetBlobsBundle_Call { _c.Call.Return(run) return _c } // GetBlockValue provides a mock function with no fields func (_m *BuiltExecutionPayloadEnv) GetBlockValue() *math.U256 { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetBlockValue") } var r0 *math.U256 if rf, ok := ret.Get(0).(func() *math.U256); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*math.U256) } } return r0 } // BuiltExecutionPayloadEnv_GetBlockValue_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlockValue' type BuiltExecutionPayloadEnv_GetBlockValue_Call struct { *mock.Call } // GetBlockValue is a helper method to define mock.On call func (_e *BuiltExecutionPayloadEnv_Expecter) GetBlockValue() *BuiltExecutionPayloadEnv_GetBlockValue_Call { return &BuiltExecutionPayloadEnv_GetBlockValue_Call{Call: _e.mock.On("GetBlockValue")} } func (_c *BuiltExecutionPayloadEnv_GetBlockValue_Call) Run(run func()) *BuiltExecutionPayloadEnv_GetBlockValue_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BuiltExecutionPayloadEnv_GetBlockValue_Call) Return(_a0 *math.U256) *BuiltExecutionPayloadEnv_GetBlockValue_Call { _c.Call.Return(_a0) return _c } func (_c *BuiltExecutionPayloadEnv_GetBlockValue_Call) RunAndReturn(run func() *math.U256) *BuiltExecutionPayloadEnv_GetBlockValue_Call { _c.Call.Return(run) return _c } // GetEncodedExecutionRequests provides a mock function with no fields func (_m *BuiltExecutionPayloadEnv) GetEncodedExecutionRequests() []types.EncodedExecutionRequest { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetEncodedExecutionRequests") } var r0 []types.EncodedExecutionRequest if rf, ok := ret.Get(0).(func() []types.EncodedExecutionRequest); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.EncodedExecutionRequest) } } return r0 } // BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetEncodedExecutionRequests' type BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call struct { *mock.Call } // GetEncodedExecutionRequests is a helper method to define mock.On call func (_e *BuiltExecutionPayloadEnv_Expecter) GetEncodedExecutionRequests() *BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call { return &BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call{Call: _e.mock.On("GetEncodedExecutionRequests")} } func (_c *BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call) Run(run func()) *BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call) Return(_a0 []types.EncodedExecutionRequest) *BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call { _c.Call.Return(_a0) return _c } func (_c *BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call) RunAndReturn(run func() []types.EncodedExecutionRequest) *BuiltExecutionPayloadEnv_GetEncodedExecutionRequests_Call { _c.Call.Return(run) return _c } // GetExecutionPayload provides a mock function with no fields func (_m *BuiltExecutionPayloadEnv) GetExecutionPayload() *types.ExecutionPayload { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetExecutionPayload") } var r0 *types.ExecutionPayload if rf, ok := ret.Get(0).(func() *types.ExecutionPayload); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.ExecutionPayload) } } return r0 } // BuiltExecutionPayloadEnv_GetExecutionPayload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExecutionPayload' type BuiltExecutionPayloadEnv_GetExecutionPayload_Call struct { *mock.Call } // GetExecutionPayload is a helper method to define mock.On call func (_e *BuiltExecutionPayloadEnv_Expecter) GetExecutionPayload() *BuiltExecutionPayloadEnv_GetExecutionPayload_Call { return &BuiltExecutionPayloadEnv_GetExecutionPayload_Call{Call: _e.mock.On("GetExecutionPayload")} } func (_c *BuiltExecutionPayloadEnv_GetExecutionPayload_Call) Run(run func()) *BuiltExecutionPayloadEnv_GetExecutionPayload_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BuiltExecutionPayloadEnv_GetExecutionPayload_Call) Return(_a0 *types.ExecutionPayload) *BuiltExecutionPayloadEnv_GetExecutionPayload_Call { _c.Call.Return(_a0) return _c } func (_c *BuiltExecutionPayloadEnv_GetExecutionPayload_Call) RunAndReturn(run func() *types.ExecutionPayload) *BuiltExecutionPayloadEnv_GetExecutionPayload_Call { _c.Call.Return(run) return _c } // ShouldOverrideBuilder provides a mock function with no fields func (_m *BuiltExecutionPayloadEnv) ShouldOverrideBuilder() bool { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for ShouldOverrideBuilder") } var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() } else { r0 = ret.Get(0).(bool) } return r0 } // BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ShouldOverrideBuilder' type BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call struct { *mock.Call } // ShouldOverrideBuilder is a helper method to define mock.On call func (_e *BuiltExecutionPayloadEnv_Expecter) ShouldOverrideBuilder() *BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call { return &BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call{Call: _e.mock.On("ShouldOverrideBuilder")} } func (_c *BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call) Run(run func()) *BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call) Return(_a0 bool) *BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call { _c.Call.Return(_a0) return _c } func (_c *BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call) RunAndReturn(run func() bool) *BuiltExecutionPayloadEnv_ShouldOverrideBuilder_Call { _c.Call.Return(run) return _c } // NewBuiltExecutionPayloadEnv creates a new instance of BuiltExecutionPayloadEnv. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBuiltExecutionPayloadEnv(t interface { mock.TestingT Cleanup(func()) }) *BuiltExecutionPayloadEnv { mock := &BuiltExecutionPayloadEnv{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: consensus-types/types/mocks/new_payload_request.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( types "github.com/berachain/beacon-kit/consensus-types/types" common "github.com/berachain/beacon-kit/primitives/common" crypto "github.com/berachain/beacon-kit/primitives/crypto" mock "github.com/stretchr/testify/mock" ) // NewPayloadRequest is an autogenerated mock type for the NewPayloadRequest type type NewPayloadRequest struct { mock.Mock } type NewPayloadRequest_Expecter struct { mock *mock.Mock } func (_m *NewPayloadRequest) EXPECT() *NewPayloadRequest_Expecter { return &NewPayloadRequest_Expecter{mock: &_m.Mock} } // GetEncodedExecutionRequests provides a mock function with no fields func (_m *NewPayloadRequest) GetEncodedExecutionRequests() ([]types.EncodedExecutionRequest, error) { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetEncodedExecutionRequests") } var r0 []types.EncodedExecutionRequest var r1 error if rf, ok := ret.Get(0).(func() ([]types.EncodedExecutionRequest, error)); ok { return rf() } if rf, ok := ret.Get(0).(func() []types.EncodedExecutionRequest); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]types.EncodedExecutionRequest) } } if rf, ok := ret.Get(1).(func() error); ok { r1 = rf() } else { r1 = ret.Error(1) } return r0, r1 } // NewPayloadRequest_GetEncodedExecutionRequests_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetEncodedExecutionRequests' type NewPayloadRequest_GetEncodedExecutionRequests_Call struct { *mock.Call } // GetEncodedExecutionRequests is a helper method to define mock.On call func (_e *NewPayloadRequest_Expecter) GetEncodedExecutionRequests() *NewPayloadRequest_GetEncodedExecutionRequests_Call { return &NewPayloadRequest_GetEncodedExecutionRequests_Call{Call: _e.mock.On("GetEncodedExecutionRequests")} } func (_c *NewPayloadRequest_GetEncodedExecutionRequests_Call) Run(run func()) *NewPayloadRequest_GetEncodedExecutionRequests_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *NewPayloadRequest_GetEncodedExecutionRequests_Call) Return(_a0 []types.EncodedExecutionRequest, _a1 error) *NewPayloadRequest_GetEncodedExecutionRequests_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *NewPayloadRequest_GetEncodedExecutionRequests_Call) RunAndReturn(run func() ([]types.EncodedExecutionRequest, error)) *NewPayloadRequest_GetEncodedExecutionRequests_Call { _c.Call.Return(run) return _c } // GetExecutionPayload provides a mock function with no fields func (_m *NewPayloadRequest) GetExecutionPayload() *types.ExecutionPayload { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetExecutionPayload") } var r0 *types.ExecutionPayload if rf, ok := ret.Get(0).(func() *types.ExecutionPayload); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*types.ExecutionPayload) } } return r0 } // NewPayloadRequest_GetExecutionPayload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExecutionPayload' type NewPayloadRequest_GetExecutionPayload_Call struct { *mock.Call } // GetExecutionPayload is a helper method to define mock.On call func (_e *NewPayloadRequest_Expecter) GetExecutionPayload() *NewPayloadRequest_GetExecutionPayload_Call { return &NewPayloadRequest_GetExecutionPayload_Call{Call: _e.mock.On("GetExecutionPayload")} } func (_c *NewPayloadRequest_GetExecutionPayload_Call) Run(run func()) *NewPayloadRequest_GetExecutionPayload_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *NewPayloadRequest_GetExecutionPayload_Call) Return(_a0 *types.ExecutionPayload) *NewPayloadRequest_GetExecutionPayload_Call { _c.Call.Return(_a0) return _c } func (_c *NewPayloadRequest_GetExecutionPayload_Call) RunAndReturn(run func() *types.ExecutionPayload) *NewPayloadRequest_GetExecutionPayload_Call { _c.Call.Return(run) return _c } // GetForkVersion provides a mock function with no fields func (_m *NewPayloadRequest) GetForkVersion() common.Version { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetForkVersion") } var r0 common.Version if rf, ok := ret.Get(0).(func() common.Version); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(common.Version) } } return r0 } // NewPayloadRequest_GetForkVersion_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetForkVersion' type NewPayloadRequest_GetForkVersion_Call struct { *mock.Call } // GetForkVersion is a helper method to define mock.On call func (_e *NewPayloadRequest_Expecter) GetForkVersion() *NewPayloadRequest_GetForkVersion_Call { return &NewPayloadRequest_GetForkVersion_Call{Call: _e.mock.On("GetForkVersion")} } func (_c *NewPayloadRequest_GetForkVersion_Call) Run(run func()) *NewPayloadRequest_GetForkVersion_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *NewPayloadRequest_GetForkVersion_Call) Return(_a0 common.Version) *NewPayloadRequest_GetForkVersion_Call { _c.Call.Return(_a0) return _c } func (_c *NewPayloadRequest_GetForkVersion_Call) RunAndReturn(run func() common.Version) *NewPayloadRequest_GetForkVersion_Call { _c.Call.Return(run) return _c } // GetParentBeaconBlockRoot provides a mock function with no fields func (_m *NewPayloadRequest) GetParentBeaconBlockRoot() common.Root { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetParentBeaconBlockRoot") } var r0 common.Root if rf, ok := ret.Get(0).(func() common.Root); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(common.Root) } } return r0 } // NewPayloadRequest_GetParentBeaconBlockRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetParentBeaconBlockRoot' type NewPayloadRequest_GetParentBeaconBlockRoot_Call struct { *mock.Call } // GetParentBeaconBlockRoot is a helper method to define mock.On call func (_e *NewPayloadRequest_Expecter) GetParentBeaconBlockRoot() *NewPayloadRequest_GetParentBeaconBlockRoot_Call { return &NewPayloadRequest_GetParentBeaconBlockRoot_Call{Call: _e.mock.On("GetParentBeaconBlockRoot")} } func (_c *NewPayloadRequest_GetParentBeaconBlockRoot_Call) Run(run func()) *NewPayloadRequest_GetParentBeaconBlockRoot_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *NewPayloadRequest_GetParentBeaconBlockRoot_Call) Return(_a0 common.Root) *NewPayloadRequest_GetParentBeaconBlockRoot_Call { _c.Call.Return(_a0) return _c } func (_c *NewPayloadRequest_GetParentBeaconBlockRoot_Call) RunAndReturn(run func() common.Root) *NewPayloadRequest_GetParentBeaconBlockRoot_Call { _c.Call.Return(run) return _c } // GetParentProposerPubkey provides a mock function with no fields func (_m *NewPayloadRequest) GetParentProposerPubkey() *crypto.BLSPubkey { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetParentProposerPubkey") } var r0 *crypto.BLSPubkey if rf, ok := ret.Get(0).(func() *crypto.BLSPubkey); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*crypto.BLSPubkey) } } return r0 } // NewPayloadRequest_GetParentProposerPubkey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetParentProposerPubkey' type NewPayloadRequest_GetParentProposerPubkey_Call struct { *mock.Call } // GetParentProposerPubkey is a helper method to define mock.On call func (_e *NewPayloadRequest_Expecter) GetParentProposerPubkey() *NewPayloadRequest_GetParentProposerPubkey_Call { return &NewPayloadRequest_GetParentProposerPubkey_Call{Call: _e.mock.On("GetParentProposerPubkey")} } func (_c *NewPayloadRequest_GetParentProposerPubkey_Call) Run(run func()) *NewPayloadRequest_GetParentProposerPubkey_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *NewPayloadRequest_GetParentProposerPubkey_Call) Return(_a0 *crypto.BLSPubkey) *NewPayloadRequest_GetParentProposerPubkey_Call { _c.Call.Return(_a0) return _c } func (_c *NewPayloadRequest_GetParentProposerPubkey_Call) RunAndReturn(run func() *crypto.BLSPubkey) *NewPayloadRequest_GetParentProposerPubkey_Call { _c.Call.Return(run) return _c } // GetVersionedHashes provides a mock function with no fields func (_m *NewPayloadRequest) GetVersionedHashes() []common.ExecutionHash { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetVersionedHashes") } var r0 []common.ExecutionHash if rf, ok := ret.Get(0).(func() []common.ExecutionHash); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]common.ExecutionHash) } } return r0 } // NewPayloadRequest_GetVersionedHashes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVersionedHashes' type NewPayloadRequest_GetVersionedHashes_Call struct { *mock.Call } // GetVersionedHashes is a helper method to define mock.On call func (_e *NewPayloadRequest_Expecter) GetVersionedHashes() *NewPayloadRequest_GetVersionedHashes_Call { return &NewPayloadRequest_GetVersionedHashes_Call{Call: _e.mock.On("GetVersionedHashes")} } func (_c *NewPayloadRequest_GetVersionedHashes_Call) Run(run func()) *NewPayloadRequest_GetVersionedHashes_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *NewPayloadRequest_GetVersionedHashes_Call) Return(_a0 []common.ExecutionHash) *NewPayloadRequest_GetVersionedHashes_Call { _c.Call.Return(_a0) return _c } func (_c *NewPayloadRequest_GetVersionedHashes_Call) RunAndReturn(run func() []common.ExecutionHash) *NewPayloadRequest_GetVersionedHashes_Call { _c.Call.Return(run) return _c } // HasValidVersionedAndBlockHashes provides a mock function with no fields func (_m *NewPayloadRequest) HasValidVersionedAndBlockHashes() error { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for HasValidVersionedAndBlockHashes") } var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() } else { r0 = ret.Error(0) } return r0 } // NewPayloadRequest_HasValidVersionedAndBlockHashes_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasValidVersionedAndBlockHashes' type NewPayloadRequest_HasValidVersionedAndBlockHashes_Call struct { *mock.Call } // HasValidVersionedAndBlockHashes is a helper method to define mock.On call func (_e *NewPayloadRequest_Expecter) HasValidVersionedAndBlockHashes() *NewPayloadRequest_HasValidVersionedAndBlockHashes_Call { return &NewPayloadRequest_HasValidVersionedAndBlockHashes_Call{Call: _e.mock.On("HasValidVersionedAndBlockHashes")} } func (_c *NewPayloadRequest_HasValidVersionedAndBlockHashes_Call) Run(run func()) *NewPayloadRequest_HasValidVersionedAndBlockHashes_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *NewPayloadRequest_HasValidVersionedAndBlockHashes_Call) Return(_a0 error) *NewPayloadRequest_HasValidVersionedAndBlockHashes_Call { _c.Call.Return(_a0) return _c } func (_c *NewPayloadRequest_HasValidVersionedAndBlockHashes_Call) RunAndReturn(run func() error) *NewPayloadRequest_HasValidVersionedAndBlockHashes_Call { _c.Call.Return(run) return _c } // NewNewPayloadRequest creates a new instance of NewPayloadRequest. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewNewPayloadRequest(t interface { mock.TestingT Cleanup(func()) }) *NewPayloadRequest { mock := &NewPayloadRequest{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: consensus-types/types/mocks/proposer_domain.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( common "github.com/berachain/beacon-kit/primitives/common" mock "github.com/stretchr/testify/mock" ) // ProposerDomain is an autogenerated mock type for the ProposerDomain type type ProposerDomain struct { mock.Mock } type ProposerDomain_Expecter struct { mock *mock.Mock } func (_m *ProposerDomain) EXPECT() *ProposerDomain_Expecter { return &ProposerDomain_Expecter{mock: &_m.Mock} } // DomainTypeProposer provides a mock function with no fields func (_m *ProposerDomain) DomainTypeProposer() common.DomainType { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for DomainTypeProposer") } var r0 common.DomainType if rf, ok := ret.Get(0).(func() common.DomainType); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(common.DomainType) } } return r0 } // ProposerDomain_DomainTypeProposer_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DomainTypeProposer' type ProposerDomain_DomainTypeProposer_Call struct { *mock.Call } // DomainTypeProposer is a helper method to define mock.On call func (_e *ProposerDomain_Expecter) DomainTypeProposer() *ProposerDomain_DomainTypeProposer_Call { return &ProposerDomain_DomainTypeProposer_Call{Call: _e.mock.On("DomainTypeProposer")} } func (_c *ProposerDomain_DomainTypeProposer_Call) Run(run func()) *ProposerDomain_DomainTypeProposer_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *ProposerDomain_DomainTypeProposer_Call) Return(_a0 common.DomainType) *ProposerDomain_DomainTypeProposer_Call { _c.Call.Return(_a0) return _c } func (_c *ProposerDomain_DomainTypeProposer_Call) RunAndReturn(run func() common.DomainType) *ProposerDomain_DomainTypeProposer_Call { _c.Call.Return(run) return _c } // NewProposerDomain creates a new instance of ProposerDomain. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewProposerDomain(t interface { mock.TestingT Cleanup(func()) }) *ProposerDomain { mock := &ProposerDomain{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: consensus-types/types/mocks/unused_enforcer.mock.go ================================================ // Code generated by mockery v2.49.0. DO NOT EDIT. package mocks import mock "github.com/stretchr/testify/mock" // UnusedEnforcer is an autogenerated mock type for the UnusedEnforcer type type UnusedEnforcer struct { mock.Mock } type UnusedEnforcer_Expecter struct { mock *mock.Mock } func (_m *UnusedEnforcer) EXPECT() *UnusedEnforcer_Expecter { return &UnusedEnforcer_Expecter{mock: &_m.Mock} } // EnforceUnused provides a mock function with given fields: func (_m *UnusedEnforcer) EnforceUnused() error { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for EnforceUnused") } var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() } else { r0 = ret.Error(0) } return r0 } // UnusedEnforcer_EnforceUnused_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnforceUnused' type UnusedEnforcer_EnforceUnused_Call struct { *mock.Call } // EnforceUnused is a helper method to define mock.On call func (_e *UnusedEnforcer_Expecter) EnforceUnused() *UnusedEnforcer_EnforceUnused_Call { return &UnusedEnforcer_EnforceUnused_Call{Call: _e.mock.On("EnforceUnused")} } func (_c *UnusedEnforcer_EnforceUnused_Call) Run(run func()) *UnusedEnforcer_EnforceUnused_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *UnusedEnforcer_EnforceUnused_Call) Return(_a0 error) *UnusedEnforcer_EnforceUnused_Call { _c.Call.Return(_a0) return _c } func (_c *UnusedEnforcer_EnforceUnused_Call) RunAndReturn(run func() error) *UnusedEnforcer_EnforceUnused_Call { _c.Call.Return(run) return _c } // NewUnusedEnforcer creates a new instance of UnusedEnforcer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewUnusedEnforcer(t interface { mock.TestingT Cleanup(func()) }) *UnusedEnforcer { mock := &UnusedEnforcer{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: consensus-types/types/payload.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) const ( // ExecutionPayloadStaticSize is the static size of the ExecutionPayload. ExecutionPayloadStaticSize uint32 = 528 // ExtraDataSize is the size of ExtraData in bytes. ExtraDataSize = 32 ) // Compile-time assertions to ensure ExecutionPayload implements necessary interfaces. var ( _ ssz.DynamicObject = (*ExecutionPayload)(nil) _ constraints.SSZVersionedMarshallableRootable = (*ExecutionPayload)(nil) ) // ExecutionPayload represents the payload of an execution block. type ExecutionPayload struct { constraints.Versionable `json:"-"` // ParentHash is the hash of the parent block. ParentHash common.ExecutionHash `json:"parentHash"` // FeeRecipient is the address of the fee recipient. FeeRecipient common.ExecutionAddress `json:"feeRecipient"` // StateRoot is the root of the state trie. StateRoot common.Bytes32 `json:"stateRoot"` // ReceiptsRoot is the root of the receipts trie. ReceiptsRoot common.Bytes32 `json:"receiptsRoot"` // LogsBloom is the bloom filter for the logs. LogsBloom bytes.B256 `json:"logsBloom"` // Random is the prevRandao value. Random common.Bytes32 `json:"prevRandao"` // Number is the block number. Number math.U64 `json:"blockNumber"` // GasLimit is the gas limit for the block. GasLimit math.U64 `json:"gasLimit"` // GasUsed is the amount of gas used in the block. GasUsed math.U64 `json:"gasUsed"` // Timestamp is the timestamp of the block. Timestamp math.U64 `json:"timestamp"` // ExtraData is the extra data of the block. ExtraData bytes.Bytes `json:"extraData"` // BaseFeePerGas is the base fee per gas. BaseFeePerGas *math.U256 `json:"baseFeePerGas"` // BlockHash is the hash of the block. BlockHash common.ExecutionHash `json:"blockHash"` // Transactions is the list of transactions in the block. Transactions engineprimitives.Transactions `json:"transactions"` // Withdrawals is the list of withdrawals in the block. Withdrawals []*engineprimitives.Withdrawal `json:"withdrawals"` // BlobGasUsed is the amount of blob gas used in the block. BlobGasUsed math.U64 `json:"blobGasUsed"` // ExcessBlobGas is the amount of excess blob gas in the block. ExcessBlobGas math.U64 `json:"excessBlobGas"` } func NewEmptyExecutionPayloadWithVersion(forkVersion common.Version) *ExecutionPayload { ep := &ExecutionPayload{ Versionable: NewVersionable(forkVersion), BaseFeePerGas: &math.U256{}, } // For any fork version Capella onwards, non-nil withdrawals are required. if version.EqualsOrIsAfter(forkVersion, version.Capella()) { ep.Withdrawals = make([]*engineprimitives.Withdrawal, 0) } return ep } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns either the static size of the object if fixed == true, or // the total size otherwise. func (p *ExecutionPayload) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { var size = ExecutionPayloadStaticSize if fixed { return size } size += ssz.SizeDynamicBytes(siz, p.ExtraData) size += ssz.SizeSliceOfDynamicBytes(siz, p.Transactions) size += ssz.SizeSliceOfStaticObjects(siz, p.Withdrawals) return size } // DefineSSZ defines how an object is encoded/decoded. // //nolint:mnd // TODO: get from accessible chainspec field params func (p *ExecutionPayload) DefineSSZ(codec *ssz.Codec) { // Define the static data (fields and dynamic offsets) ssz.DefineStaticBytes(codec, &p.ParentHash) ssz.DefineStaticBytes(codec, &p.FeeRecipient) ssz.DefineStaticBytes(codec, &p.StateRoot) ssz.DefineStaticBytes(codec, &p.ReceiptsRoot) ssz.DefineStaticBytes(codec, &p.LogsBloom) ssz.DefineStaticBytes(codec, &p.Random) ssz.DefineUint64(codec, &p.Number) ssz.DefineUint64(codec, &p.GasLimit) ssz.DefineUint64(codec, &p.GasUsed) ssz.DefineUint64(codec, &p.Timestamp) ssz.DefineDynamicBytesOffset(codec, (*[]byte)(&p.ExtraData), 32) ssz.DefineUint256(codec, &p.BaseFeePerGas) ssz.DefineStaticBytes(codec, &p.BlockHash) ssz.DefineSliceOfDynamicBytesOffset( codec, (*[][]byte)(&p.Transactions), constants.MaxTxsPerPayload, constants.MaxBytesPerTx, ) ssz.DefineSliceOfStaticObjectsOffset(codec, &p.Withdrawals, 16) ssz.DefineUint64(codec, &p.BlobGasUsed) ssz.DefineUint64(codec, &p.ExcessBlobGas) // Define the dynamic data (fields) ssz.DefineDynamicBytesContent(codec, (*[]byte)(&p.ExtraData), 32) ssz.DefineSliceOfDynamicBytesContent( codec, (*[][]byte)(&p.Transactions), constants.MaxTxsPerPayload, constants.MaxBytesPerTx, ) ssz.DefineSliceOfStaticObjectsContent(codec, &p.Withdrawals, 16) // Note that at this state we don't have any guarantee that // p.Withdrawal is not nil, which we require Capella onwards // (empty list of withdrawals are fine). We ensure non-nillness // in ValidateAfterDecodingSSZ. } // MarshalSSZ serializes the ExecutionPayload object into a slice of bytes. func (p *ExecutionPayload) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(p)) return buf, ssz.EncodeToBytes(buf, p) } func (p *ExecutionPayload) ValidateAfterDecodingSSZ() error { // For any fork version Capella onwards, non-nil withdrawals are required. if p.Withdrawals == nil && version.EqualsOrIsAfter(p.GetForkVersion(), version.Capella()) { p.Withdrawals = make([]*engineprimitives.Withdrawal, 0) } return nil } // HashTreeRoot returns the hash tree root of the ExecutionPayload. func (p *ExecutionPayload) HashTreeRoot() common.Root { return ssz.HashConcurrent(p) } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo serializes the ExecutionPayload object into a writer. func (p *ExecutionPayload) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := p.MarshalSSZ() if err != nil { return nil, err } dst = append(dst, bz...) return dst, nil } // HashTreeRootWith ssz hashes the ExecutionPayload object with a hasher. // //nolint:mnd // will be deprecated eventually. func (p *ExecutionPayload) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'ParentHash' hh.PutBytes(p.ParentHash[:]) // Field (1) 'FeeRecipient' hh.PutBytes(p.FeeRecipient[:]) // Field (2) 'StateRoot' hh.PutBytes(p.StateRoot[:]) // Field (3) 'ReceiptsRoot' hh.PutBytes(p.ReceiptsRoot[:]) // Field (4) 'LogsBloom' hh.PutBytes(p.LogsBloom[:]) // Field (5) 'Random' hh.PutBytes(p.Random[:]) // Field (6) 'Number' hh.PutUint64(uint64(p.Number)) // Field (7) 'GasLimit' hh.PutUint64(uint64(p.GasLimit)) // Field (8) 'GasUsed' hh.PutUint64(uint64(p.GasUsed)) // Field (9) 'Timestamp' hh.PutUint64(uint64(p.Timestamp)) // Field (10) 'ExtraData' { elemIndx := hh.Index() byteLen := uint64(len(p.ExtraData)) if byteLen > 32 { return fastssz.ErrIncorrectListSize } hh.Append(p.ExtraData) hh.MerkleizeWithMixin(elemIndx, byteLen, (32+31)/32) } // Field (11) 'BaseFeePerGas' bz, err := p.BaseFeePerGas.MarshalSSZ() if err != nil { return err } hh.PutBytes(bz) // Field (12) 'BlockHash' hh.PutBytes(p.BlockHash[:]) // Field (13) 'Transactions' { subIndx := hh.Index() num := uint64(len(p.Transactions)) if num > 1048576 { return fastssz.ErrIncorrectListSize } for _, elem := range p.Transactions { { elemIndx := hh.Index() byteLen := uint64(len(elem)) if byteLen > 1073741824 { return fastssz.ErrIncorrectListSize } hh.AppendBytes32(elem) hh.MerkleizeWithMixin(elemIndx, byteLen, (1073741824+31)/32) } } hh.MerkleizeWithMixin(subIndx, num, 1048576) } // Field (14) 'Withdrawals' { subIndx := hh.Index() num := uint64(len(p.Withdrawals)) if num > 16 { return fastssz.ErrIncorrectListSize } for _, elem := range p.Withdrawals { if err = elem.HashTreeRootWith(hh); err != nil { return err } } hh.MerkleizeWithMixin(subIndx, num, 16) } // Field (15) 'BlobGasUsed' hh.PutUint64(uint64(p.BlobGasUsed)) // Field (16) 'ExcessBlobGas' hh.PutUint64(uint64(p.ExcessBlobGas)) hh.Merkleize(indx) return nil } // GetTree ssz hashes the ExecutionPayload object. func (p *ExecutionPayload) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(p) } /* -------------------------------------------------------------------------- */ /* JSON */ /* -------------------------------------------------------------------------- */ // MarshalJSON marshals as JSON. func (p ExecutionPayload) MarshalJSON() ([]byte, error) { type ExecutionPayload struct { ParentHash common.ExecutionHash `json:"parentHash"` FeeRecipient common.ExecutionAddress `json:"feeRecipient"` StateRoot bytes.B32 `json:"stateRoot"` ReceiptsRoot bytes.B32 `json:"receiptsRoot"` LogsBloom bytes.B256 `json:"logsBloom"` Random bytes.B32 `json:"prevRandao"` Number math.U64 `json:"blockNumber"` GasLimit math.U64 `json:"gasLimit"` GasUsed math.U64 `json:"gasUsed"` Timestamp math.U64 `json:"timestamp"` ExtraData bytes.Bytes `json:"extraData"` BaseFeePerGas *math.U256Hex `json:"baseFeePerGas"` BlockHash common.ExecutionHash `json:"blockHash"` Transactions []bytes.Bytes `json:"transactions"` Withdrawals []*engineprimitives.Withdrawal `json:"withdrawals"` BlobGasUsed math.U64 `json:"blobGasUsed"` ExcessBlobGas math.U64 `json:"excessBlobGas"` } var enc ExecutionPayload enc.ParentHash = p.ParentHash enc.FeeRecipient = p.FeeRecipient enc.StateRoot = p.StateRoot enc.ReceiptsRoot = p.ReceiptsRoot enc.LogsBloom = p.LogsBloom enc.Random = p.Random enc.Number = p.Number enc.GasLimit = p.GasLimit enc.GasUsed = p.GasUsed enc.Timestamp = p.Timestamp enc.ExtraData = p.ExtraData enc.BaseFeePerGas = (*math.U256Hex)(p.BaseFeePerGas) enc.BlockHash = p.BlockHash enc.Transactions = make([]bytes.Bytes, len(p.Transactions)) for k, v := range p.Transactions { enc.Transactions[k] = v } enc.Withdrawals = p.Withdrawals enc.BlobGasUsed = p.BlobGasUsed enc.ExcessBlobGas = p.ExcessBlobGas return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. // //nolint:funlen // todo fix. func (p *ExecutionPayload) UnmarshalJSON(input []byte) error { type ExecutionPayload struct { ParentHash *common.ExecutionHash `json:"parentHash"` FeeRecipient *common.ExecutionAddress `json:"feeRecipient"` StateRoot *bytes.B32 `json:"stateRoot"` ReceiptsRoot *bytes.B32 `json:"receiptsRoot"` LogsBloom *bytes.B256 `json:"logsBloom"` Random *bytes.B32 `json:"prevRandao"` Number *math.U64 `json:"blockNumber"` GasLimit *math.U64 `json:"gasLimit"` GasUsed *math.U64 `json:"gasUsed"` Timestamp *math.U64 `json:"timestamp"` ExtraData *bytes.Bytes `json:"extraData"` BaseFeePerGas *math.U256Hex `json:"baseFeePerGas"` BlockHash *common.ExecutionHash `json:"blockHash"` Transactions []bytes.Bytes `json:"transactions"` Withdrawals []*engineprimitives.Withdrawal `json:"withdrawals"` BlobGasUsed *math.U64 `json:"blobGasUsed"` ExcessBlobGas *math.U64 `json:"excessBlobGas"` } var dec ExecutionPayload if err := json.Unmarshal(input, &dec); err != nil { return err } if dec.ParentHash == nil { return errors.New( "missing required field 'parentHash' for ExecutionPayload", ) } p.ParentHash = *dec.ParentHash if dec.FeeRecipient == nil { return errors.New( "missing required field 'feeRecipient' for ExecutionPayload", ) } p.FeeRecipient = *dec.FeeRecipient if dec.StateRoot == nil { return errors.New( "missing required field 'stateRoot' for ExecutionPayload", ) } p.StateRoot = *dec.StateRoot if dec.ReceiptsRoot == nil { return errors.New( "missing required field 'receiptsRoot' for ExecutionPayload", ) } p.ReceiptsRoot = *dec.ReceiptsRoot if dec.LogsBloom == nil { return errors.New( "missing required field 'logsBloom' for ExecutionPayload", ) } p.LogsBloom = *dec.LogsBloom if dec.Random == nil { return errors.New( "missing required field 'prevRandao' for ExecutionPayload", ) } p.Random = *dec.Random if dec.Number == nil { return errors.New( "missing required field 'blockNumber' for ExecutionPayload", ) } p.Number = *dec.Number if dec.GasLimit == nil { return errors.New( "missing required field 'gasLimit' for ExecutionPayload", ) } p.GasLimit = *dec.GasLimit if dec.GasUsed == nil { return errors.New( "missing required field 'gasUsed' for ExecutionPayload", ) } p.GasUsed = *dec.GasUsed if dec.Timestamp == nil { return errors.New( "missing required field 'timestamp' for ExecutionPayload", ) } p.Timestamp = *dec.Timestamp if dec.ExtraData == nil { return errors.New( "missing required field 'extraData' for ExecutionPayload", ) } p.ExtraData = *dec.ExtraData if dec.BaseFeePerGas == nil { return errors.New( "missing required field 'baseFeePerGas' for ExecutionPayload", ) } p.BaseFeePerGas = (*math.U256)(dec.BaseFeePerGas) if dec.BlockHash == nil { return errors.New( "missing required field 'blockHash' for ExecutionPayload", ) } p.BlockHash = *dec.BlockHash if dec.Transactions == nil { return errors.New( "missing required field 'transactions' for ExecutionPayload", ) } p.Transactions = make([][]byte, len(dec.Transactions)) for k, v := range dec.Transactions { p.Transactions[k] = v } if dec.Withdrawals != nil { p.Withdrawals = dec.Withdrawals } if dec.BlobGasUsed != nil { p.BlobGasUsed = *dec.BlobGasUsed } if dec.ExcessBlobGas != nil { p.ExcessBlobGas = *dec.ExcessBlobGas } return nil } /* -------------------------------------------------------------------------- */ /* Getters */ /* -------------------------------------------------------------------------- */ // IsBlinded checks if the ExecutionPayload is blinded. func (p *ExecutionPayload) IsBlinded() bool { return false } // GetParentHash returns the parent hash of the ExecutionPayload. func (p *ExecutionPayload) GetParentHash() common.ExecutionHash { return p.ParentHash } // GetFeeRecipient returns the fee recipient address of the ExecutionPayload. func (p *ExecutionPayload) GetFeeRecipient() common.ExecutionAddress { return p.FeeRecipient } // GetStateRoot returns the state root of the ExecutionPayload. func (p *ExecutionPayload) GetStateRoot() common.Bytes32 { return p.StateRoot } // GetReceiptsRoot returns the receipts root of the ExecutionPayload. func (p *ExecutionPayload) GetReceiptsRoot() common.Bytes32 { return p.ReceiptsRoot } // GetLogsBloom returns the logs bloom of the ExecutionPayload. func (p *ExecutionPayload) GetLogsBloom() bytes.B256 { return p.LogsBloom } // GetPrevRandao returns the previous Randao value of the ExecutionPayload. func (p *ExecutionPayload) GetPrevRandao() common.Bytes32 { return p.Random } // GetNumber returns the block number of the ExecutionPayload. func (p *ExecutionPayload) GetNumber() math.U64 { return p.Number } // GetGasLimit returns the gas limit of the ExecutionPayload. func (p *ExecutionPayload) GetGasLimit() math.U64 { return p.GasLimit } // GetGasUsed returns the gas used of the ExecutionPayload. func (p *ExecutionPayload) GetGasUsed() math.U64 { return p.GasUsed } // GetTimestamp returns the timestamp of the ExecutionPayload. func (p *ExecutionPayload) GetTimestamp() math.U64 { return p.Timestamp } // GetExtraData returns the extra data of the ExecutionPayload. func (p *ExecutionPayload) GetExtraData() []byte { return p.ExtraData } // GetBaseFeePerGas returns the base fee per gas of the ExecutionPayload. func (p *ExecutionPayload) GetBaseFeePerGas() *math.U256 { return p.BaseFeePerGas } // GetBlockHash returns the block hash of the ExecutionPayload. func (p *ExecutionPayload) GetBlockHash() common.ExecutionHash { return p.BlockHash } // GetTransactions returns the transactions of the ExecutionPayload. func (p *ExecutionPayload) GetTransactions() engineprimitives.Transactions { return p.Transactions } // GetWithdrawals returns the withdrawals of the ExecutionPayload. func (p *ExecutionPayload) GetWithdrawals() engineprimitives.Withdrawals { return p.Withdrawals } // GetBlobGasUsed returns the blob gas used of the ExecutionPayload. func (p *ExecutionPayload) GetBlobGasUsed() math.U64 { return p.BlobGasUsed } // GetExcessBlobGas returns the excess blob gas of the ExecutionPayload. func (p *ExecutionPayload) GetExcessBlobGas() math.U64 { return p.ExcessBlobGas } // ToHeader converts the ExecutionPayload to an ExecutionPayloadHeader. func (p *ExecutionPayload) ToHeader() (*ExecutionPayloadHeader, error) { switch p.GetForkVersion() { case version.Deneb(), version.Deneb1(), version.Electra(), version.Electra1(), version.Fulu(): return &ExecutionPayloadHeader{ Versionable: p.Versionable, ParentHash: p.GetParentHash(), FeeRecipient: p.GetFeeRecipient(), StateRoot: p.GetStateRoot(), ReceiptsRoot: p.GetReceiptsRoot(), LogsBloom: p.GetLogsBloom(), Random: p.GetPrevRandao(), Number: p.GetNumber(), GasLimit: p.GetGasLimit(), GasUsed: p.GetGasUsed(), Timestamp: p.GetTimestamp(), ExtraData: p.GetExtraData(), BaseFeePerGas: p.GetBaseFeePerGas(), BlockHash: p.GetBlockHash(), TransactionsRoot: p.GetTransactions().HashTreeRoot(), WithdrawalsRoot: p.GetWithdrawals().HashTreeRoot(), BlobGasUsed: p.GetBlobGasUsed(), ExcessBlobGas: p.GetExcessBlobGas(), }, nil default: return nil, errors.New("unknown fork version") } } ================================================ FILE: consensus-types/types/payload_env.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) // BuiltExecutionPayloadEnv is an interface for the execution payload envelope. // // TODO: move interface definition to packages where it is used. type BuiltExecutionPayloadEnv interface { // GetExecutionPayload retrieves the associated execution payload. GetExecutionPayload() *ExecutionPayload // GetBlockValue returns the Wei value of the block in the execution payload. GetBlockValue() *math.U256 // GetBlobsBundle fetches the associated BlobsBundleV1 if available. GetBlobsBundle() engineprimitives.BlobsBundle // GetEncodedExecutionRequests fetches the associated execution requests if available GetEncodedExecutionRequests() []EncodedExecutionRequest // ShouldOverrideBuilder indicates if the builder should be overridden. ShouldOverrideBuilder() bool } // executionPayloadEnvelope is a struct that holds the execution payload and // its associated data. type executionPayloadEnvelope[BlobsBundleT engineprimitives.BlobsBundle] struct { ExecutionPayload *ExecutionPayload `json:"executionPayload"` BlockValue *math.U256 `json:"blockValue"` BlobsBundle BlobsBundleT `json:"blobsBundle"` ExecutionRequests []EncodedExecutionRequest `json:"executionRequests"` Override bool `json:"shouldOverrideBuilder"` } // NewEmptyExecutionPayloadEnvelope returns an empty executionPayloadEnvelope // for the given fork version. func NewEmptyExecutionPayloadEnvelope[ BlobsBundleT engineprimitives.BlobsBundle, ](forkVersion common.Version) BuiltExecutionPayloadEnv { return &executionPayloadEnvelope[BlobsBundleT]{ ExecutionPayload: NewEmptyExecutionPayloadWithVersion(forkVersion), } } func NewExecutionPayloadEnvelope[ BlobsBundleT engineprimitives.BlobsBundle, ]( payload *ExecutionPayload, blobs BlobsBundleT, executionRequests []EncodedExecutionRequest, ) BuiltExecutionPayloadEnv { return &executionPayloadEnvelope[BlobsBundleT]{ ExecutionPayload: payload, BlobsBundle: blobs, ExecutionRequests: executionRequests, } } // GetExecutionPayload returns the execution payload of the // executionPayloadEnvelope. func (e *executionPayloadEnvelope[BlobsBundleT]) GetExecutionPayload() *ExecutionPayload { return e.ExecutionPayload } // GetBlockValue returns the block value of the executionPayloadEnvelope. func (e *executionPayloadEnvelope[BlobsBundleT]) GetBlockValue() *math.U256 { return e.BlockValue } // GetBlobsBundle returns the blobs bundle of the executionPayloadEnvelope. func (e *executionPayloadEnvelope[BlobsBundleT]) GetBlobsBundle() engineprimitives.BlobsBundle { return e.BlobsBundle } // GetEncodedExecutionRequests returns the encoded Execution Requests func (e *executionPayloadEnvelope[BlobsBundleT]) GetEncodedExecutionRequests() []EncodedExecutionRequest { return e.ExecutionRequests } // ShouldOverrideBuilder returns whether the builder should be overridden. func (e *executionPayloadEnvelope[BlobsBundleT]) ShouldOverrideBuilder() bool { return e.Override } ================================================ FILE: consensus-types/types/payload_header.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // ExecutionPayloadHeaderStaticSize is the static size of the ExecutionPayloadHeader. const ExecutionPayloadHeaderStaticSize uint32 = 584 // Compile-time assertions to ensure ExecutionPayloadHeader implements necessary interfaces. var ( _ ssz.DynamicObject = (*ExecutionPayloadHeader)(nil) _ constraints.SSZVersionedMarshallableRootable = (*ExecutionPayloadHeader)(nil) ) // ExecutionPayloadHeader represents the payload header of an execution block. type ExecutionPayloadHeader struct { // NOTE: This version is not required but left in for backwards compatibility. // // A recommended alternative to `GetForkVersion()` on this struct would be to use the chain // spec's `ActiveForkVersionForTimestamp()` on the value of `GetTimestamp()`. // // This version should still be set to the correct value to avoid potential inconsistencies. constraints.Versionable // Contents // // ParentHash is the hash of the parent block. ParentHash common.ExecutionHash `json:"parentHash"` // FeeRecipient is the address of the fee recipient. FeeRecipient common.ExecutionAddress `json:"feeRecipient"` // StateRoot is the root of the state trie. StateRoot common.Bytes32 `json:"stateRoot"` // ReceiptsRoot is the root of the receipts trie. ReceiptsRoot common.Bytes32 `json:"receiptsRoot"` // LogsBloom is the bloom filter for the logs. LogsBloom bytes.B256 `json:"logsBloom"` // Random is the prevRandao value. Random common.Bytes32 `json:"prevRandao"` // Number is the block number. Number math.U64 `json:"blockNumber"` // GasLimit is the gas limit for the block. GasLimit math.U64 `json:"gasLimit"` // GasUsed is the amount of gas used in the block. GasUsed math.U64 `json:"gasUsed"` // Timestamp is the timestamp of the block. Timestamp math.U64 `json:"timestamp"` // ExtraData is the extra data of the block. ExtraData bytes.Bytes `json:"extraData"` // BaseFeePerGas is the base fee per gas. BaseFeePerGas *math.U256 `json:"baseFeePerGas"` // BlockHash is the hash of the block. BlockHash common.ExecutionHash `json:"blockHash"` // TransactionsRoot is the root of the transaction trie. TransactionsRoot common.Root `json:"transactionsRoot"` // WithdrawalsRoot is the root of the withdrawals trie. WithdrawalsRoot common.Root `json:"withdrawalsRoot"` // BlobGasUsed is the amount of blob gas used in the block. BlobGasUsed math.U64 `json:"blobGasUsed"` // ExcessBlobGas is the amount of excess blob gas in the block. ExcessBlobGas math.U64 `json:"excessBlobGas"` } func NewEmptyExecutionPayloadHeaderWithVersion(version common.Version) *ExecutionPayloadHeader { return &ExecutionPayloadHeader{ Versionable: NewVersionable(version), BaseFeePerGas: &math.U256{}, } } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns either the static size of the object if fixed == true, or // the total size otherwise. func (h *ExecutionPayloadHeader) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { size := ExecutionPayloadHeaderStaticSize if fixed { return size } size += ssz.SizeDynamicBytes(siz, h.ExtraData) return size } // DefineSSZ defines how an object is encoded/decoded. func (h *ExecutionPayloadHeader) DefineSSZ(codec *ssz.Codec) { // Define the static data (fields and dynamic offsets) ssz.DefineStaticBytes(codec, &h.ParentHash) ssz.DefineStaticBytes(codec, &h.FeeRecipient) ssz.DefineStaticBytes(codec, &h.StateRoot) ssz.DefineStaticBytes(codec, &h.ReceiptsRoot) ssz.DefineStaticBytes(codec, &h.LogsBloom) ssz.DefineStaticBytes(codec, &h.Random) ssz.DefineUint64(codec, &h.Number) ssz.DefineUint64(codec, &h.GasLimit) ssz.DefineUint64(codec, &h.GasUsed) ssz.DefineUint64(codec, &h.Timestamp) //nolint:mnd // TODO: get from accessible chainspec field params ssz.DefineDynamicBytesOffset(codec, (*[]byte)(&h.ExtraData), 32) ssz.DefineUint256(codec, &h.BaseFeePerGas) ssz.DefineStaticBytes(codec, &h.BlockHash) ssz.DefineStaticBytes(codec, &h.TransactionsRoot) ssz.DefineStaticBytes(codec, &h.WithdrawalsRoot) ssz.DefineUint64(codec, &h.BlobGasUsed) ssz.DefineUint64(codec, &h.ExcessBlobGas) // Define the dynamic data (fields) //nolint:mnd // TODO: get from accessible chainspec field params ssz.DefineDynamicBytesContent(codec, (*[]byte)(&h.ExtraData), 32) } // MarshalSSZ serializes the ExecutionPayloadHeader object into a slice of // bytes. func (h *ExecutionPayloadHeader) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(h)) return buf, ssz.EncodeToBytes(buf, h) } func (*ExecutionPayloadHeader) ValidateAfterDecodingSSZ() error { return nil } // HashTreeRootSSZ returns the hash tree root of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) HashTreeRoot() common.Root { return ssz.HashConcurrent(h) } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo ssz marshals the ExecutionPayloadHeaderDeneb object to a target // array. func (h *ExecutionPayloadHeader) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := h.MarshalSSZ() if err != nil { return nil, err } dst = append(dst, bz...) return dst, nil } // HashTreeRootWith ssz hashes the ExecutionPayloadHeaderDeneb object with a // hasher // //nolint:mnd // from fastssz. func (h *ExecutionPayloadHeader) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'ParentHash' hh.PutBytes(h.ParentHash[:]) // Field (1) 'FeeRecipient' hh.PutBytes(h.FeeRecipient[:]) // Field (2) 'StateRoot' hh.PutBytes(h.StateRoot[:]) // Field (3) 'ReceiptsRoot' hh.PutBytes(h.ReceiptsRoot[:]) // Field (4) 'LogsBloom' if size := len(h.LogsBloom); size != 256 { return fastssz.ErrBytesLengthFn( "ExecutionPayloadHeaderDeneb.LogsBloom", size, 256, ) } hh.PutBytes(h.LogsBloom[:]) // Field (5) 'Random' hh.PutBytes(h.Random[:]) // Field (6) 'Number' hh.PutUint64(uint64(h.Number)) // Field (7) 'GasLimit' hh.PutUint64(uint64(h.GasLimit)) // Field (8) 'GasUsed' hh.PutUint64(uint64(h.GasUsed)) // Field (9) 'Timestamp' hh.PutUint64(uint64(h.Timestamp)) // Field (10) 'ExtraData' { elemIndx := hh.Index() byteLen := uint64(len(h.ExtraData)) if byteLen > 32 { return fastssz.ErrIncorrectListSize } hh.Append(h.ExtraData) hh.MerkleizeWithMixin(elemIndx, byteLen, (32+31)/32) } // Field (11) 'BaseFeePerGas' bz, err := h.BaseFeePerGas.MarshalSSZ() if err != nil { return err } hh.PutBytes(bz) // Field (12) 'BlockHash' hh.PutBytes(h.BlockHash[:]) // Field (13) 'TransactionsRoot' hh.PutBytes(h.TransactionsRoot[:]) // Field (14) 'WithdrawalsRoot' hh.PutBytes(h.WithdrawalsRoot[:]) // Field (15) 'BlobGasUsed' hh.PutUint64(uint64(h.BlobGasUsed)) // Field (16) 'ExcessBlobGas' hh.PutUint64(uint64(h.ExcessBlobGas)) hh.Merkleize(indx) return nil } // GetTree ssz hashes the ExecutionPayloadHeaderDeneb object. func (h *ExecutionPayloadHeader) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(h) } /* -------------------------------------------------------------------------- */ /* JSON */ /* -------------------------------------------------------------------------- */ // MarshalJSON marshals as JSON. func (h ExecutionPayloadHeader) MarshalJSON() ([]byte, error) { type ExecutionPayloadHeader struct { ParentHash common.ExecutionHash `json:"parentHash"` FeeRecipient common.ExecutionAddress `json:"feeRecipient"` StateRoot bytes.B32 `json:"stateRoot"` ReceiptsRoot bytes.B32 `json:"receiptsRoot"` LogsBloom bytes.B256 `json:"logsBloom"` Random bytes.B32 `json:"prevRandao"` Number math.U64 `json:"blockNumber"` GasLimit math.U64 `json:"gasLimit"` GasUsed math.U64 `json:"gasUsed"` Timestamp math.U64 `json:"timestamp"` ExtraData bytes.Bytes `json:"extraData"` BaseFeePerGas *math.U256 `json:"baseFeePerGas"` BlockHash common.ExecutionHash `json:"blockHash"` TransactionsRoot common.Root `json:"transactionsRoot"` WithdrawalsRoot common.Root `json:"withdrawalsRoot"` BlobGasUsed math.U64 `json:"blobGasUsed"` ExcessBlobGas math.U64 `json:"excessBlobGas"` } var enc ExecutionPayloadHeader enc.ParentHash = h.ParentHash enc.FeeRecipient = h.FeeRecipient enc.StateRoot = h.StateRoot enc.ReceiptsRoot = h.ReceiptsRoot enc.LogsBloom = h.LogsBloom enc.Random = h.Random enc.Number = h.Number enc.GasLimit = h.GasLimit enc.GasUsed = h.GasUsed enc.Timestamp = h.Timestamp enc.ExtraData = h.ExtraData enc.BaseFeePerGas = h.BaseFeePerGas enc.BlockHash = h.BlockHash enc.TransactionsRoot = h.TransactionsRoot enc.WithdrawalsRoot = h.WithdrawalsRoot enc.BlobGasUsed = h.BlobGasUsed enc.ExcessBlobGas = h.ExcessBlobGas return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. // //nolint:funlen // codegen. func (h *ExecutionPayloadHeader) UnmarshalJSON(input []byte) error { type ExecutionPayloadHeader struct { ParentHash *common.ExecutionHash `json:"parentHash"` FeeRecipient *common.ExecutionAddress `json:"feeRecipient"` StateRoot *bytes.B32 `json:"stateRoot"` ReceiptsRoot *bytes.B32 `json:"receiptsRoot"` LogsBloom *bytes.B256 `json:"logsBloom"` Random *bytes.B32 `json:"prevRandao"` Number *math.U64 `json:"blockNumber"` GasLimit *math.U64 `json:"gasLimit"` GasUsed *math.U64 `json:"gasUsed"` Timestamp *math.U64 `json:"timestamp"` ExtraData *bytes.Bytes `json:"extraData"` BaseFeePerGas *math.U256 `json:"baseFeePerGas"` BlockHash *common.ExecutionHash `json:"blockHash"` TransactionsRoot *common.Root `json:"transactionsRoot"` WithdrawalsRoot *common.Root `json:"withdrawalsRoot"` BlobGasUsed *math.U64 `json:"blobGasUsed"` ExcessBlobGas *math.U64 `json:"excessBlobGas"` } var dec ExecutionPayloadHeader if err := json.Unmarshal(input, &dec); err != nil { return err } if dec.ParentHash == nil { return errors.New( "missing required field 'parentHash' for ExecutionPayloadHeader", ) } h.ParentHash = *dec.ParentHash if dec.FeeRecipient == nil { return errors.New( "missing required field 'feeRecipient' for ExecutionPayloadHeader", ) } h.FeeRecipient = *dec.FeeRecipient if dec.StateRoot == nil { return errors.New( "missing required field 'stateRoot' for ExecutionPayloadHeader", ) } h.StateRoot = *dec.StateRoot if dec.ReceiptsRoot == nil { return errors.New( "missing required field 'receiptsRoot' for ExecutionPayloadHeader", ) } h.ReceiptsRoot = *dec.ReceiptsRoot if dec.LogsBloom == nil { return errors.New( "missing required field 'logsBloom' for ExecutionPayloadHeader", ) } h.LogsBloom = *dec.LogsBloom if dec.Random == nil { return errors.New( "missing required field 'prevRandao' for ExecutionPayloadHeader", ) } h.Random = *dec.Random if dec.Number == nil { return errors.New( "missing required field 'blockNumber' for ExecutionPayloadHeader", ) } h.Number = *dec.Number if dec.GasLimit == nil { return errors.New( "missing required field 'gasLimit' for ExecutionPayloadHeader", ) } h.GasLimit = *dec.GasLimit if dec.GasUsed == nil { return errors.New( "missing required field 'gasUsed' for ExecutionPayloadHeader", ) } h.GasUsed = *dec.GasUsed if dec.Timestamp == nil { return errors.New( "missing required field 'timestamp' for ExecutionPayloadHeader", ) } h.Timestamp = *dec.Timestamp if dec.ExtraData == nil { return errors.New( "missing required field 'extraData' for ExecutionPayloadHeader", ) } // TODO: This is required for the API to be symmetric? But it's not really // clear if // this matters. if len(*dec.ExtraData) != 0 { h.ExtraData = *dec.ExtraData } if dec.BaseFeePerGas == nil { return errors.New( "missing required field 'baseFeePerGas' for ExecutionPayloadHeader", ) } h.BaseFeePerGas = dec.BaseFeePerGas if dec.BlockHash == nil { return errors.New( "missing required field 'blockHash' for ExecutionPayloadHeader", ) } h.BlockHash = *dec.BlockHash if dec.TransactionsRoot == nil { return errors.New( "missing required field 'transactionsRoot' for ExecutionPayloadHeader", ) } h.TransactionsRoot = *dec.TransactionsRoot if dec.WithdrawalsRoot != nil { h.WithdrawalsRoot = *dec.WithdrawalsRoot } if dec.BlobGasUsed != nil { h.BlobGasUsed = *dec.BlobGasUsed } if dec.ExcessBlobGas != nil { h.ExcessBlobGas = *dec.ExcessBlobGas } return nil } /* -------------------------------------------------------------------------- */ /* Getters */ /* -------------------------------------------------------------------------- */ // GetParentHash returns the parent hash of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetParentHash() common.ExecutionHash { return h.ParentHash } // GetFeeRecipient returns the fee recipient address of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetFeeRecipient() common.ExecutionAddress { return h.FeeRecipient } // GetStateRoot returns the state root of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetStateRoot() common.Bytes32 { return h.StateRoot } // GetReceiptsRoot returns the receipts root of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetReceiptsRoot() common.Bytes32 { return h.ReceiptsRoot } // GetLogsBloom returns the logs bloom of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetLogsBloom() bytes.B256 { return h.LogsBloom } // GetPrevRandao returns the previous Randao value of the // ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetPrevRandao() common.Bytes32 { return h.Random } // GetNumber returns the block number of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetNumber() math.U64 { return h.Number } // GetGasLimit returns the gas limit of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetGasLimit() math.U64 { return h.GasLimit } // GetGasUsed returns the gas used of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetGasUsed() math.U64 { return h.GasUsed } // GetTimestamp returns the timestamp of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetTimestamp() math.U64 { return h.Timestamp } // GetExtraData returns the extra data of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetExtraData() []byte { return h.ExtraData } // GetBaseFeePerGas returns the base fee per gas of the // ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetBaseFeePerGas() *math.U256 { return h.BaseFeePerGas } // GetBlockHash returns the block hash of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetBlockHash() common.ExecutionHash { return h.BlockHash } // GetTransactionsRoot returns the transactions root of the // ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetTransactionsRoot() common.Root { return h.TransactionsRoot } // GetWithdrawalsRoot returns the withdrawals root of the // ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetWithdrawalsRoot() common.Root { return h.WithdrawalsRoot } // GetBlobGasUsed returns the blob gas used of the ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetBlobGasUsed() math.U64 { return h.BlobGasUsed } // GetExcessBlobGas returns the excess blob gas of the // ExecutionPayloadHeader. func (h *ExecutionPayloadHeader) GetExcessBlobGas() math.U64 { return h.ExcessBlobGas } ================================================ FILE: consensus-types/types/payload_header_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/json" sszutil "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) // generateExecutionPayloadHeader generates an ExecutionPayloadHeader. func generateExecutionPayloadHeader(version common.Version) *types.ExecutionPayloadHeader { return &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(version), ParentHash: common.ExecutionHash{}, FeeRecipient: common.ExecutionAddress{}, StateRoot: bytes.B32{}, ReceiptsRoot: bytes.B32{}, LogsBloom: bytes.B256{}, Random: bytes.B32{}, Number: math.U64(0), GasLimit: math.U64(0), GasUsed: math.U64(0), Timestamp: math.U64(0), ExtraData: nil, BaseFeePerGas: &math.U256{}, BlockHash: common.ExecutionHash{}, TransactionsRoot: common.Root{}, WithdrawalsRoot: common.Root{}, BlobGasUsed: math.U64(0), ExcessBlobGas: math.U64(0), } } func TestExecutionPayloadHeader_Getters(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { header := generateExecutionPayloadHeader(v) require.NotNil(t, header) require.Equal(t, common.ExecutionHash{}, header.GetParentHash()) require.Equal( t, common.ExecutionAddress{}, header.GetFeeRecipient(), ) require.Equal(t, bytes.B32{}, header.GetStateRoot()) require.Equal(t, bytes.B32{}, header.GetReceiptsRoot()) require.Equal(t, bytes.B256{}, header.GetLogsBloom()) require.Equal(t, bytes.B32{}, header.GetPrevRandao()) require.Equal(t, math.U64(0), header.GetNumber()) require.Equal(t, math.U64(0), header.GetGasLimit()) require.Equal(t, math.U64(0), header.GetGasUsed()) require.Equal(t, math.U64(0), header.GetTimestamp()) require.Equal(t, []byte(nil), header.GetExtraData()) require.Equal(t, math.NewU256(0), header.GetBaseFeePerGas()) require.Equal(t, common.ExecutionHash{}, header.GetBlockHash()) require.Equal(t, common.Root{}, header.GetTransactionsRoot()) require.Equal(t, common.Root{}, header.GetWithdrawalsRoot()) require.Equal(t, math.U64(0), header.GetBlobGasUsed()) require.Equal(t, math.U64(0), header.GetExcessBlobGas()) }) } func TestExecutionPayloadHeader_IsNil(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { header := generateExecutionPayloadHeader(v) require.NotNil(t, header) }) } func TestExecutionPayloadHeader_Version(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { header := generateExecutionPayloadHeader(v) require.Equal(t, v, header.GetForkVersion()) }) } func TestExecutionPayloadHeader_MarshalUnmarshalJSON(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { originalHeader := generateExecutionPayloadHeader(v) data, err := originalHeader.MarshalJSON() require.NoError(t, err) require.NotNil(t, data) var header types.ExecutionPayloadHeader err = header.UnmarshalJSON(data) require.NoError(t, err) header.Versionable = types.NewVersionable(originalHeader.GetForkVersion()) require.Equal(t, originalHeader, &header) }) } func TestExecutionPayloadHeader_Serialization(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { original := generateExecutionPayloadHeader(v) data, err := original.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := types.NewEmptyExecutionPayloadHeaderWithVersion(original.GetForkVersion()) err = sszutil.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, original, unmarshalled) }) } func TestExecutionPayloadHeader_MarshalSSZTo(t *testing.T) { t.Parallel() testcases := []struct { name string malleate func(common.Version) *types.ExecutionPayloadHeader expErr error }{ { name: "valid", malleate: generateExecutionPayloadHeader, expErr: nil, }, { name: "invalid extra data passes marshalling", malleate: func(version common.Version) *types.ExecutionPayloadHeader { header := generateExecutionPayloadHeader(version) header.ExtraData = make([]byte, 100) return header }, expErr: nil, }, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { header := tc.malleate(v) buf := make([]byte, 64) _, err := header.MarshalSSZTo(buf) if tc.expErr != nil { require.Error(t, err) } else { require.NoError(t, err) } }) }) } } func TestExecutionPayloadHeader_NewFromSSZ_EmptyBuf(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { buf := make([]byte, 0) header := types.NewEmptyExecutionPayloadHeaderWithVersion(v) err := sszutil.Unmarshal(buf, header) require.ErrorIs(t, err, io.ErrUnexpectedEOF) }) } func TestExecutionPayloadHeader_NewFromSSZ_Invalid(t *testing.T) { t.Parallel() testcases := []struct { name string malleate func() []byte expErr error }{ { name: "offset exceeds length", malleate: func() []byte { header := generateExecutionPayloadHeader(version.Deneb()) buf, err := header.MarshalSSZ() require.NoError(t, err) buf[436] = 10 buf[437] = 10 buf[438] = 10 buf[439] = 10 return buf }, expErr: ssz.ErrOffsetBeyondCapacity, }, { name: "invalid extra data: extra data too large", malleate: func() []byte { header := generateExecutionPayloadHeader(version.Deneb()) buf, err := header.MarshalSSZ() // add dummy extra data to exceed the 32 limit dummyExtra := make([]byte, 100) buf = append(buf, dummyExtra...) require.NoError(t, err) return buf }, expErr: ssz.ErrMaxLengthExceeded, }, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { buf := tc.malleate() dest := types.NewEmptyExecutionPayloadHeaderWithVersion(version.Deneb()) err := sszutil.Unmarshal(buf, dest) require.ErrorIs(t, err, tc.expErr) }) } } func TestExecutionPayloadHeader_NewFromSSZ_Invalid_TooSmall(t *testing.T) { t.Parallel() header := generateExecutionPayloadHeader(version.Deneb()) buf, err := header.MarshalSSZ() require.NoError(t, err) buf[436] = 1 buf[437] = 0 buf[438] = 0 buf[439] = 0 dest := types.NewEmptyExecutionPayloadHeaderWithVersion(version.Deneb()) err = sszutil.Unmarshal(buf, dest) require.Error(t, err) // Can be either ErrFirstOffsetMismatch or ErrBadOffsetProgression due to reused Decoder in // SSZ lib. If the SSZ lib happens to grab a reused Decoder from the decoderPool, the decoder's // `offsets` field is already initialized to an empty slice instead of nil. This passes the nil // check in the ErrFirstOffsetMismatch error condition resulting in no error. Immediately after, // it will still fail the ErrBadOffsetProgression error condition. This flakiness depends upon // retrieving a used Decoder from the decoderPool as well as the intentional misuse of the // marshaled data. In the case that an actor intentionally tries to induce this behavior, the // unmarshaling of the data correctly results in error, just a different error. // In this unit test, we simply expect the error to be one of the two possible errors. isExpectedError := errors.IsAny(err, ssz.ErrFirstOffsetMismatch, ssz.ErrBadOffsetProgression) require.True( t, isExpectedError, "expected %w or %w, got %w", ssz.ErrFirstOffsetMismatch, ssz.ErrBadOffsetProgression, err, ) } func TestExecutionPayloadHeader_SizeSSZ(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { header := generateExecutionPayloadHeader(v) size := ssz.Size(header) require.Equal(t, types.ExecutionPayloadHeaderStaticSize, size) }) } func TestExecutionPayloadHeader_HashTreeRoot(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { header := generateExecutionPayloadHeader(v) require.NotPanics(t, func() { header.HashTreeRoot() }) }) } func TestExecutionPayloadHeader_GetTree(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { header := generateExecutionPayloadHeader(v) _, err := header.GetTree() require.NoError(t, err) }) } func TestExecutablePayloadHeader_UnmarshalJSON_Error(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { original := generateExecutionPayloadHeader(v) validJSON, err := original.MarshalJSON() require.NoError(t, err) testCases := []struct { name string removeField string expectedError string }{ { name: "missing required field 'parentHash'", removeField: "parentHash", expectedError: "missing required field 'parentHash' for ExecutionPayloadHeader", }, { name: "missing required field 'feeRecipient'", removeField: "feeRecipient", expectedError: "missing required field 'feeRecipient' for ExecutionPayloadHeader", }, { name: "missing required field 'stateRoot'", removeField: "stateRoot", expectedError: "missing required field 'stateRoot' for ExecutionPayloadHeader", }, { name: "missing required field 'receiptsRoot'", removeField: "receiptsRoot", expectedError: "missing required field 'receiptsRoot' for ExecutionPayloadHeader", }, { name: "missing required field 'logsBloom'", removeField: "logsBloom", expectedError: "missing required field 'logsBloom' for ExecutionPayloadHeader", }, { name: "missing required field 'prevRandao'", removeField: "prevRandao", expectedError: "missing required field 'prevRandao' for ExecutionPayloadHeader", }, { name: "missing required field 'blockNumber'", removeField: "blockNumber", expectedError: "missing required field 'blockNumber' for ExecutionPayloadHeader", }, { name: "missing required field 'gasLimit'", removeField: "gasLimit", expectedError: "missing required field 'gasLimit' for ExecutionPayloadHeader", }, { name: "missing required field 'gasUsed'", removeField: "gasUsed", expectedError: "missing required field 'gasUsed' for ExecutionPayloadHeader", }, { name: "missing required field 'timestamp'", removeField: "timestamp", expectedError: "missing required field 'timestamp' for ExecutionPayloadHeader", }, { name: "missing required field 'extraData'", removeField: "extraData", expectedError: "missing required field 'extraData' for ExecutionPayloadHeader", }, { name: "missing required field 'baseFeePerGas'", removeField: "baseFeePerGas", expectedError: "missing required field 'baseFeePerGas' for ExecutionPayloadHeader", }, { name: "missing required field 'blockHash'", removeField: "blockHash", expectedError: "missing required field 'blockHash' for ExecutionPayloadHeader", }, { name: "missing required field 'transactionsRoot'", removeField: "transactionsRoot", expectedError: "missing required field 'transactionsRoot' for ExecutionPayloadHeader", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { var payload types.ExecutionPayloadHeader var jsonMap map[string]interface{} errUnmarshal := json.Unmarshal(validJSON, &jsonMap) require.NoError(t, errUnmarshal) delete(jsonMap, tc.removeField) malformedJSON, errMarshal := json.Marshal(jsonMap) require.NoError(t, errMarshal) err = payload.UnmarshalJSON(malformedJSON) require.Error(t, err) require.Contains(t, err.Error(), tc.expectedError) }) } }) } func TestExecutablePayloadHeader_UnmarshalJSON_Empty(t *testing.T) { t.Parallel() var payload types.ExecutionPayloadHeader err := payload.UnmarshalJSON([]byte{}) require.Error(t, err) } func TestExecutablePayloadHeader_HashTreeRootWith(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { testcases := []struct { name string malleate func() *types.ExecutionPayloadHeader expErr error }{ { name: "invalid ExtraData length", malleate: func() *types.ExecutionPayloadHeader { var header = generateExecutionPayloadHeader(v) header.ExtraData = make([]byte, 50) return header }, expErr: fastssz.ErrIncorrectListSize, }, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { t.Parallel() hh := fastssz.DefaultHasherPool.Get() header := tc.malleate() err := header.HashTreeRootWith(hh) require.Equal(t, tc.expErr, err) }) } }) } func TestExecutionPayloadHeader_NewFromSSZ(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { testCases := []struct { name string data []byte expErr error expectedHeader *types.ExecutionPayloadHeader }{ { name: "Valid SSZ data", data: func() []byte { data, _ := generateExecutionPayloadHeader(v).MarshalSSZ() return data }(), expErr: nil, expectedHeader: generateExecutionPayloadHeader(v), }, { name: "Invalid SSZ data", data: []byte{0x01, 0x02}, expErr: io.ErrUnexpectedEOF, expectedHeader: nil, }, { name: "Empty SSZ data", data: []byte{}, expErr: io.ErrUnexpectedEOF, expectedHeader: nil, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() header := types.NewEmptyExecutionPayloadHeaderWithVersion(v) if tc.name == "Different fork version" { require.Panics(t, func() { _ = sszutil.Unmarshal(tc.data, header) }, "Expected panic for different fork version") } else { err := sszutil.Unmarshal(tc.data, header) if tc.expErr != nil { require.ErrorIs(t, err, tc.expErr) } else { require.NoError(t, err) require.Equal(t, tc.expectedHeader, header) } } }) } }) } func TestExecutionPayloadHeader_NewFromJSON(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { type testCase struct { name string data []byte header *types.ExecutionPayloadHeader expectedError error } testCases := []testCase{ func() testCase { header := generateExecutionPayloadHeader(v) return testCase{ name: "Valid JSON", header: header, data: func() []byte { data, err := json.Marshal(header) require.NoError(t, err) return data }(), } }(), { name: "Invalid JSON", data: []byte{}, expectedError: errors.New("unexpected end of JSON input"), }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() header := types.NewEmptyExecutionPayloadHeaderWithVersion(v) err := json.Unmarshal(tc.data, header) if tc.expectedError != nil { require.Error(t, err) require.Contains(t, err.Error(), tc.expectedError.Error()) } else { require.NoError(t, err) } if tc.header != nil { require.Equal(t, tc.header, header) } }) } }) } ================================================ FILE: consensus-types/types/payload_requests.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "math/big" "unsafe" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/errors" bkitgethtypes "github.com/berachain/beacon-kit/gethlib/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/version" gethcommon "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" gethtrie "github.com/ethereum/go-ethereum/trie" ) // NewPayloadRequest as per the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#modified-newpayloadrequest type NewPayloadRequest interface { constraints.Versionable HasValidVersionedAndBlockHashes() error GetExecutionPayload() *ExecutionPayload GetVersionedHashes() []common.ExecutionHash GetParentBeaconBlockRoot() common.Root GetEncodedExecutionRequests() ([]EncodedExecutionRequest, error) GetParentProposerPubkey() *crypto.BLSPubkey } type newPayloadRequest struct { constraints.Versionable // executionPayload is the payload to the execution client. executionPayload *ExecutionPayload // versionedHashes is the versioned hashes of the execution payload. versionedHashes []common.ExecutionHash // parentBeaconBlockRoot is the root of the parent beacon block. parentBeaconBlockRoot common.Root // ExecutionRequests is introduced in Pectra. It is only non-nil after Pectra. executionRequests []EncodedExecutionRequest // ParentProposerPubkey is introduced in Pectra1. It is only non-nil after Pectra1. parentProposerPubkey *crypto.BLSPubkey } // BuildNewPayloadRequestFromFork will build a NewPayloadRequest. func BuildNewPayloadRequestFromFork(blk *BeaconBlock, parentProposerPubkey *crypto.BLSPubkey) (NewPayloadRequest, error) { forkVersion := blk.GetForkVersion() if version.IsBefore(forkVersion, version.Deneb()) { return nil, ErrForkVersionNotSupported } var ( body = blk.GetBody() payload = body.GetExecutionPayload() parentBeaconBlockRoot = blk.GetParentBlockRoot() executionRequestsList []EncodedExecutionRequest ) if version.EqualsOrIsAfter(forkVersion, version.Electra()) { // If we're post-electra, we set execution requests. executionRequests, err := body.GetExecutionRequests() if err != nil { return nil, err } executionRequestsList, err = GetExecutionRequestsList(executionRequests) if err != nil { return nil, err } } if version.IsBefore(forkVersion, version.Electra1()) { if parentProposerPubkey != nil { return nil, engineprimitives.ErrNonEmptyPrevProposerPubKey } } else { if parentProposerPubkey == nil { return nil, engineprimitives.ErrEmptyPrevProposerPubKey } } return &newPayloadRequest{ Versionable: NewVersionable(payload.GetForkVersion()), executionPayload: payload, versionedHashes: body.GetBlobKzgCommitments().ToVersionedHashes(), parentBeaconBlockRoot: parentBeaconBlockRoot, executionRequests: executionRequestsList, parentProposerPubkey: parentProposerPubkey, }, nil } func (n *newPayloadRequest) GetExecutionPayload() *ExecutionPayload { return n.executionPayload } func (n *newPayloadRequest) GetVersionedHashes() []common.ExecutionHash { return n.versionedHashes } func (n *newPayloadRequest) GetParentBeaconBlockRoot() common.Root { return n.parentBeaconBlockRoot } // GetParentProposerPubkey may return a nil parent pub key. See BuildNewPayloadRequestFromFork // to understand how parentProposerPubkey gets populated func (n *newPayloadRequest) GetParentProposerPubkey() *crypto.BLSPubkey { return n.parentProposerPubkey } func (n *newPayloadRequest) GetEncodedExecutionRequests() ([]EncodedExecutionRequest, error) { if version.IsBefore(n.GetForkVersion(), version.Electra()) { return nil, errors.Wrap( ErrForkVersionNotSupported, "execution requests not supported in newPayloadRequest before electra", ) } if n.executionRequests == nil { return nil, errors.Wrap(ErrNilValue, "executionRequests cannot be nil") } return n.executionRequests, nil } // HasValidVersionedAndBlockHashes checks if the version and block hashes are // valid. // As per the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.2/specs/deneb/beacon-chain.md#is_valid_block_hash // https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.2/specs/deneb/beacon-chain.md#is_valid_versioned_hashes func (n *newPayloadRequest) HasValidVersionedAndBlockHashes() error { var executionRequests []EncodedExecutionRequest if version.EqualsOrIsAfter(n.GetForkVersion(), version.Electra()) { var err error executionRequests, err = n.GetEncodedExecutionRequests() if err != nil { return err } } block, blobHashes, err := MakeEthBlock( n.GetExecutionPayload(), n.GetParentBeaconBlockRoot(), executionRequests, n.GetParentProposerPubkey(), ) if err != nil { return err } // Validate the blob hashes from the transactions in the execution payload. // Check if the number of blob hashes matches the number of versioned hashes. if len(blobHashes) != len(n.GetVersionedHashes()) { return errors.Wrapf( engineprimitives.ErrMismatchedNumVersionedHashes, "expected %d, got %d", len(blobHashes), len(n.GetVersionedHashes()), ) } // Validate each blob hash against the corresponding versioned hash. for i, blobHash := range blobHashes { if common.ExecutionHash(blobHash) != n.GetVersionedHashes()[i] { return errors.Wrapf( engineprimitives.ErrInvalidVersionedHash, "index %d: expected %v, got %v", i, blobHash, n.GetVersionedHashes()[i], ) } } // Verify that the payload is telling the truth about its block hash. if common.ExecutionHash(block.Hash()) != n.GetExecutionPayload().GetBlockHash() { return errors.Wrapf(engineprimitives.ErrPayloadBlockHashMismatch, "expected %x, got %x", block.Hash(), n.GetExecutionPayload().GetBlockHash(), ) } return nil } // MakeEthBlock builds an Ethereum block out of given payload and parent block root and // execution requests and/or parent proposer pubkey if needed. // It also returns blobHashes out of payload to ease up checks. func MakeEthBlock( payload *ExecutionPayload, parentBeaconBlockRoot common.Root, executionRequests []EncodedExecutionRequest, parentProposerPubKey *crypto.BLSPubkey, ) ( *bkitgethtypes.Block, []gethcommon.Hash, error, ) { var ( txs = make([]*bkitgethtypes.Transaction, 0, len(payload.GetTransactions())) blobHashes = make([]gethcommon.Hash, 0) ) for i, encTx := range payload.GetTransactions() { var tx bkitgethtypes.Transaction if err := tx.UnmarshalBinary(encTx); err != nil { return nil, nil, errors.Wrapf(err, "invalid transaction %d", i) } txs = append(txs, &tx) blobHashes = append(blobHashes, tx.BlobHashes()...) } wds := payload.GetWithdrawals() withdrawalsHash := gethtypes.DeriveSha(wds, gethtrie.NewStackTrie(nil)) blkHeader := &bkitgethtypes.Header{ ParentHash: gethcommon.Hash(payload.GetParentHash()), UncleHash: gethtypes.EmptyUncleHash, Coinbase: gethcommon.Address(payload.GetFeeRecipient()), Root: gethcommon.Hash(payload.GetStateRoot()), TxHash: gethtypes.DeriveSha(bkitgethtypes.Transactions(txs), gethtrie.NewStackTrie(nil)), ReceiptHash: gethcommon.Hash(payload.GetReceiptsRoot()), Bloom: gethtypes.Bloom(payload.GetLogsBloom()), Difficulty: big.NewInt(0), Number: new(big.Int).SetUint64(payload.GetNumber().Unwrap()), GasLimit: payload.GetGasLimit().Unwrap(), GasUsed: payload.GetGasUsed().Unwrap(), Time: payload.GetTimestamp().Unwrap(), BaseFee: payload.GetBaseFeePerGas().ToBig(), Extra: payload.GetExtraData(), MixDigest: gethcommon.Hash(payload.GetPrevRandao()), WithdrawalsHash: &withdrawalsHash, ExcessBlobGas: payload.GetExcessBlobGas().UnwrapPtr(), BlobGasUsed: payload.GetBlobGasUsed().UnwrapPtr(), ParentBeaconRoot: (*gethcommon.Hash)(&parentBeaconBlockRoot), ParentProposerPubkey: (*bkitgethtypes.ExecutionPubkey)(parentProposerPubKey), } if version.EqualsOrIsAfter(payload.GetForkVersion(), version.Electra()) { if executionRequests == nil { return nil, nil, errors.Wrap(ErrNilValue, "executionRequests is nil after electra in makeEthBlock") } result := make([][]byte, len(executionRequests)) for i, req := range executionRequests { result[i] = req // conversion from ExecutionRequest to []byte } reqHash := gethtypes.CalcRequestsHash(result) blkHeader.RequestsHash = &reqHash } block := bkitgethtypes.NewBlockWithHeader(blkHeader).WithBody( bkitgethtypes.Body{ Transactions: txs, Uncles: nil, Withdrawals: *(*gethtypes.Withdrawals)(unsafe.Pointer(&wds)), //#nosec:G103 // its okay. }, ) return block, blobHashes, nil } type ForkchoiceUpdateRequest struct { // State is the forkchoice state. State *engineprimitives.ForkchoiceStateV1 // PayloadAttributes is the payload attributer. PayloadAttributes *engineprimitives.PayloadAttributes // ForkVersion is the fork version that we // are going to be submitting for. ForkVersion common.Version } // BuildForkchoiceUpdateRequest builds a forkchoice update request. func BuildForkchoiceUpdateRequest( state *engineprimitives.ForkchoiceStateV1, payloadAttributes *engineprimitives.PayloadAttributes, forkVersion common.Version, ) *ForkchoiceUpdateRequest { return &ForkchoiceUpdateRequest{ State: state, PayloadAttributes: payloadAttributes, ForkVersion: forkVersion, } } // BuildForkchoiceUpdateRequestNoAttrs builds a forkchoice update request // without // any attributes. func BuildForkchoiceUpdateRequestNoAttrs( state *engineprimitives.ForkchoiceStateV1, forkVersion common.Version, ) *ForkchoiceUpdateRequest { return &ForkchoiceUpdateRequest{ State: state, ForkVersion: forkVersion, } } // GetPayloadRequest represents a request to get a payload. type GetPayloadRequest struct { // PayloadID is the payload ID. PayloadID engineprimitives.PayloadID // ForkVersion is the fork version that we are // currently on. ForkVersion common.Version } // BuildGetPayloadRequest builds a get payload request. func BuildGetPayloadRequest( payloadID engineprimitives.PayloadID, forkVersion common.Version, ) *GetPayloadRequest { return &GetPayloadRequest{ PayloadID: payloadID, ForkVersion: forkVersion, } } ================================================ FILE: consensus-types/types/payload_requests_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "testing" "time" "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/testing/utils" "github.com/stretchr/testify/require" ) func TestBuildNewPayloadRequestFromFork(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { block := utils.GenerateValidBeaconBlock(t, v) var parentProposerPubKey *crypto.BLSPubkey if version.EqualsOrIsAfter(v, version.Electra1()) { parentProposerPubKey = &crypto.BLSPubkey{0x01} } request, err := types.BuildNewPayloadRequestFromFork(block, parentProposerPubKey) require.NoError(t, err) require.NotNil(t, request) require.Equal(t, block.GetBody().GetExecutionPayload(), request.GetExecutionPayload()) require.Equal(t, block.GetBody().GetBlobKzgCommitments().ToVersionedHashes(), request.GetVersionedHashes()) require.Equal(t, block.GetParentBlockRoot(), request.GetParentBeaconBlockRoot()) if version.EqualsOrIsAfter(v, version.Electra()) { requests, getErr := block.GetBody().GetExecutionRequests() require.NoError(t, getErr) list, getErr := types.GetExecutionRequestsList(requests) require.NoError(t, getErr) executionRequests, getErr := request.GetEncodedExecutionRequests() require.NoError(t, getErr) require.Equal(t, list, executionRequests) } }) } func TestBuildForkchoiceUpdateRequest(t *testing.T) { t.Parallel() var ( state = &engineprimitives.ForkchoiceStateV1{} forkVersion = version.Deneb1() ) payloadAttributes, err := engineprimitives.NewPayloadAttributes( forkVersion, math.U64(time.Now().Truncate(time.Second).Unix()), common.Bytes32{0x01}, common.ExecutionAddress{}, engineprimitives.Withdrawals{}, common.Root{}, nil, ) require.NoError(t, err) request := types.BuildForkchoiceUpdateRequest( state, payloadAttributes, forkVersion, ) require.NotNil(t, request) require.Equal(t, state, request.State) require.Equal(t, payloadAttributes, request.PayloadAttributes) require.Equal(t, forkVersion, request.ForkVersion) } func TestBuildGetPayloadRequest(t *testing.T) { t.Parallel() payloadID := engineprimitives.PayloadID{} forkVersion := version.Altair() request := types.BuildGetPayloadRequest(payloadID, forkVersion) require.NotNil(t, request) require.Equal(t, payloadID, request.PayloadID) require.Equal(t, forkVersion, request.ForkVersion) } func TestHasValidVersionedAndBlockHashesPayloadError(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { block := utils.GenerateValidBeaconBlock(t, v) // Remove txs and kzg commitments from body cos not valid block.GetBody().SetExecutionPayload(&types.ExecutionPayload{ Versionable: types.NewVersionable(v), }) block.GetBody().SetBlobKzgCommitments(eip4844.KZGCommitments[common.ExecutionHash]{}) var parentProposerPubKey *crypto.BLSPubkey if version.EqualsOrIsAfter(v, version.Electra1()) { parentProposerPubKey = &crypto.BLSPubkey{0x01} } request, err := types.BuildNewPayloadRequestFromFork(block, parentProposerPubKey) require.NoError(t, err) require.NotNil(t, request) require.Equal(t, block.GetBody().GetExecutionPayload(), request.GetExecutionPayload()) require.Equal(t, block.GetBody().GetBlobKzgCommitments().ToVersionedHashes(), request.GetVersionedHashes()) require.Equal(t, block.GetParentBlockRoot(), request.GetParentBeaconBlockRoot()) if version.EqualsOrIsAfter(v, version.Electra()) { requests, getErr := block.GetBody().GetExecutionRequests() require.NoError(t, getErr) list, getErr := types.GetExecutionRequestsList(requests) require.NoError(t, getErr) executionRequests, getErr := request.GetEncodedExecutionRequests() require.NoError(t, getErr) require.Equal(t, list, executionRequests) } err = request.HasValidVersionedAndBlockHashes() require.ErrorIs(t, err, engineprimitives.ErrPayloadBlockHashMismatch) }) } func TestHasValidVersionedAndBlockHashesMismatchedHashes(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { block := utils.GenerateValidBeaconBlock(t, v) // Remove txs and kzg commitments from body cos not valid block.GetBody().SetExecutionPayload(&types.ExecutionPayload{ Versionable: types.NewVersionable(v), }) block.GetBody().SetBlobKzgCommitments(eip4844.KZGCommitments[common.ExecutionHash]{{}}) var parentProposerPubKey *crypto.BLSPubkey if version.EqualsOrIsAfter(v, version.Electra1()) { parentProposerPubKey = &crypto.BLSPubkey{0x01} } request, err := types.BuildNewPayloadRequestFromFork(block, parentProposerPubKey) require.NoError(t, err) err = request.HasValidVersionedAndBlockHashes() require.ErrorIs(t, err, engineprimitives.ErrMismatchedNumVersionedHashes) }) } ================================================ FILE: consensus-types/types/payload_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) func generateExecutionPayload() *types.ExecutionPayload { var ( transactions = [][]byte{{0x07}} withdrawals = []*engineprimitives.Withdrawal{ { Index: 0, Validator: 0, Address: common.ExecutionAddress{}, Amount: 0, }, } ) ep := &types.ExecutionPayload{ Versionable: types.NewVersionable(version.Deneb1()), ParentHash: common.ExecutionHash{}, FeeRecipient: common.ExecutionAddress{}, StateRoot: bytes.B32{}, ReceiptsRoot: bytes.B32{}, LogsBloom: bytes.B256{}, Random: bytes.B32{}, Number: math.U64(0), GasLimit: math.U64(0), GasUsed: math.U64(0), Timestamp: math.U64(0), ExtraData: []byte{0x01}, BaseFeePerGas: &math.U256{}, BlockHash: common.ExecutionHash{}, Transactions: transactions, Withdrawals: withdrawals, BlobGasUsed: math.U64(0), ExcessBlobGas: math.U64(0), } return ep } func TestExecutionPayload_Serialization(t *testing.T) { t.Parallel() original := generateExecutionPayload() data, err := original.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := types.NewEmptyExecutionPayloadWithVersion(original.GetForkVersion()) err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, original, unmarshalled) var buf []byte buf, err = original.MarshalSSZTo(buf) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) } func TestExecutionPayload_SizeSSZ(t *testing.T) { t.Parallel() payload := generateExecutionPayload() size := karalabessz.Size(payload) require.Equal(t, uint32(578), size) unmarshalledBody := types.NewEmptyExecutionPayloadWithVersion(version.Deneb1()) err := ssz.Unmarshal( []byte{0x01, 0x02, 0x03}, // Invalid data unmarshalledBody, ) require.ErrorIs(t, err, io.ErrUnexpectedEOF) } func TestExecutionPayload_HashTreeRoot(t *testing.T) { t.Parallel() payload := generateExecutionPayload() require.NotPanics(t, func() { _ = payload.HashTreeRoot() }) } func TestExecutionPayload_GetTree(t *testing.T) { t.Parallel() payload := generateExecutionPayload() tree, err := payload.GetTree() require.NoError(t, err) require.NotNil(t, tree) } func TestExecutionPayload_Getters(t *testing.T) { t.Parallel() payload := generateExecutionPayload() require.Equal(t, common.ExecutionHash{}, payload.GetParentHash()) require.Equal( t, common.ExecutionAddress{}, payload.GetFeeRecipient(), ) transactions := make(engineprimitives.Transactions, 1) transactions[0] = []byte{0x07} withdrawals := make(engineprimitives.Withdrawals, 1) withdrawals[0] = &engineprimitives.Withdrawal{ Index: 0, Validator: 0, Address: common.ExecutionAddress{}, Amount: 0, } require.Equal(t, common.ExecutionHash{}, payload.GetParentHash()) require.Equal(t, common.ExecutionAddress{}, payload.GetFeeRecipient()) require.Equal(t, bytes.B32{}, payload.GetStateRoot()) require.Equal(t, bytes.B32{}, payload.GetReceiptsRoot()) require.Equal(t, bytes.B256{}, payload.GetLogsBloom()) require.Equal(t, bytes.B32{}, payload.GetPrevRandao()) require.Equal(t, math.U64(0), payload.GetNumber()) require.Equal(t, math.U64(0), payload.GetGasLimit()) require.Equal(t, math.U64(0), payload.GetGasUsed()) require.Equal(t, math.U64(0), payload.GetTimestamp()) require.Equal(t, []byte{0x01}, payload.GetExtraData()) require.Equal(t, &math.U256{}, payload.GetBaseFeePerGas()) require.Equal(t, common.ExecutionHash{}, payload.GetBlockHash()) require.Equal(t, transactions, payload.GetTransactions()) require.Equal(t, withdrawals, payload.GetWithdrawals()) require.Equal(t, math.U64(0), payload.GetBlobGasUsed()) require.Equal(t, math.U64(0), payload.GetExcessBlobGas()) } func TestExecutionPayload_MarshalJSON(t *testing.T) { t.Parallel() payload := generateExecutionPayload() data, err := payload.MarshalJSON() require.NoError(t, err) require.NotNil(t, data) var unmarshalled types.ExecutionPayload err = unmarshalled.UnmarshalJSON(data) require.NoError(t, err) unmarshalled.Versionable = payload.Versionable require.Equal(t, payload, &unmarshalled) } func TestExecutionPayload_MarshalJSON_ValueAndPointer(t *testing.T) { t.Parallel() val := types.ExecutionPayload{} // Marshal on raw val uses default json marshal valSerialized, err := json.Marshal(val) require.NoError(t, err) // Marshal on ptr val uses implemented MarshalJSON ptrSerialized, err := json.Marshal(&val) require.NoError(t, err) require.Equal(t, valSerialized, ptrSerialized) } func TestExecutionPayload_IsNil(t *testing.T) { t.Parallel() var payload *types.ExecutionPayload require.Nil(t, payload) payload = generateExecutionPayload() require.NotNil(t, payload) } func TestExecutionPayload_IsBlinded(t *testing.T) { t.Parallel() payload := generateExecutionPayload() require.False(t, payload.IsBlinded()) } func TestExecutionPayload_Version(t *testing.T) { t.Parallel() payload := generateExecutionPayload() require.Equal(t, version.Deneb1(), payload.GetForkVersion()) } func TestExecutionPayload_ToHeader(t *testing.T) { t.Parallel() payload := &types.ExecutionPayload{ Versionable: types.NewVersionable(version.Deneb1()), ParentHash: common.ExecutionHash{}, FeeRecipient: common.ExecutionAddress{}, StateRoot: bytes.B32{}, ReceiptsRoot: bytes.B32{}, LogsBloom: bytes.B256{}, Random: bytes.B32{}, Number: math.U64(0), GasLimit: math.U64(0), GasUsed: math.U64(0), Timestamp: math.U64(0), ExtraData: []byte{}, BaseFeePerGas: &math.U256{}, BlockHash: common.ExecutionHash{}, Transactions: [][]byte{{0x01}}, Withdrawals: engineprimitives.Withdrawals{}, BlobGasUsed: math.U64(0), ExcessBlobGas: math.U64(0), } header, err := payload.ToHeader() require.NoError(t, err) require.NotNil(t, header) require.Equal(t, payload.GetParentHash(), header.GetParentHash()) require.Equal(t, payload.GetFeeRecipient(), header.GetFeeRecipient()) require.Equal(t, payload.GetStateRoot(), header.GetStateRoot()) require.Equal(t, payload.GetReceiptsRoot(), header.GetReceiptsRoot()) require.Equal(t, payload.GetLogsBloom(), header.GetLogsBloom()) require.Equal(t, payload.GetPrevRandao(), header.GetPrevRandao()) require.Equal(t, payload.GetNumber(), header.GetNumber()) require.Equal(t, payload.GetGasLimit(), header.GetGasLimit()) require.Equal(t, payload.GetGasUsed(), header.GetGasUsed()) require.Equal(t, payload.GetTimestamp(), header.GetTimestamp()) require.Equal(t, payload.GetExtraData(), header.GetExtraData()) require.Equal(t, payload.GetBaseFeePerGas(), header.GetBaseFeePerGas()) require.Equal(t, payload.GetBlockHash(), header.GetBlockHash()) require.Equal(t, payload.GetBlobGasUsed(), header.GetBlobGasUsed()) require.Equal(t, payload.GetExcessBlobGas(), header.GetExcessBlobGas()) require.Equal(t, payload.GetForkVersion(), header.GetForkVersion()) require.Equal(t, payload.HashTreeRoot(), header.HashTreeRoot()) } func TestExecutionPayload_UnmarshalJSON_Error(t *testing.T) { t.Parallel() original := generateExecutionPayload() validJSON, err := original.MarshalJSON() require.NoError(t, err) testCases := []struct { name string removeField string expectedError string }{ { name: "missing required field 'parentHash'", removeField: "parentHash", expectedError: "missing required field 'parentHash' for ExecutionPayload", }, { name: "missing required field 'feeRecipient'", removeField: "feeRecipient", expectedError: "missing required field 'feeRecipient' for ExecutionPayload", }, { name: "missing required field 'stateRoot'", removeField: "stateRoot", expectedError: "missing required field 'stateRoot' for ExecutionPayload", }, { name: "missing required field 'receiptsRoot'", removeField: "receiptsRoot", expectedError: "missing required field 'receiptsRoot' for ExecutionPayload", }, { name: "missing required field 'logsBloom'", removeField: "logsBloom", expectedError: "missing required field 'logsBloom' for ExecutionPayload", }, { name: "missing required field 'prevRandao'", removeField: "prevRandao", expectedError: "missing required field 'prevRandao' for ExecutionPayload", }, { name: "missing required field 'blockNumber'", removeField: "blockNumber", expectedError: "missing required field 'blockNumber' for ExecutionPayload", }, { name: "missing required field 'gasLimit'", removeField: "gasLimit", expectedError: "missing required field 'gasLimit' for ExecutionPayload", }, { name: "missing required field 'gasUsed'", removeField: "gasUsed", expectedError: "missing required field 'gasUsed' for ExecutionPayload", }, { name: "missing required field 'timestamp'", removeField: "timestamp", expectedError: "missing required field 'timestamp' for ExecutionPayload", }, { name: "missing required field 'extraData'", removeField: "extraData", expectedError: "missing required field 'extraData' for ExecutionPayload", }, { name: "missing required field 'baseFeePerGas'", removeField: "baseFeePerGas", expectedError: "missing required field 'baseFeePerGas' for ExecutionPayload", }, { name: "missing required field 'blockHash'", removeField: "blockHash", expectedError: "missing required field 'blockHash' for ExecutionPayload", }, { name: "missing required field 'transactions'", removeField: "transactions", expectedError: "missing required field 'transactions' for ExecutionPayload", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { var payload types.ExecutionPayload var jsonMap map[string]interface{} errUnmarshal := json.Unmarshal(validJSON, &jsonMap) require.NoError(t, errUnmarshal) delete(jsonMap, tc.removeField) malformedJSON, errMarshal := json.Marshal(jsonMap) require.NoError(t, errMarshal) err = payload.UnmarshalJSON(malformedJSON) require.Error(t, err) require.Contains(t, err.Error(), tc.expectedError) }) } } ================================================ FILE: consensus-types/types/pending_partial_withdrawal.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // sszPendingPartialWithdrawalSize defines the total SSZ serialized size for // PendingPartialWithdrawal. The fields are assumed to be encoded as follows: // - ValidatorIndex: 8 bytes (uint64) // - Amount: 8 bytes (math.Gwei) // - WithdrawableEpoch: 8 bytes (uint64) // Total = 8 + 8 + 8 = 24 bytes. const sszPendingPartialWithdrawalSize = 24 // Compile-time check to ensure PendingPartialWithdrawal and PendingPartialWithdrawals implements the necessary interfaces. var ( _ ssz.StaticObject = (*PendingPartialWithdrawal)(nil) _ constraints.SSZMarshallable = (*PendingPartialWithdrawal)(nil) _ ssz.DynamicObject = (*PendingPartialWithdrawals)(nil) _ constraints.SSZMarshallable = (*PendingPartialWithdrawals)(nil) ) // PendingPartialWithdrawal reflects the following spec: // // class PendingPartialWithdrawal(Container): // validator_index: ValidatorIndex // amount: Gwei // withdrawable_epoch: Epoch type PendingPartialWithdrawal struct { ValidatorIndex math.ValidatorIndex Amount math.Gwei WithdrawableEpoch math.Epoch } /* -------------------------------------------------------------------------- */ /* PendingPartialWithdrawal SSZ */ /* -------------------------------------------------------------------------- */ // ValidateAfterDecodingSSZ validates the PendingPartialWithdrawal object // after decoding from SSZ. Customize further validation as needed. func (p *PendingPartialWithdrawal) ValidateAfterDecodingSSZ() error { return nil } // DefineSSZ registers the SSZ encoding for each field in PendingPartialWithdrawal. func (p *PendingPartialWithdrawal) DefineSSZ(codec *ssz.Codec) { ssz.DefineUint64(codec, &p.ValidatorIndex) ssz.DefineUint64(codec, &p.Amount) ssz.DefineUint64(codec, &p.WithdrawableEpoch) } // SizeSSZ returns the fixed size of the SSZ serialization for PendingPartialWithdrawal. func (p *PendingPartialWithdrawal) SizeSSZ(_ *ssz.Sizer) uint32 { return sszPendingPartialWithdrawalSize } // MarshalSSZ returns the SSZ encoding of the PendingPartialWithdrawal. func (p *PendingPartialWithdrawal) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(p)) return buf, ssz.EncodeToBytes(buf, p) } // HashTreeRoot computes and returns the hash tree root for the PendingPartialWithdrawal. func (p *PendingPartialWithdrawal) HashTreeRoot() common.Root { return ssz.HashSequential(p) } // HashTreeRootWith SSZ hashes the Deposit object with a hasher. Needed for BeaconState SSZ. func (p *PendingPartialWithdrawal) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'ValidatorIndex' hh.PutUint64(uint64(p.ValidatorIndex)) // Field (1) 'Amount' hh.PutUint64(uint64(p.Amount)) // Field (2) 'WithdrawableEpoch' hh.PutUint64(uint64(p.WithdrawableEpoch)) hh.Merkleize(indx) return nil } // PendingPartialWithdrawals is a SSZ list of PendingPartialWithdrawal containers. type PendingPartialWithdrawals []*PendingPartialWithdrawal // NewEmptyPendingPartialWithdrawals returns a new empty PendingPartialWithdrawals list. func NewEmptyPendingPartialWithdrawals() *PendingPartialWithdrawals { return &PendingPartialWithdrawals{} } // DefineSSZ defines the SSZ encoding for the PendingPartialWithdrawals list. func (p *PendingPartialWithdrawals) DefineSSZ(codec *ssz.Codec) { ssz.DefineSliceOfStaticObjectsOffset(codec, (*[]*PendingPartialWithdrawal)(p), constants.PendingPartialWithdrawalsLimit) ssz.DefineSliceOfStaticObjectsContent(codec, (*[]*PendingPartialWithdrawal)(p), constants.PendingPartialWithdrawalsLimit) } // SizeSSZ returns the size of the PendingPartialWithdrawals list. func (p *PendingPartialWithdrawals) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { if fixed { return constants.SSZOffsetSize } return constants.SSZOffsetSize + ssz.SizeSliceOfStaticObjects(siz, *p) } // MarshalSSZ returns the SSZ encoding of the PendingPartialWithdrawals list. func (p *PendingPartialWithdrawals) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(p)) return buf, ssz.EncodeToBytes(buf, p) } // ValidateAfterDecodingSSZ validates the PendingPartialWithdrawals list after decoding from SSZ. func (p *PendingPartialWithdrawals) ValidateAfterDecodingSSZ() error { if p == nil { return errors.New("nil PendingPartialWithdrawals") } if len(*p) > constants.PendingPartialWithdrawalsLimit { return errors.New("pending partial withdrawals too large") } return nil } // PendingBalanceToWithdraw implements get_pending_balance_to_withdraw from the ETH2.0 spec. // https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-get_pending_balance_to_withdraw func (p PendingPartialWithdrawals) PendingBalanceToWithdraw(validatorIndex math.ValidatorIndex) math.Gwei { var total math.Gwei for _, withdrawal := range p { if withdrawal.ValidatorIndex == validatorIndex { total += withdrawal.Amount } } return total } ================================================ FILE: consensus-types/types/pending_partial_withdrawal_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "fmt" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/encoding/ssz" prysmtypes "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" "github.com/stretchr/testify/require" ) func TestPendingPartialWithdrawal_ValidValuesSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string pending *types.PendingPartialWithdrawal }{ { name: "basic", pending: &types.PendingPartialWithdrawal{ ValidatorIndex: 1, Amount: 1000, WithdrawableEpoch: 10, }, }, { name: "zero amount", pending: &types.PendingPartialWithdrawal{ ValidatorIndex: 2, Amount: 0, WithdrawableEpoch: 20, }, }, { name: "max values", pending: &types.PendingPartialWithdrawal{ ValidatorIndex: 1<<64 - 1, Amount: 1<<64 - 1, WithdrawableEpoch: 1<<64 - 1, }, }, { name: "random-ish values", pending: &types.PendingPartialWithdrawal{ ValidatorIndex: 7, Amount: 54321, WithdrawableEpoch: 999, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // Marshal the original pending partial withdrawal. pendingBytes, err := tc.pending.MarshalSSZ() require.NoError(t, err) // Unmarshal into the prysm type. var prysmType prysmtypes.PendingPartialWithdrawal err = prysmType.UnmarshalSSZ(pendingBytes) require.NoError(t, err) // Compare the HashTreeRoots. originalHTR := tc.pending.HashTreeRoot() prysmHTR, err := prysmType.HashTreeRoot() require.NoError(t, err) require.Equal(t, originalHTR[:], prysmHTR[:]) // Marshal the prysm request prysmBytes, err := prysmType.MarshalSSZ() require.NoError(t, err) // Unmarshal back into original type var recomputedPending types.PendingPartialWithdrawal err = ssz.Unmarshal(prysmBytes, &recomputedPending) require.NoError(t, err) require.Equal(t, *tc.pending, recomputedPending) }) } } //nolint:paralleltest // Invalid SSZ values cannot be run in parallel due to shared zeroalloc. func TestPendingPartialWithdrawal_InvalidValuesUnmarshalSSZ(t *testing.T) { // Build a valid pending partial withdrawal to get a baseline payload. validPending := &types.PendingPartialWithdrawal{ ValidatorIndex: 1, Amount: 1000, WithdrawableEpoch: 10, } validBytes, err := validPending.MarshalSSZ() require.NoError(t, err) // Define several invalid payloads. invalidPayloads := [][]byte{ nil, // nil slice {}, // empty slice []byte("this is not ssz"), // arbitrary non-SSZ data {0x00, 0x01}, // too short to be valid // A truncated valid payload: remove last 5 bytes. func() []byte { if len(validBytes) > 5 { return validBytes[:len(validBytes)-5] } return validBytes }(), // A valid payload with extra trailing bytes. func() []byte { extra := []byte{0xAA, 0xBB, 0xCC, 0xDD} return append(validBytes, extra...) }(), } for i, payload := range invalidPayloads { i, payload := i, payload // capture loop variables t.Run(fmt.Sprintf("invalidPendingPartialWithdrawal_%d", i), func(t *testing.T) { // Ensure that Unmarshal does not panic and returns an error. require.NotPanics(t, func() { var p types.PendingPartialWithdrawal err = ssz.Unmarshal(payload, &p) require.Error(t, err, "expected error for payload %v", payload) }) }) } } // ----------------------------------------------------------------------------- // Tests for the slice type: PendingPartialWithdrawals // ----------------------------------------------------------------------------- func TestPendingPartialWithdrawals_ValidValuesSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string withdraw *types.PendingPartialWithdrawals }{ { name: "empty slice", withdraw: types.NewEmptyPendingPartialWithdrawals(), }, { name: "one element", withdraw: &types.PendingPartialWithdrawals{ &types.PendingPartialWithdrawal{ ValidatorIndex: 1, Amount: 1000, WithdrawableEpoch: 10, }, }, }, { name: "multiple elements", withdraw: &types.PendingPartialWithdrawals{ &types.PendingPartialWithdrawal{ValidatorIndex: 1, Amount: 1000, WithdrawableEpoch: 10}, &types.PendingPartialWithdrawal{ValidatorIndex: 2, Amount: 2000, WithdrawableEpoch: 20}, &types.PendingPartialWithdrawal{ValidatorIndex: 3, Amount: 3000, WithdrawableEpoch: 30}, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // Marshal the slice to SSZ. withdrawBytes, err := tc.withdraw.MarshalSSZ() require.NoError(t, err) // Unmarshal into a new PendingPartialWithdrawals variable. var recomputed types.PendingPartialWithdrawals err = ssz.Unmarshal(withdrawBytes, &recomputed) require.NoError(t, err) // Compare the original slice to the recomputed one. require.Equal(t, tc.withdraw, &recomputed) }) } } //nolint:paralleltest // Invalid SSZ payloads rely on shared zeroalloc func TestPendingPartialWithdrawals_InvalidValuesUnmarshalSSZ(t *testing.T) { // Build a valid pending partial withdrawals slice to obtain a baseline payload. validWithdrawals := types.PendingPartialWithdrawals{ &types.PendingPartialWithdrawal{ ValidatorIndex: 1, Amount: 1000, WithdrawableEpoch: 10, }, &types.PendingPartialWithdrawal{ ValidatorIndex: 2, Amount: 2000, WithdrawableEpoch: 20, }, } validBytes, err := validWithdrawals.MarshalSSZ() require.NoError(t, err) invalidPayloads := [][]byte{ nil, // nil slice {}, // empty slice []byte("this is not ssz"), // arbitrary non-SSZ data {0x00, 0x01}, // too short to be valid // A truncated valid payload. func() []byte { if len(validBytes) > 5 { return validBytes[:len(validBytes)-5] } return validBytes }(), // A valid payload with extra trailing bytes. func() []byte { extra := []byte{0xAA, 0xBB, 0xCC, 0xDD} return append(validBytes, extra...) }(), } for i, payload := range invalidPayloads { i, payload := i, payload // capture range variables t.Run(fmt.Sprintf("invalidPendingSlice_%d", i), func(t *testing.T) { // Ensure that unmarshalling does not panic and returns an error. require.NotPanics(t, func() { var withdrawals types.PendingPartialWithdrawals err = ssz.Unmarshal(payload, &withdrawals) require.Error(t, err, "expected error for payload %v", payload) }) }) } } ================================================ FILE: consensus-types/types/proposer_slashings.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // separate file for ease of future implementation package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure ProposerSlashing implements necessary interfaces. var ( _ ssz.StaticObject = (*ProposerSlashing)(nil) _ constraints.SSZMarshallableRootable = (*ProposerSlashing)(nil) _ common.UnusedEnforcer = (*ProposerSlashings)(nil) ) type ( ProposerSlashing = common.UnusedType ProposerSlashings []*ProposerSlashing ) // SizeSSZ returns the SSZ encoded size in bytes for the ProposerSlashings. func (ps ProposerSlashings) SizeSSZ(siz *ssz.Sizer, _ bool) uint32 { return ssz.SizeSliceOfStaticObjects(siz, ps) } // DefineSSZ defines the SSZ encoding for the ProposerSlashings object. func (ps ProposerSlashings) DefineSSZ(c *ssz.Codec) { c.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*ProposerSlashing)(&ps), constants.MaxProposerSlashings) }) c.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*ProposerSlashing)(&ps), constants.MaxProposerSlashings) }) c.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfStaticObjectsOffset(c, (*[]*ProposerSlashing)(&ps), constants.MaxProposerSlashings) }) } // HashTreeRoot returns the hash tree root of the ProposerSlashings. func (ps ProposerSlashings) HashTreeRoot() common.Root { return ssz.HashSequential(ps) } // EnforceUnused return true if the length of the ProposerSlashings is 0. // As long as this type remains unimplemented and unvalidated by consensus, // we must enforce that it contains no data. func (ps ProposerSlashings) EnforceUnused() error { if len(ps) != 0 { return errors.New("ProposerSlashings must be unused") } return nil } ================================================ FILE: consensus-types/types/signed_beacon_block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/version" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure SignedBeaconBlock implements necessary interfaces. var ( _ ssz.DynamicObject = (*SignedBeaconBlock)(nil) _ constraints.SSZVersionedMarshallableRootable = (*SignedBeaconBlock)(nil) ) // SignedBeaconBlock is a struct that contains a BeaconBlock and a BLSSignature. // // NOTE: This struct is only ever (un)marshalled with SSZ and NOT with JSON. type SignedBeaconBlock struct { *BeaconBlock Signature crypto.BLSSignature } /* -------------------------------------------------------------------------- */ /* Constructors */ /* -------------------------------------------------------------------------- */ // NewSignedBeaconBlock signs the provided BeaconBlock and populates the receiver. // // NOTE: will panic if any provided argument is nil. Only errors if signing fails. func NewSignedBeaconBlock( blk *BeaconBlock, forkData *ForkData, cs ProposerDomain, signer crypto.BLSSigner, ) (*SignedBeaconBlock, error) { domain := forkData.ComputeDomain(cs.DomainTypeProposer()) signingRoot := ComputeSigningRoot(blk, domain) signature, err := signer.Sign(signingRoot[:]) if err != nil { return nil, err } return &SignedBeaconBlock{ BeaconBlock: blk, Signature: signature, }, nil } func NewEmptySignedBeaconBlockWithVersion(forkVersion common.Version) (*SignedBeaconBlock, error) { switch forkVersion { case version.Deneb(), version.Deneb1(), version.Electra(), version.Electra1(), version.Fulu(): return &SignedBeaconBlock{ BeaconBlock: NewEmptyBeaconBlockWithVersion(forkVersion), }, nil default: // We return a non-nil block here to appease nilaway. return nil, errors.Wrapf(ErrForkVersionNotSupported, "fork %d", forkVersion) } } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the SignedBeaconBlockHeader object // in SSZ encoding. // Total size: MessageOffset (4) + Signature (96) + MessageContentDynamic. func (b *SignedBeaconBlock) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { size := constants.SSZOffsetSize + bytes.B96Size if fixed { return size } size += ssz.SizeDynamicObject(siz, b.BeaconBlock) return size } // DefineSSZ defines the SSZ encoding for the SignedBeaconBlockHeader object. func (b *SignedBeaconBlock) DefineSSZ(codec *ssz.Codec) { ssz.DefineDynamicObjectOffset(codec, &b.BeaconBlock) ssz.DefineStaticBytes(codec, &b.Signature) // Define the dynamic data (fields) ssz.DefineDynamicObjectContent(codec, &b.BeaconBlock) } // MarshalSSZ marshals the SignedBeaconBlockHeader object to SSZ format. func (b *SignedBeaconBlock) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(b)) return buf, ssz.EncodeToBytes(buf, b) } func (b *SignedBeaconBlock) ValidateAfterDecodingSSZ() error { return b.BeaconBlock.ValidateAfterDecodingSSZ() } // HashTreeRoot computes the SSZ hash tree root of the // SignedBeaconBlockHeader object. func (b *SignedBeaconBlock) HashTreeRoot() common.Root { return ssz.HashSequential(b) } /* -------------------------------------------------------------------------- */ /* Getters */ /* -------------------------------------------------------------------------- */ func (b *SignedBeaconBlock) GetBeaconBlock() *BeaconBlock { return b.BeaconBlock } func (b *SignedBeaconBlock) GetSignature() crypto.BLSSignature { return b.Signature } ================================================ FILE: consensus-types/types/signed_beacon_block_header.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure SignedBeaconBlockHeader implements necessary interfaces. var ( _ ssz.StaticObject = (*SignedBeaconBlockHeader)(nil) _ constraints.SSZMarshallableRootable = (*SignedBeaconBlockHeader)(nil) ) // SignedBeaconBlockHeader is a struct that contains a BeaconBlockHeader and a BLSSignature. // // NOTE: This struct is only ever (un)marshalled with SSZ and NOT with JSON. type SignedBeaconBlockHeader struct { Header *BeaconBlockHeader Signature crypto.BLSSignature } /* -------------------------------------------------------------------------- */ /* Constructor */ /* -------------------------------------------------------------------------- */ // NewSignedBeaconBlockHeader creates a new BeaconBlockHeader. func NewSignedBeaconBlockHeader( header *BeaconBlockHeader, signature crypto.BLSSignature, ) *SignedBeaconBlockHeader { return &SignedBeaconBlockHeader{ header, signature, } } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the SignedBeaconBlockHeader object // in SSZ encoding. Total size: Header (112) + Signature (96). func (b *SignedBeaconBlockHeader) SizeSSZ(sizer *ssz.Sizer) uint32 { //nolint:mnd // no magic size := (*BeaconBlockHeader)(nil).SizeSSZ(sizer) + 96 return size } // DefineSSZ defines the SSZ encoding for the SignedBeaconBlockHeader object. func (b *SignedBeaconBlockHeader) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticObject(codec, &b.Header) ssz.DefineStaticBytes(codec, &b.Signature) } // MarshalSSZ marshals the SignedBeaconBlockHeader object to SSZ format. func (b *SignedBeaconBlockHeader) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(b)) return buf, ssz.EncodeToBytes(buf, b) } func (*SignedBeaconBlockHeader) ValidateAfterDecodingSSZ() error { return nil } // HashTreeRoot computes the SSZ hash tree root of the // SignedBeaconBlockHeader object. func (b *SignedBeaconBlockHeader) HashTreeRoot() common.Root { return ssz.HashSequential(b) } /* -------------------------------------------------------------------------- */ /* Getters and Setters */ /* -------------------------------------------------------------------------- */ // Getheader retrieves the header of the SignedBeaconBlockHeader. func (b *SignedBeaconBlockHeader) GetHeader() *BeaconBlockHeader { return b.Header } // GetSignature retrieves the Signature of the SignedBeaconBlockHeader. func (b *SignedBeaconBlockHeader) GetSignature() crypto.BLSSignature { return b.Signature } ================================================ FILE: consensus-types/types/signed_beacon_block_header_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) func TestSignedBeaconBlockHeader_Serialization(t *testing.T) { t.Parallel() header := types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{0xde, 0xad, 0xbe, 0xef}, common.Root{0xca, 0xca, 0xca, 0xfe}, common.Root{0xde, 0xad, 0xca, 0xfe}, ) sig := crypto.BLSSignature{0xde, 0xad, 0xc4, 0xc4} orig := &types.SignedBeaconBlockHeader{ Header: header, Signature: sig, } data, err := orig.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(types.SignedBeaconBlockHeader) err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, orig, unmarshalled) buf := make([]byte, karalabessz.Size(orig)) err = karalabessz.EncodeToBytes(buf, orig) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) } func TestSignedBeaconBlockHeader_EmptySerialization(t *testing.T) { t.Parallel() orig := &types.SignedBeaconBlockHeader{} data, err := orig.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(types.SignedBeaconBlockHeader) err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.NotNil(t, unmarshalled) require.NotNil(t, unmarshalled.GetHeader()) require.NotNil(t, unmarshalled.GetSignature()) require.Equal(t, &types.BeaconBlockHeader{}, unmarshalled.GetHeader()) buf := make([]byte, karalabessz.Size(orig)) err = karalabessz.EncodeToBytes(buf, orig) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) } func TestSignedBeaconBlockHeader_SizeSSZ(t *testing.T) { t.Parallel() sigHeader := types.NewSignedBeaconBlockHeader( types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{0xaa}, common.Root{0xbb}, common.Root{0xcc}, ), crypto.BLSSignature{0xff}, ) size := karalabessz.Size(sigHeader) require.Equal(t, uint32(208), size) } func TestSignedBeaconBlockHeader_HashTreeRoot(t *testing.T) { t.Parallel() sigHeader := types.NewSignedBeaconBlockHeader( types.NewBeaconBlockHeader( math.Slot(100), math.ValidatorIndex(200), common.Root{0xaa}, common.Root{0xbb}, common.Root{0xcc}, ), crypto.BLSSignature{0xff}, ) _ = sigHeader.HashTreeRoot() } ================================================ FILE: consensus-types/types/signed_beacon_block_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "testing" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" sszutil "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/testing/utils" cmtcrypto "github.com/cometbft/cometbft/crypto" "github.com/cometbft/cometbft/crypto/bls12381" "github.com/cometbft/cometbft/privval" "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) // runForAllSupportedVersions iterates over all supported versions, // creating a subtest for each that runs the provided testFunc. // TODO: Find a better home for this function. func runForAllSupportedVersions(t *testing.T, testFunc func(t *testing.T, v common.Version)) { t.Helper() for _, v := range version.GetSupportedVersions() { v := v // capture the variable for parallel tests t.Run(v.String(), func(t *testing.T) { t.Parallel() testFunc(t, v) }) } } func generateFakeSignedBeaconBlock(t *testing.T, version common.Version) *types.SignedBeaconBlock { t.Helper() return &types.SignedBeaconBlock{ BeaconBlock: utils.GenerateValidBeaconBlock(t, version), } } func generatePrivKey() (cmtcrypto.PrivKey, error) { privKey, err := bls12381.GenPrivKey() if err != nil { return nil, err } return privKey, nil } func generateSigningRoot(blk *types.BeaconBlock) (common.Root, error) { cs, err := spec.DevnetChainSpec() if err != nil { return common.Root{}, err } domain := (&types.ForkData{}).ComputeDomain(cs.DomainTypeProposer()) signingRoot := types.ComputeSigningRoot(blk, domain) return signingRoot, nil } func generateRealSignedBeaconBlock(t *testing.T, blsSigner crypto.BLSSigner, version common.Version) (*types.SignedBeaconBlock, error) { t.Helper() blk := utils.GenerateValidBeaconBlock(t, version) signingRoot, err := generateSigningRoot(blk) if err != nil { return nil, err } signature, err := blsSigner.Sign(signingRoot[:]) if err != nil { return nil, err } return &types.SignedBeaconBlock{ BeaconBlock: blk, Signature: signature, }, nil } // TestNewSignedBeaconBlockFromSSZ tests the roundtrip SSZ encoding for Deneb. func TestNewSignedBeaconBlockFromSSZ(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { originalBlock := generateFakeSignedBeaconBlock(t, v) blockBytes, err := originalBlock.MarshalSSZ() require.NoError(t, err) require.NotNil(t, blockBytes) newBlock, err := types.NewEmptySignedBeaconBlockWithVersion(originalBlock.GetForkVersion()) require.NoError(t, err) err = sszutil.Unmarshal(blockBytes, newBlock) require.NoError(t, err) require.NotNil(t, newBlock) require.Equal(t, originalBlock, newBlock) }) } func TestNewSignedBeaconBlockFromSSZForkVersionNotSupported(t *testing.T) { t.Parallel() _, err := types.NewEmptySignedBeaconBlockWithVersion(version.Altair()) require.ErrorIs(t, err, types.ErrForkVersionNotSupported) } func TestSignedBeaconBlock_HashTreeRoot(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { sBlk := generateFakeSignedBeaconBlock(t, v) sBlk.HashTreeRoot() }) } // TestSignedBeaconBlock_SignBeaconBlock ensures the validity of the block // signatures. func TestSignedBeaconBlock_SignBeaconBlock(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { // Generate a new bls key signer filePV, err := privval.GenFilePV( "signed_beacon_block_test_filepv_key", "signed_beacon_block_test_filepv_state", generatePrivKey, ) require.NoError(t, err) blsSigner := signer.BLSSigner{PrivValidator: filePV} // Generate real signed beacon block signedBlk, err := generateRealSignedBeaconBlock(t, blsSigner, v) require.NoError(t, err) require.NotNil(t, signedBlk) // Use SignBeaconBlock to sign the same BeaconBlock cs, err := spec.DevnetChainSpec() require.NoError(t, err) newSignedBlk, err := types.NewSignedBeaconBlock( signedBlk.GetBeaconBlock(), &types.ForkData{}, cs, blsSigner, ) require.NoError(t, err) // Check that the signature from SignBeaconBlock matches sig1 := signedBlk.GetSignature() sig2 := newSignedBlk.GetSignature() require.Equal(t, sig1, sig2) // Verify the signature is good signingRoot, err := generateSigningRoot(newSignedBlk.GetBeaconBlock()) require.NoError(t, err) err = blsSigner.VerifySignature(blsSigner.PublicKey(), signingRoot[:], newSignedBlk.GetSignature()) require.NoError(t, err) }) } func TestSignedBeaconBlock_SizeSSZ(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { sBlk := generateFakeSignedBeaconBlock(t, v) size := ssz.Size(sBlk) require.Positive(t, size) }) } func TestSignedBeaconBlock_EmptySerialization(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, fv common.Version) { orig := &types.SignedBeaconBlock{ BeaconBlock: types.NewEmptyBeaconBlockWithVersion(fv), } data, err := orig.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled, err := types.NewEmptySignedBeaconBlockWithVersion(fv) require.NoError(t, err) err = sszutil.Unmarshal(data, unmarshalled) require.NoError(t, err) require.NotNil(t, unmarshalled.GetBeaconBlock()) require.NotNil(t, unmarshalled.GetSignature()) buf := make([]byte, ssz.Size(orig)) err = ssz.EncodeToBytes(buf, orig) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) }) } ================================================ FILE: consensus-types/types/signing_data.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "encoding/binary" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) var ( _ ssz.StaticObject = (*SigningData)(nil) _ constraints.SSZMarshallableRootable = (*SigningData)(nil) ) // SigningData as defined in the Ethereum 2.0 specification. // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#signingdata type SigningData struct { // ObjectRoot is the hash tree root of the object being signed. ObjectRoot common.Root // Domain is the domain the object is being signed in. Domain common.Domain } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the SigningData object in SSZ encoding. func (*SigningData) SizeSSZ(_ *ssz.Sizer) uint32 { //nolint:mnd // 32*2 = 64. return 64 } // DefineSSZ defines the SSZ encoding for the SigningData object. func (s *SigningData) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticBytes(codec, &s.ObjectRoot) ssz.DefineStaticBytes(codec, &s.Domain) } // HashTreeRoot computes the SSZ hash tree root of the SigningData object. func (s *SigningData) HashTreeRoot() common.Root { return ssz.HashSequential(s) } // MarshalSSZTo marshals the SigningData object to SSZ format into the provided // buffer. func (s *SigningData) MarshalSSZTo(buf []byte) ([]byte, error) { return buf, ssz.EncodeToBytes(buf, s) } // MarshalSSZ marshals the SigningData object to SSZ format. func (s *SigningData) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(s)) return s.MarshalSSZTo(buf) } func (*SigningData) ValidateAfterDecodingSSZ() error { return nil } // ComputeSigningRoot as defined in the Ethereum 2.0 specification. // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_signing_root func ComputeSigningRoot( sszObject interface{ HashTreeRoot() common.Root }, domain common.Domain, ) common.Root { return (&SigningData{ ObjectRoot: sszObject.HashTreeRoot(), Domain: domain, }).HashTreeRoot() } // ComputeSigningRootUInt64 computes the signing root of a uint64 value. func ComputeSigningRootUInt64( value uint64, domain common.Domain, ) common.Root { bz := make([]byte, constants.RootLength) binary.LittleEndian.PutUint64(bz, value) return (&SigningData{ ObjectRoot: common.Root(bz), Domain: domain, }).HashTreeRoot() } ================================================ FILE: consensus-types/types/signing_data_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" types "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/stretchr/testify/require" ) func generateSigningData() *types.SigningData { return &types.SigningData{ ObjectRoot: common.Root{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, Domain: bytes.B32{ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}, } } func TestSigningData_MarshalSSZ_UnmarshalSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string data *types.SigningData expected *types.SigningData err error }{ { name: "Valid SigningData", data: generateSigningData(), expected: generateSigningData(), err: nil, }, { name: "Empty SigningData", data: &types.SigningData{ ObjectRoot: common.Root{}, Domain: bytes.B32{}, }, expected: &types.SigningData{ ObjectRoot: common.Root{}, Domain: bytes.B32{}, }, err: nil, }, { name: "Invalid Buffer Size", data: generateSigningData(), expected: nil, err: io.ErrUnexpectedEOF, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() data, err := tc.data.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(types.SigningData) if tc.name == "Invalid Buffer Size" { err = ssz.Unmarshal(data[:32], unmarshalled) require.ErrorIs(t, err, tc.err) } else { err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, tc.expected, unmarshalled) } }) } } ================================================ FILE: consensus-types/types/slashing_info.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // SlashingInfoSize is the size of the SlashingInfo object in SSZ encoding. const SlashingInfoSize = 16 // 8 bytes for Slot + 8 bytes for Index // Compile-time assertions to ensure SlashingInfo implements the correct // interfaces. var ( _ ssz.StaticObject = (*SlashingInfo)(nil) _ constraints.SSZMarshallableRootable = (*SlashingInfo)(nil) ) // Compile-time assertion to ensure SlashingInfoSize matches the SizeSSZ method. var _ = [1]struct{}{}[16-SlashingInfoSize] // SlashingInfo represents a slashing info. type SlashingInfo struct { // Slot is the slot number of the slashing info. Slot math.Slot // ValidatorIndex is the validator index of the slashing info. Index math.U64 } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the SlashingInfo object in SSZ encoding. func (*SlashingInfo) SizeSSZ(*ssz.Sizer) uint32 { return SlashingInfoSize } // DefineSSZ defines the SSZ encoding for the SlashingInfo object. func (s *SlashingInfo) DefineSSZ(codec *ssz.Codec) { ssz.DefineUint64(codec, &s.Slot) ssz.DefineUint64(codec, &s.Index) } // HashTreeRoot computes the SSZ hash tree root of the SlashingInfo object. func (s *SlashingInfo) HashTreeRoot() common.Root { return ssz.HashSequential(s) } // MarshalSSZ marshals the SlashingInfo object to SSZ format. func (s *SlashingInfo) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(s)) return buf, ssz.EncodeToBytes(buf, s) } func (*SlashingInfo) ValidateAfterDecodingSSZ() error { return nil } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo ssz marshals the SlashingInfo object into a pre-allocated byte // slice. func (s *SlashingInfo) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := s.MarshalSSZ() if err != nil { return nil, err } dst = append(dst, bz...) return dst, nil } // HashTreeRootWith ssz hashes the SlashingInfo object with a hasher. func (s *SlashingInfo) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'Slot' hh.PutUint64(uint64(s.Slot)) // Field (1) 'Index' hh.PutUint64(uint64(s.Index)) hh.Merkleize(indx) return nil } // GetTree ssz hashes the SlashingInfo object. func (s *SlashingInfo) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(s) } /* -------------------------------------------------------------------------- */ /* Getters and Setters */ /* -------------------------------------------------------------------------- */ // GetSlot returns the slot of the slashing info. func (s *SlashingInfo) GetSlot() math.Slot { return s.Slot } // GetIndex returns the index of the slashing info. func (s *SlashingInfo) GetIndex() math.U64 { return s.Index } // SetSlot sets the slot of the slashing info. func (s *SlashingInfo) SetSlot(slot math.Slot) { s.Slot = slot } // SetIndex sets the index of the slashing info. func (s *SlashingInfo) SetIndex(index math.U64) { s.Index = index } ================================================ FILE: consensus-types/types/slashing_info_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) func generateSlashingInfo() *types.SlashingInfo { return &types.SlashingInfo{ Slot: 12345, Index: 67890, } } func TestSlashingInfo_MarshalSSZ_UnmarshalSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string data *types.SlashingInfo expected *types.SlashingInfo err error }{ { name: "Valid SlashingInfo", data: generateSlashingInfo(), expected: generateSlashingInfo(), err: nil, }, { name: "Empty SlashingInfo", data: &types.SlashingInfo{ Slot: 0, Index: 0, }, expected: &types.SlashingInfo{ Slot: 0, Index: 0, }, err: nil, }, { name: "Invalid Buffer Size", data: generateSlashingInfo(), expected: nil, err: io.ErrUnexpectedEOF, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() data, err := tc.data.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(types.SlashingInfo) if tc.name == "Invalid Buffer Size" { err = ssz.Unmarshal(data[:8], unmarshalled) require.ErrorIs(t, err, tc.err) } else { err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, tc.expected, unmarshalled) var buf []byte buf, err = tc.data.MarshalSSZTo(buf) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, data, buf) } }) } } func TestSlashingInfo_GetTree(t *testing.T) { t.Parallel() data := generateSlashingInfo() tree, err := data.GetTree() require.NoError(t, err) require.NotNil(t, tree) expectedRoot := data.HashTreeRoot() actualRoot := tree.Hash() require.Equal(t, string(expectedRoot[:]), string(actualRoot)) } func TestSlashingInfo_SetSlot(t *testing.T) { t.Parallel() data := generateSlashingInfo() newSlot := math.Slot(67890) data.SetSlot(newSlot) require.Equal(t, newSlot, data.GetSlot()) } func TestSlashingInfo_SetIndex(t *testing.T) { t.Parallel() data := generateSlashingInfo() newIndex := math.U64(12345) data.SetIndex(newIndex) require.Equal(t, newIndex, data.GetIndex()) } ================================================ FILE: consensus-types/types/state.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // BeaconState represents the entire state of the beacon chain. type BeaconState struct { constraints.Versionable `json:"-"` // Versioning GenesisValidatorsRoot common.Root `json:"genesis_validators_root,omitempty"` Slot math.Slot `json:"slot,omitempty"` Fork *Fork `json:"fork,omitempty"` // History LatestBlockHeader *BeaconBlockHeader `json:"latest_block_header,omitempty"` BlockRoots []common.Root `json:"block_roots,omitempty"` StateRoots []common.Root `json:"state_roots,omitempty"` // Eth1 Eth1Data *Eth1Data `json:"eth1_data,omitempty"` Eth1DepositIndex uint64 `json:"eth1_deposit_index,omitempty"` LatestExecutionPayloadHeader *ExecutionPayloadHeader `json:"latest_execution_payload_header,omitempty"` // Registry Validators []*Validator `json:"validators,omitempty"` Balances []uint64 `json:"balances,omitempty"` // Randomness RandaoMixes []common.Bytes32 `json:"randao_mixes,omitempty"` // Withdrawals NextWithdrawalIndex uint64 `json:"next_withdrawal_index,omitempty"` NextWithdrawalValidatorIndex math.ValidatorIndex `json:"next_withdrawal_validator_index,omitempty"` // Slashing Slashings []math.Gwei `json:"slashings,omitempty"` TotalSlashing math.Gwei `json:"total_slashing,omitempty"` // PendingPartialWithdrawals is introduced in electra PendingPartialWithdrawals []*PendingPartialWithdrawal `json:"pending_partial_withdrawals,omitempty"` } // NewEmptyBeaconStateWithVersion returns a new empty BeaconState with the given fork version. func NewEmptyBeaconStateWithVersion(version common.Version) *BeaconState { return &BeaconState{ Versionable: NewVersionable(version), } } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the ssz encoded size in bytes for the BeaconState object. func (st *BeaconState) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { /* GenesisValidatorsRoot = 32 Slot = 8 Fork = 4 + 4 + 8 = 16 LatestBlockHeader = 8 + 8 + 32 + 32 + 32 = 112 BlockRoots = 4 (Dynamic field) StateRoots = 4 (Dynamic field) Eth1Data = 32 + 8 + 32 = 72 Eth1DepositIndex = 8 LatestExecutionPayloadHeader = 4 (Dynamic field) Validators = 4 (Dynamic field) Balances = 4 (Dynamic field) RandaoMixes = 4 (Dynamic field) NextWithdrawalIndex = 8 NextWithdrawalValidatorIndex = 8 Slashings = 4 (Dynamic field) TotalSlashings = 8 // Electra Fork PendingPartialWithdrawals = 4 (Dynamic field) */ var size uint32 = 300 if version.EqualsOrIsAfter(st.GetForkVersion(), version.Electra()) { // Add 4 for PendingPartialWithdrawals after Electra size += 4 } if fixed { return size } // Dynamic size fields size += ssz.SizeSliceOfStaticBytes(siz, st.BlockRoots) size += ssz.SizeSliceOfStaticBytes(siz, st.StateRoots) size += ssz.SizeDynamicObject(siz, st.LatestExecutionPayloadHeader) size += ssz.SizeSliceOfStaticObjects(siz, st.Validators) size += ssz.SizeSliceOfUint64s(siz, st.Balances) size += ssz.SizeSliceOfStaticBytes(siz, st.RandaoMixes) size += ssz.SizeSliceOfUint64s(siz, st.Slashings) if version.EqualsOrIsAfter(st.GetForkVersion(), version.Electra()) { size += ssz.SizeSliceOfStaticObjects(siz, st.PendingPartialWithdrawals) } return size } // DefineSSZ defines the SSZ encoding for the BeaconState object. // //nolint:mnd // TODO: get from accessible chainspec field params func (st *BeaconState) DefineSSZ(codec *ssz.Codec) { // Versioning ssz.DefineStaticBytes(codec, &st.GenesisValidatorsRoot) ssz.DefineUint64(codec, &st.Slot) ssz.DefineStaticObject(codec, &st.Fork) // History ssz.DefineStaticObject(codec, &st.LatestBlockHeader) ssz.DefineSliceOfStaticBytesOffset(codec, &st.BlockRoots, 8192) ssz.DefineSliceOfStaticBytesOffset(codec, &st.StateRoots, 8192) // Eth1 ssz.DefineStaticObject(codec, &st.Eth1Data) ssz.DefineUint64(codec, &st.Eth1DepositIndex) ssz.DefineDynamicObjectOffset(codec, &st.LatestExecutionPayloadHeader) // Registry ssz.DefineSliceOfStaticObjectsOffset(codec, &st.Validators, 1099511627776) ssz.DefineSliceOfUint64sOffset(codec, &st.Balances, 1099511627776) // Randomness ssz.DefineSliceOfStaticBytesOffset(codec, &st.RandaoMixes, 65536) // Withdrawals ssz.DefineUint64(codec, &st.NextWithdrawalIndex) ssz.DefineUint64(codec, &st.NextWithdrawalValidatorIndex) // Slashing ssz.DefineSliceOfUint64sOffset(codec, &st.Slashings, 1099511627776) ssz.DefineUint64(codec, (*uint64)(&st.TotalSlashing)) // Electra Withdrawals if version.EqualsOrIsAfter(st.GetForkVersion(), version.Electra()) { ssz.DefineSliceOfStaticObjectsOffset(codec, &st.PendingPartialWithdrawals, constants.PendingPartialWithdrawalsLimit) } // Dynamic content ssz.DefineSliceOfStaticBytesContent(codec, &st.BlockRoots, 8192) ssz.DefineSliceOfStaticBytesContent(codec, &st.StateRoots, 8192) ssz.DefineDynamicObjectContent(codec, &st.LatestExecutionPayloadHeader) ssz.DefineSliceOfStaticObjectsContent(codec, &st.Validators, 1099511627776) ssz.DefineSliceOfUint64sContent(codec, &st.Balances, 1099511627776) ssz.DefineSliceOfStaticBytesContent(codec, &st.RandaoMixes, 65536) ssz.DefineSliceOfUint64sContent(codec, &st.Slashings, 1099511627776) // Electra Withdrawals if version.EqualsOrIsAfter(st.GetForkVersion(), version.Electra()) { ssz.DefineSliceOfStaticObjectsContent(codec, &st.PendingPartialWithdrawals, constants.PendingPartialWithdrawalsLimit) } } // MarshalSSZ marshals the BeaconState into SSZ format. func (st *BeaconState) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(st)) return buf, ssz.EncodeToBytes(buf, st) } // UnmarshalSSZ unmarshals the BeaconState from SSZ format. func (st *BeaconState) UnmarshalSSZ(buf []byte) error { return ssz.DecodeFromBytes(buf, st) } // HashTreeRoot computes the Merkleization of the BeaconState. func (st *BeaconState) HashTreeRoot() common.Root { return ssz.HashConcurrent(st) } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // HashTreeRootWith ssz hashes the BeaconState object with a hasher. // //nolint:mnd,funlen,gocognit // todo fix. func (st *BeaconState) HashTreeRootWith( hh fastssz.HashWalker, ) error { indx := hh.Index() // Field (0) 'GenesisValidatorsRoot' hh.PutBytes(st.GenesisValidatorsRoot[:]) // Field (1) 'Slot' hh.PutUint64(uint64(st.Slot)) // Field (2) 'Fork' if st.Fork == nil { st.Fork = &Fork{} } if err := st.Fork.HashTreeRootWith(hh); err != nil { return err } // Field (3) 'LatestBlockHeader' if st.LatestBlockHeader == nil { st.LatestBlockHeader = &BeaconBlockHeader{} } if err := st.LatestBlockHeader.HashTreeRootWith(hh); err != nil { return err } // Field (4) 'BlockRoots' if size := len(st.BlockRoots); size > 8192 { return fastssz.ErrListTooBigFn("BeaconState.BlockRoots", size, 8192) } subIndx := hh.Index() for _, i := range st.BlockRoots { hh.Append(i[:]) } numItems := uint64(len(st.BlockRoots)) hh.MerkleizeWithMixin(subIndx, numItems, 8192) // Field (5) 'StateRoots' if size := len(st.StateRoots); size > 8192 { return fastssz.ErrListTooBigFn("BeaconState.StateRoots", size, 8192) } subIndx = hh.Index() for _, i := range st.StateRoots { hh.Append(i[:]) } numItems = uint64(len(st.StateRoots)) hh.MerkleizeWithMixin(subIndx, numItems, 8192) // Field (6) 'Eth1Data' if st.Eth1Data == nil { st.Eth1Data = &Eth1Data{} } if err := st.Eth1Data.HashTreeRootWith(hh); err != nil { return err } // Field (7) 'Eth1DepositIndex' hh.PutUint64(st.Eth1DepositIndex) // Field (8) 'LatestExecutionPayloadHeader' if st.LatestExecutionPayloadHeader == nil { st.LatestExecutionPayloadHeader = NewEmptyExecutionPayloadHeaderWithVersion(st.GetForkVersion()) } if err := st.LatestExecutionPayloadHeader.HashTreeRootWith(hh); err != nil { return err } // Field (9) 'Validators' subIndx = hh.Index() num := uint64(len(st.Validators)) if num > 1099511627776 { return fastssz.ErrIncorrectListSize } for _, elem := range st.Validators { if err := elem.HashTreeRootWith(hh); err != nil { return err } } hh.MerkleizeWithMixin(subIndx, num, 1099511627776) // Field (10) 'Balances' if size := len(st.Balances); size > 1099511627776 { return fastssz.ErrListTooBigFn( "BeaconState.Balances", size, 1099511627776, ) } subIndx = hh.Index() for _, i := range st.Balances { hh.AppendUint64(i) } hh.FillUpTo32() numItems = uint64(len(st.Balances)) hh.MerkleizeWithMixin( subIndx, numItems, fastssz.CalculateLimit(1099511627776, numItems, 8), ) // Field (11) 'RandaoMixes' if size := len(st.RandaoMixes); size > 65536 { return fastssz.ErrListTooBigFn("BeaconState.RandaoMixes", size, 65536) } subIndx = hh.Index() for _, i := range st.RandaoMixes { hh.Append(i[:]) } numItems = uint64(len(st.RandaoMixes)) hh.MerkleizeWithMixin(subIndx, numItems, 65536) // Field (12) 'NextWithdrawalIndex' hh.PutUint64(st.NextWithdrawalIndex) // Field (13) 'NextWithdrawalValidatorIndex' hh.PutUint64(uint64(st.NextWithdrawalValidatorIndex)) // Field (14) 'Slashings' if size := len(st.Slashings); size > 1099511627776 { return fastssz.ErrListTooBigFn( "BeaconState.Slashings", size, 1099511627776, ) } subIndx = hh.Index() for _, i := range st.Slashings { hh.AppendUint64(uint64(i)) } hh.FillUpTo32() numItems = uint64(len(st.Slashings)) hh.MerkleizeWithMixin( subIndx, numItems, fastssz.CalculateLimit(1099511627776, numItems, 8), ) // Field (15) 'TotalSlashing' hh.PutUint64(uint64(st.TotalSlashing)) // Field (16) 'PendingPartialWithdrawals' post-electra if version.EqualsOrIsAfter(st.GetForkVersion(), version.Electra()) { subIndx = hh.Index() numPPW := uint64(len(st.PendingPartialWithdrawals)) if numPPW > constants.PendingPartialWithdrawalsLimit { return fastssz.ErrIncorrectListSize } for _, elem := range st.PendingPartialWithdrawals { if err := elem.HashTreeRootWith(hh); err != nil { return err } } hh.MerkleizeWithMixin(subIndx, numPPW, constants.PendingPartialWithdrawalsLimit) } hh.Merkleize(indx) return nil } // GetTree ssz hashes the BeaconState object. func (st *BeaconState) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(st) } ================================================ FILE: consensus-types/types/state_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" ssz "github.com/ferranbt/fastssz" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) // generateValidBeaconState generates a valid beacon state for the types. func generateValidBeaconState(forkVersion common.Version) *types.BeaconState { beaconState := &types.BeaconState{ Versionable: types.NewVersionable(forkVersion), GenesisValidatorsRoot: common.Root{0x01, 0x02, 0x03}, Slot: 1234, BlockRoots: []common.Root{ {0x04, 0x05, 0x06}, {0x07, 0x08, 0x09}, }, StateRoots: []common.Root{ {0x0a, 0x0b, 0x0c}, {0x0d, 0x0e, 0x0f}, }, Fork: &types.Fork{ PreviousVersion: [4]byte{0x01, 0x00, 0x00, 0x00}, CurrentVersion: [4]byte{0x02, 0x00, 0x00, 0x00}, Epoch: 5678, }, Validators: []*types.Validator{ { Pubkey: [48]byte{0x01}, WithdrawalCredentials: [32]byte{0x02}, EffectiveBalance: 32000000000, Slashed: false, ActivationEligibilityEpoch: 1, ActivationEpoch: 2, ExitEpoch: 18446744073709551615, WithdrawableEpoch: 18446744073709551615, }, { Pubkey: [48]byte{0x03}, WithdrawalCredentials: [32]byte{0x04}, EffectiveBalance: 31000000000, Slashed: true, ActivationEligibilityEpoch: 3, ActivationEpoch: 4, ExitEpoch: 5, WithdrawableEpoch: 6, }, }, Balances: []uint64{32000000000, 31000000000}, RandaoMixes: generateRandomBytes32(65536), Slashings: []math.Gwei{1000000000, 2000000000}, NextWithdrawalIndex: 7, NextWithdrawalValidatorIndex: 8, TotalSlashing: 3000000000, LatestExecutionPayloadHeader: &types.ExecutionPayloadHeader{ ParentHash: [32]byte{0x16, 0x17, 0x18}, FeeRecipient: [20]byte{0x19, 0x1a, 0x1b}, StateRoot: [32]byte{0x1c, 0x1d, 0x1e}, ReceiptsRoot: [32]byte{0x1f, 0x20, 0x21}, LogsBloom: [256]byte{0x22}, Random: [32]byte{0x23, 0x24, 0x25}, Number: 9876, GasLimit: 30000000, GasUsed: 25000000, Timestamp: 1625097600, ExtraData: []byte{0x26, 0x27, 0x28}, BaseFeePerGas: math.NewU256(3906250), BlockHash: [32]byte{0x2c, 0x2d, 0x2e}, TransactionsRoot: [32]byte{0x2f, 0x30, 0x31}, WithdrawalsRoot: [32]byte{0x32, 0x33, 0x34}, }, LatestBlockHeader: &types.BeaconBlockHeader{ Slot: 5678, ProposerIndex: 123, ParentBlockRoot: [32]byte{0x35, 0x36, 0x37}, StateRoot: [32]byte{0x38, 0x39, 0x3a}, BodyRoot: [32]byte{0x3b, 0x3c, 0x3d}, }, Eth1Data: &types.Eth1Data{ DepositRoot: [32]byte{0x3e, 0x3f, 0x40}, DepositCount: 1000, BlockHash: [32]byte{0x41, 0x42, 0x43}, }, Eth1DepositIndex: 100, } if version.EqualsOrIsAfter(beaconState.GetForkVersion(), version.Electra()) { beaconState.PendingPartialWithdrawals = []*types.PendingPartialWithdrawal{ { ValidatorIndex: 123, Amount: 32000000000, WithdrawableEpoch: 100, }, { ValidatorIndex: 124, Amount: 100, WithdrawableEpoch: 1, }, } } return beaconState } func generateRandomBytes32(count int) []common.Bytes32 { result := make([]common.Bytes32, count) for i := range result { var randomBytes [32]byte for j := range randomBytes { randomBytes[j] = byte((i + j) % 256) } result[i] = randomBytes } return result } func TestBeaconStateMarshalUnmarshalSSZ(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { genState := generateValidBeaconState(v) data, fastSSZMarshalErr := genState.MarshalSSZ() require.NoError(t, fastSSZMarshalErr) require.NotNil(t, data) newState := types.NewEmptyBeaconStateWithVersion(v) err := newState.UnmarshalSSZ(data) require.NoError(t, err) require.EqualValues(t, genState, newState) // Check if the state size is greater than 0 require.Positive(t, karalabessz.Size(genState)) }) } func TestHashTreeRoot(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { state := generateValidBeaconState(v) require.NotPanics(t, func() { state.HashTreeRoot() }) }) } func TestGetTree(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { state := generateValidBeaconState(v) tree, err := state.GetTree() require.NoError(t, err) require.NotNil(t, tree) }) } func TestBeaconState_UnmarshalSSZ_Error(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { state := types.NewEmptyBeaconStateWithVersion(v) err := state.UnmarshalSSZ([]byte{0x01, 0x02, 0x03}) // Invalid data require.ErrorIs(t, err, io.ErrUnexpectedEOF) }) } func TestBeaconState_HashTreeRoot(t *testing.T) { t.Parallel() runForAllSupportedVersions(t, func(t *testing.T, v common.Version) { state := generateValidBeaconState(v) // Get the HashTreeRoot root := state.HashTreeRoot() // Get the HashConcurrent concurrentRoot := common.Root(karalabessz.HashSequential(state)) // Get the HashTreeRootWith hasher := ssz.NewHasher() err := state.HashTreeRootWith(hasher) require.NoError(t, err) root2 := hasher.Hash() // Compare the results require.Equal( t, root, concurrentRoot, "HashTreeRoot and HashSequential should produce the same result", ) require.Equal(t, root[:], root2, "HashTreeRoot and HashTreeRootWith should produce the same result", ) }) } ================================================ FILE: consensus-types/types/sync_aggregate.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/ssz/schema" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure SyncAggregate implements necessary interfaces. var ( _ ssz.StaticObject = (*SyncAggregate)(nil) _ constraints.SSZMarshallableRootable = (*SyncAggregate)(nil) _ common.UnusedEnforcer = (*SyncAggregate)(nil) ) const ( syncCommitteeSize = 512 syncCommitteeBitsLength = syncCommitteeSize / 8 ) type SyncAggregate struct { SyncCommitteeBits [syncCommitteeBitsLength]byte SyncCommitteeSignature crypto.BLSSignature } // SizeSSZ returns the SSZ encoded size in bytes for the SyncAggregate. func (s *SyncAggregate) SizeSSZ(_ *ssz.Sizer) uint32 { return syncCommitteeBitsLength + schema.B96Size } // DefineSSZ defines the SSZ encoding for the SyncAggregate object. func (s *SyncAggregate) DefineSSZ(c *ssz.Codec) { ssz.DefineStaticBytes(c, &s.SyncCommitteeBits) ssz.DefineStaticBytes(c, &s.SyncCommitteeSignature) } // MarshalSSZ marshals the SyncAggregate object to SSZ format. func (s *SyncAggregate) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(s)) return buf, ssz.EncodeToBytes(buf, s) } func (*SyncAggregate) ValidateAfterDecodingSSZ() error { return nil } // HashTreeRoot returns the hash tree root of the Deposits. func (s *SyncAggregate) HashTreeRoot() common.Root { htr := ssz.HashSequential(s) return htr } // EnforceUnused return true if the SyncAggregate contains all zero values. // As long as this type remains unused and unvalidated by consensus, // we must enforce that it contains no data. func (s *SyncAggregate) EnforceUnused() error { if (s != nil && *s != SyncAggregate{}) { return errors.New("SyncAggregate must be unused") } return nil } ================================================ FILE: consensus-types/types/validator.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" ) // ValidatorSize is the size of the Validator struct in bytes. const ValidatorSize = 121 // Compile-time checks for the Validator struct. var ( _ ssz.StaticObject = (*Validator)(nil) _ constraints.SSZMarshallableRootable = (*Validator)(nil) ) // Validator as defined in the Ethereum 2.0 Spec // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#validator type Validator struct { // Pubkey is the validator's 48-byte BLS public key. Pubkey crypto.BLSPubkey `json:"pubkey"` // WithdrawalCredentials are an address that controls the validator. WithdrawalCredentials WithdrawalCredentials `json:"withdrawalCredentials"` // EffectiveBalance is the validator's current effective balance in gwei. EffectiveBalance math.Gwei `json:"effectiveBalance"` // Slashed indicates whether the validator has been slashed. Slashed bool `json:"slashed"` // ActivationEligibilityEpoch is the epoch in which the validator became // eligible for activation. ActivationEligibilityEpoch math.Epoch `json:"activationEligibilityEpoch"` // ActivationEpoch is the epoch in which the validator activated. ActivationEpoch math.Epoch `json:"activationEpoch"` // ExitEpoch is the epoch in which the validator exited. ExitEpoch math.Epoch `json:"exitEpoch"` // WithdrawableEpoch is the epoch in which the validator can withdraw. WithdrawableEpoch math.Epoch `json:"withdrawableEpoch"` } /* -------------------------------------------------------------------------- */ /* Constructor */ /* -------------------------------------------------------------------------- */ // NewValidatorFromDeposit creates a new Validator from the // given public key, withdrawal credentials, and amount. // // As defined in the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#deposits func NewValidatorFromDeposit( pubkey crypto.BLSPubkey, withdrawalCredentials WithdrawalCredentials, amount math.Gwei, effectiveBalanceIncrement math.Gwei, maxEffectiveBalance math.Gwei, ) *Validator { return &Validator{ Pubkey: pubkey, WithdrawalCredentials: withdrawalCredentials, EffectiveBalance: ComputeEffectiveBalance( amount, effectiveBalanceIncrement, maxEffectiveBalance, ), Slashed: false, ActivationEligibilityEpoch: constants.FarFutureEpoch, ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, } } func NewEmptyValidator() *Validator { return &Validator{} } func ComputeEffectiveBalance( amount, effectiveBalanceIncrement, maxEffectiveBalance math.Gwei, ) math.Gwei { return min(amount-amount%effectiveBalanceIncrement, maxEffectiveBalance) } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the Validator object in SSZ encoding. func (*Validator) SizeSSZ(*ssz.Sizer) uint32 { return ValidatorSize } // DefineSSZ defines the SSZ encoding for the Validator object. func (v *Validator) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticBytes(codec, &v.Pubkey) ssz.DefineStaticBytes(codec, &v.WithdrawalCredentials) ssz.DefineUint64(codec, &v.EffectiveBalance) ssz.DefineBool(codec, &v.Slashed) ssz.DefineUint64(codec, &v.ActivationEligibilityEpoch) ssz.DefineUint64(codec, &v.ActivationEpoch) ssz.DefineUint64(codec, &v.ExitEpoch) ssz.DefineUint64(codec, &v.WithdrawableEpoch) } // HashTreeRoot computes the SSZ hash tree root of the Validator object. func (v *Validator) HashTreeRoot() common.Root { return ssz.HashSequential(v) } // MarshalSSZ marshals the Validator object to SSZ format. func (v *Validator) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(v)) return buf, ssz.EncodeToBytes(buf, v) } func (*Validator) ValidateAfterDecodingSSZ() error { return nil } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo marshals the Validator object to SSZ format into the provided // buffer. func (v *Validator) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := v.MarshalSSZ() if err != nil { return nil, err } dst = append(dst, bz...) return dst, nil } // HashTreeRootWith ssz hashes the Validator object with a hasher. func (v *Validator) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'Pubkey' hh.PutBytes(v.Pubkey[:]) // Field (1) 'WithdrawalCredentials' hh.PutBytes(v.WithdrawalCredentials[:]) // Field (2) 'EffectiveBalance' hh.PutUint64(uint64(v.EffectiveBalance)) // Field (3) 'Slashed' hh.PutBool(v.Slashed) // Field (4) 'ActivationEligibilityEpoch' hh.PutUint64(uint64(v.ActivationEligibilityEpoch)) // Field (5) 'ActivationEpoch' hh.PutUint64(uint64(v.ActivationEpoch)) // Field (6) 'ExitEpoch' hh.PutUint64(uint64(v.ExitEpoch)) // Field (7) 'WithdrawableEpoch' hh.PutUint64(uint64(v.WithdrawableEpoch)) hh.Merkleize(indx) return nil } // GetTree ssz hashes the Validator object. func (v *Validator) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(v) } /* -------------------------------------------------------------------------- */ /* Getters and Setters */ /* -------------------------------------------------------------------------- */ // GetPubkey returns the public key of the validator. func (v *Validator) GetPubkey() crypto.BLSPubkey { return v.Pubkey } // GetEffectiveBalance returns the effective balance of the validator. func (v *Validator) GetEffectiveBalance() math.Gwei { return v.EffectiveBalance } // IsActive as defined in the Ethereum 2.0 Spec // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_active_validator func (v Validator) IsActive(epoch math.Epoch) bool { return v.ActivationEpoch <= epoch && epoch < v.ExitEpoch } // IsEligibleForActivation as defined in the Ethereum 2.0 Spec // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_eligible_for_activation_queue func (v Validator) IsEligibleForActivation(finalizedEpoch math.Epoch) bool { return v.ActivationEligibilityEpoch <= finalizedEpoch && v.ActivationEpoch == constants.FarFutureEpoch } // IsEligibleForActivationQueue is defined slightly differently from Ethereum 2.0 Spec // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_eligible_for_activation_queue func (v Validator) IsEligibleForActivationQueue(threshold math.Gwei) bool { return v.ActivationEligibilityEpoch == constants.FarFutureEpoch && v.EffectiveBalance >= threshold } // IsSlashable as defined in the Ethereum 2.0 Spec // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_slashable_validator func (v Validator) IsSlashable(epoch math.Epoch) bool { return !v.Slashed && v.ActivationEpoch <= epoch && epoch < v.WithdrawableEpoch } // IsSlashed returns whether the validator has been slashed. func (v Validator) IsSlashed() bool { return v.Slashed } // IsFullyWithdrawable as defined in the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#is_fully_withdrawable_validator func (v Validator) IsFullyWithdrawable( balance math.Gwei, epoch math.Epoch, ) bool { return v.HasEth1WithdrawalCredentials() && v.WithdrawableEpoch <= epoch && balance > 0 } // IsPartiallyWithdrawable as defined in the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#is_partially_withdrawable_validator func (v Validator) IsPartiallyWithdrawable( balance, maxEffectiveBalance math.Gwei, ) bool { hasExcessBalance := balance > maxEffectiveBalance return v.HasEth1WithdrawalCredentials() && v.HasMaxEffectiveBalance(maxEffectiveBalance) && hasExcessBalance } // HasEth1WithdrawalCredentials as defined in the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/validator.md#eth1_address_withdrawal_prefix func (v Validator) HasEth1WithdrawalCredentials() bool { return v.WithdrawalCredentials.IsValidEth1WithdrawalCredentials() } // HasExecutionWithdrawalCredential deviated from `has_execution_withdrawal_credential` by not checking for // compounding withdrawal credentials, i.e 0x02. func (v Validator) HasExecutionWithdrawalCredential() bool { return v.HasEth1WithdrawalCredentials() } // HasMaxEffectiveBalance determines if the validator has the maximum effective // balance. func (v Validator) HasMaxEffectiveBalance( maxEffectiveBalance math.Gwei, ) bool { return v.EffectiveBalance == maxEffectiveBalance } // SetEffectiveBalance sets the effective balance of the validator. func (v *Validator) SetEffectiveBalance(balance math.Gwei) { v.EffectiveBalance = balance } func (v *Validator) SetActivationEligibilityEpoch(e math.Epoch) { v.ActivationEligibilityEpoch = e } func (v *Validator) GetActivationEligibilityEpoch() math.Epoch { return v.ActivationEligibilityEpoch } func (v *Validator) SetActivationEpoch(e math.Epoch) { v.ActivationEpoch = e } func (v *Validator) GetActivationEpoch() math.Epoch { return v.ActivationEpoch } func (v *Validator) SetExitEpoch(e math.Epoch) { v.ExitEpoch = e } func (v Validator) GetExitEpoch() math.Epoch { return v.ExitEpoch } func (v *Validator) SetWithdrawableEpoch(e math.Epoch) { v.WithdrawableEpoch = e } func (v Validator) GetWithdrawableEpoch() math.Epoch { return v.WithdrawableEpoch } // GetWithdrawalCredentials returns the withdrawal credentials of the validator. func (v Validator) GetWithdrawalCredentials() WithdrawalCredentials { return v.WithdrawalCredentials } // HasCompoundingWithdrawalCredential is equivalent to has_compounding_withdrawal_credential. // On Berachain, all validators are considered to be 'compounding' validators, regardless of whether // they have the '0x2' prefix. We introduce this for spec parity. func (v Validator) HasCompoundingWithdrawalCredential() bool { return true } // Status returns the current validator status based on its set epoch values. // This function taken from Prysm: // https://github.com/prysmaticlabs/prysm/blob/0229a2055e6349655a471b2427f349e40c275cee/beacon-chain/rpc/eth/helpers/validator_status.go#L31 func (v *Validator) Status(currentEpoch math.Epoch) (string, error) { activationEpoch := v.GetActivationEpoch() activationEligibilityEpoch := v.GetActivationEligibilityEpoch() farFutureEpoch := constants.FarFutureEpoch exitEpoch := v.GetExitEpoch() withdrawableEpoch := v.GetWithdrawableEpoch() // Status: pending if activationEpoch > currentEpoch { if activationEligibilityEpoch == farFutureEpoch { return constants.ValidatorStatusPendingInitialized, nil } else if activationEligibilityEpoch < farFutureEpoch { return constants.ValidatorStatusPendingQueued, nil } } // Status: active if activationEpoch <= currentEpoch && currentEpoch < exitEpoch { if exitEpoch == farFutureEpoch { return constants.ValidatorStatusActiveOngoing, nil } else if exitEpoch < farFutureEpoch { if v.IsSlashed() { return constants.ValidatorStatusActiveSlashed, nil } return constants.ValidatorStatusActiveExiting, nil } } // Status: exited if exitEpoch <= currentEpoch && currentEpoch < withdrawableEpoch { if v.IsSlashed() { return constants.ValidatorStatusExitedSlashed, nil } return constants.ValidatorStatusExitedUnslashed, nil } // Status: withdrawal if withdrawableEpoch <= currentEpoch { if v.GetEffectiveBalance() != math.Gwei(0) { return constants.ValidatorStatusWithdrawalPossible, nil } return constants.ValidatorStatusWithdrawalDone, nil } return "", ErrInvalidValidatorStatus } ================================================ FILE: consensus-types/types/validator_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "io" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/stretchr/testify/require" ) func TestNewValidatorFromDeposit(t *testing.T) { t.Parallel() tests := []struct { name string pubkey crypto.BLSPubkey withdrawalCredentials types.WithdrawalCredentials amount math.Gwei effectiveBalanceIncrement math.Gwei maxEffectiveBalance math.Gwei want *types.Validator }{ { name: "normal case", pubkey: [48]byte{0x01}, withdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), amount: 32e9, effectiveBalanceIncrement: 1e9, maxEffectiveBalance: 32e9, want: &types.Validator{ Pubkey: [48]byte{0x01}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), EffectiveBalance: 32e9, Slashed: false, ActivationEligibilityEpoch: constants.FarFutureEpoch, ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, }, { name: "effective balance capped at max", pubkey: [48]byte{0x02}, withdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x02}, ), amount: 40e9, effectiveBalanceIncrement: 1e9, maxEffectiveBalance: 32e9, want: &types.Validator{ Pubkey: [48]byte{0x02}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x02}, ), EffectiveBalance: 32e9, Slashed: false, ActivationEligibilityEpoch: constants.FarFutureEpoch, ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, }, { name: "effective balance rounded down", pubkey: [48]byte{0x03}, withdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x03}, ), amount: 32.5e9, effectiveBalanceIncrement: 1e9, maxEffectiveBalance: 32e9, want: &types.Validator{ Pubkey: [48]byte{0x03}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x03}, ), EffectiveBalance: 32e9, Slashed: false, ActivationEligibilityEpoch: constants.FarFutureEpoch, ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := types.NewValidatorFromDeposit( tt.pubkey, tt.withdrawalCredentials, tt.amount, tt.effectiveBalanceIncrement, tt.maxEffectiveBalance, ) require.Equal(t, tt.want, got) }) } } func TestValidator_IsActive(t *testing.T) { t.Parallel() tests := []struct { name string epoch math.Epoch validator *types.Validator want bool }{ { name: "active", epoch: 10, validator: &types.Validator{ ActivationEpoch: 5, ExitEpoch: 15, }, want: true, }, { name: "not active, before activation", epoch: 4, validator: &types.Validator{ ActivationEpoch: 5, ExitEpoch: 15, }, want: false, }, { name: "not active, after exit", epoch: 16, validator: &types.Validator{ ActivationEpoch: 5, ExitEpoch: 15, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal(t, tt.want, tt.validator.IsActive(tt.epoch)) }) } } func TestValidator_IsEligibleForActivation(t *testing.T) { t.Parallel() tests := []struct { name string finalizedEpoch math.Epoch validator *types.Validator want bool }{ { name: "eligible", finalizedEpoch: 10, validator: &types.Validator{ ActivationEligibilityEpoch: 5, ActivationEpoch: constants.FarFutureEpoch, }, want: true, }, { name: "not eligible, activation eligibility in future", finalizedEpoch: 4, validator: &types.Validator{ ActivationEligibilityEpoch: 5, ActivationEpoch: constants.FarFutureEpoch, }, want: false, }, { name: "not eligible, already activated", finalizedEpoch: 10, validator: &types.Validator{ ActivationEligibilityEpoch: 5, ActivationEpoch: 8, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal( t, tt.want, tt.validator.IsEligibleForActivation(tt.finalizedEpoch), ) }) } } func TestValidator_IsEligibleForActivationQueue(t *testing.T) { t.Parallel() maxEffectiveBalance := math.Gwei(32e9) tests := []struct { name string validator *types.Validator want bool }{ { name: "eligible", validator: &types.Validator{ ActivationEligibilityEpoch: constants.FarFutureEpoch, EffectiveBalance: maxEffectiveBalance, }, want: true, }, { name: "not eligible, activation eligibility set", validator: &types.Validator{ ActivationEligibilityEpoch: 5, EffectiveBalance: maxEffectiveBalance, }, want: false, }, { name: "not eligible, effective balance too low", validator: &types.Validator{ ActivationEligibilityEpoch: constants.FarFutureEpoch, EffectiveBalance: maxEffectiveBalance - 1, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal( t, tt.want, tt.validator.IsEligibleForActivationQueue(maxEffectiveBalance), ) }) } } func TestValidator_IsSlashable(t *testing.T) { t.Parallel() tests := []struct { name string epoch math.Epoch validator *types.Validator want bool }{ { name: "slashable", epoch: 10, validator: &types.Validator{ Slashed: false, ActivationEpoch: 5, WithdrawableEpoch: 15, }, want: true, }, { name: "not slashable, already slashed", epoch: 10, validator: &types.Validator{ Slashed: true, ActivationEpoch: 5, WithdrawableEpoch: 15, }, want: false, }, { name: "not slashable, before activation", epoch: 4, validator: &types.Validator{ Slashed: false, ActivationEpoch: 5, WithdrawableEpoch: 15, }, want: false, }, { name: "not slashable, after withdrawable", epoch: 16, validator: &types.Validator{ Slashed: false, ActivationEpoch: 5, WithdrawableEpoch: 15, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal(t, tt.want, tt.validator.IsSlashable(tt.epoch)) }) } } func TestValidator_IsFullyWithdrawable(t *testing.T) { t.Parallel() tests := []struct { name string balance math.Gwei epoch math.Epoch validator *types.Validator want bool }{ { name: "fully withdrawable", balance: 32e9, epoch: 10, validator: &types.Validator{ WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), WithdrawableEpoch: 5, }, want: true, }, { name: "not fully withdrawable, non-eth1 credentials", balance: 32e9, epoch: 10, validator: &types.Validator{ WithdrawalCredentials: types. WithdrawalCredentials{0x00}, WithdrawableEpoch: 5, }, want: false, }, { name: "not fully withdrawable, before withdrawable epoch", balance: 32e9, epoch: 4, validator: &types.Validator{ WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), WithdrawableEpoch: 5, }, want: false, }, { name: "not fully withdrawable, zero balance", balance: 0, epoch: 10, validator: &types.Validator{ WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), WithdrawableEpoch: 5, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal( t, tt.want, tt.validator.IsFullyWithdrawable(tt.balance, tt.epoch), ) }) } } func TestValidator_IsPartiallyWithdrawable(t *testing.T) { t.Parallel() maxEffectiveBalance := math.Gwei(32e9) tests := []struct { name string balance math.Gwei validator *types.Validator want bool }{ { name: "partially withdrawable", balance: 33e9, validator: &types.Validator{ WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), EffectiveBalance: maxEffectiveBalance, }, want: true, }, { name: "not partially withdrawable, non-eth1 credentials", balance: 33e9, validator: &types.Validator{ WithdrawalCredentials: types.WithdrawalCredentials{ 0x00, }, EffectiveBalance: maxEffectiveBalance, }, want: false, }, { name: "not partially withdrawable, not at max effective balance", balance: 33e9, validator: &types.Validator{ WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), EffectiveBalance: maxEffectiveBalance - 1, }, want: false, }, { name: "not partially withdrawable, no excess balance", balance: 32e9, validator: &types.Validator{ WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), EffectiveBalance: maxEffectiveBalance, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal( t, tt.want, tt.validator.IsPartiallyWithdrawable( tt.balance, maxEffectiveBalance, ), ) }) } } func TestValidator_HasEth1WithdrawalCredentials(t *testing.T) { t.Parallel() tests := []struct { name string validator *types.Validator want bool }{ { name: "has eth1 credentials", validator: &types.Validator{ WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), }, want: true, }, { name: "does not have eth1 credentials", validator: &types.Validator{ WithdrawalCredentials: types.WithdrawalCredentials{ 0x00, }, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal( t, tt.want, tt.validator.HasEth1WithdrawalCredentials(), ) }) } } func TestValidator_HasMaxEffectiveBalance(t *testing.T) { t.Parallel() maxEffectiveBalance := math.Gwei(32e9) tests := []struct { name string validator *types.Validator want bool }{ { name: "has max effective balance", validator: &types.Validator{ EffectiveBalance: maxEffectiveBalance, }, want: true, }, { name: "does not have max effective balance", validator: &types.Validator{ EffectiveBalance: maxEffectiveBalance - 1, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal( t, tt.want, tt.validator.HasMaxEffectiveBalance(maxEffectiveBalance), ) }) } } func TestValidator_MarshalUnmarshalSSZ(t *testing.T) { t.Parallel() tests := []struct { name string validator *types.Validator invalidSSZ bool }{ { name: "normal case", validator: &types.Validator{ Pubkey: [48]byte{0x01}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), EffectiveBalance: 32e9, Slashed: false, ActivationEligibilityEpoch: constants.FarFutureEpoch, ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, invalidSSZ: false, }, { name: "slashed validator", validator: &types.Validator{ Pubkey: [48]byte{0x02}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x02}, ), EffectiveBalance: 32e9, Slashed: true, ActivationEligibilityEpoch: 5, ActivationEpoch: 6, ExitEpoch: 10, WithdrawableEpoch: 15, }, invalidSSZ: false, }, { name: "validator with zero balance", validator: &types.Validator{ Pubkey: [48]byte{0x03}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x03}, ), EffectiveBalance: 0, Slashed: false, ActivationEligibilityEpoch: constants.FarFutureEpoch, ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, invalidSSZ: false, }, { name: "validator with non-default epochs", validator: &types.Validator{ Pubkey: [48]byte{0x04}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x04}, ), EffectiveBalance: 16e9, Slashed: false, ActivationEligibilityEpoch: 10, ActivationEpoch: 12, ExitEpoch: 20, WithdrawableEpoch: 25, }, invalidSSZ: false, }, { name: "invalid SSZ size", validator: &types.Validator{}, invalidSSZ: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() if tt.invalidSSZ { // Create a byte slice with an invalid size (not 121) invalidSizeData := make([]byte, 120) unmarshalled := new(types.Validator) err := ssz.Unmarshal(invalidSizeData, unmarshalled) require.ErrorIs(t, err, io.ErrUnexpectedEOF, "Test case: %s", tt.name) } else { // Marshal the validator marshaled, err := tt.validator.MarshalSSZ() require.NoError(t, err) // Unmarshal into a new validator unmarshalled := new(types.Validator) err = ssz.Unmarshal(marshaled, unmarshalled) require.NoError(t, err) // Check if the original and unmarshaled validators are equal require.Equal( t, tt.validator, unmarshalled, "Test case: %s", tt.name, ) var buf []byte buf, err = tt.validator.MarshalSSZTo(buf) require.NoError(t, err) // The two byte slices should be equal require.Equal(t, marshaled, buf) } }) } } func TestValidator_HashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string validator *types.Validator }{ { name: "normal case", validator: &types.Validator{ Pubkey: [48]byte{0x01}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), EffectiveBalance: 32e9, Slashed: false, ActivationEligibilityEpoch: constants.FarFutureEpoch, ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, }, { name: "slashed validator", validator: &types.Validator{ Pubkey: [48]byte{0x02}, WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x02}, ), EffectiveBalance: 32e9, Slashed: true, ActivationEligibilityEpoch: 5, ActivationEpoch: 6, ExitEpoch: 10, WithdrawableEpoch: 15, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() // Test HashTreeRoot root := tt.validator.HashTreeRoot() require.NotEqual(t, [32]byte{}, root) // Test HashTreeRootWith hh := fastssz.NewHasher() err := tt.validator.HashTreeRootWith(hh) require.NoError(t, err) // Test GetTree tree, err := tt.validator.GetTree() require.NoError(t, err) require.NotNil(t, tree) }) } } func TestValidator_SetEffectiveBalance(t *testing.T) { t.Parallel() tests := []struct { name string balance math.Gwei validator *types.Validator want math.Gwei }{ { name: "set effective balance", balance: 32e9, validator: &types.Validator{ EffectiveBalance: 0, }, want: 32e9, }, { name: "update effective balance", balance: 16e9, validator: &types.Validator{ EffectiveBalance: 32e9, }, want: 16e9, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() tt.validator.SetEffectiveBalance(tt.balance) require.Equal(t, tt.want, tt.validator.EffectiveBalance, "Test case: %s", tt.name) }) } } func TestValidator_GetWithdrawableEpoch(t *testing.T) { t.Parallel() tests := []struct { name string validator *types.Validator want math.Epoch }{ { name: "get withdrawable epoch", validator: &types.Validator{ WithdrawableEpoch: 10, }, want: 10, }, { name: "get far future withdrawable epoch", validator: &types.Validator{ WithdrawableEpoch: constants.FarFutureEpoch, }, want: constants.FarFutureEpoch, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.validator.GetWithdrawableEpoch() require.Equal(t, tt.want, got, "Test case: %s", tt.name) }) } } func TestValidator_GetWithdrawalCredentials(t *testing.T) { t.Parallel() tests := []struct { name string validator *types.Validator want types.WithdrawalCredentials }{ { name: "get withdrawal credentials", validator: &types.Validator{ WithdrawalCredentials: types. NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), }, want: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), }, { name: "get empty withdrawal credentials", validator: &types.Validator{ WithdrawalCredentials: types.WithdrawalCredentials{0x00}, }, want: types.WithdrawalCredentials{0x00}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.validator.GetWithdrawalCredentials() require.Equal(t, tt.want, got, "Test case: %s", tt.name) }) } } func TestValidator_IsSlashed(t *testing.T) { t.Parallel() tests := []struct { name string validator *types.Validator want bool }{ { name: "validator is slashed", validator: &types.Validator{ Slashed: true, }, want: true, }, { name: "validator is not slashed", validator: &types.Validator{ Slashed: false, }, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.validator.IsSlashed() require.Equal(t, tt.want, got, "Test case: %s", tt.name) }) } } func TestValidator_GetPubkey(t *testing.T) { t.Parallel() tests := []struct { name string validator *types.Validator want crypto.BLSPubkey }{ { name: "get pubkey", validator: &types.Validator{ Pubkey: [48]byte{0x01}, }, want: [48]byte{0x01}, }, { name: "get pubkey with multiple bytes", validator: &types.Validator{ Pubkey: [48]byte{0x01, 0x02, 0x03}, }, want: [48]byte{0x01, 0x02, 0x03}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.validator.GetPubkey() require.Equal(t, tt.want, got, "Test case: %s", tt.name) }) } } func TestValidator_GetEffectiveBalance(t *testing.T) { t.Parallel() tests := []struct { name string validator *types.Validator want math.Gwei }{ { name: "get effective balance", validator: &types.Validator{ EffectiveBalance: 32e9, }, want: 32e9, }, { name: "get zero effective balance", validator: &types.Validator{ EffectiveBalance: 0, }, want: 0, }, { name: "get maximum effective balance", validator: &types.Validator{ EffectiveBalance: math.Gwei(1<<64 - 1), }, want: math.Gwei(1<<64 - 1), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.validator.GetEffectiveBalance() require.Equal(t, tt.want, got, "Test case: %s", tt.name) }) } } ================================================ FILE: consensus-types/types/validators.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // False positive detected. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/karalabe/ssz" ) // Validators is a type alias for a SSZ list of Validator containers. type Validators []*Validator // SizeSSZ returns the SSZ encoded size in bytes for the Validators. func (vs Validators) SizeSSZ(siz *ssz.Sizer, _ bool) uint32 { return ssz.SizeSliceOfStaticObjects(siz, ([]*Validator)(vs)) } // DefineSSZ defines the SSZ encoding for the Validators object. // TODO: get from accessible chainspec field params. func (vs Validators) DefineSSZ(c *ssz.Codec) { c.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfStaticObjectsContent( c, (*[]*Validator)(&vs), constants.ValidatorsRegistryLimit) }) c.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfStaticObjectsContent( c, (*[]*Validator)(&vs), constants.ValidatorsRegistryLimit) }) c.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfStaticObjectsOffset( c, (*[]*Validator)(&vs), constants.ValidatorsRegistryLimit) }) } // HashTreeRoot returns the SSZ hash tree root for the Validators object. func (vs Validators) HashTreeRoot() common.Root { return ssz.HashSequential(vs) } ================================================ FILE: consensus-types/types/versionable.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" ) // versionable is a helper struct that implements the Versionable interface. type versionable struct { forkVersion common.Version } // NewVersionable creates a new versionable object. func NewVersionable(forkVersion common.Version) constraints.Versionable { return &versionable{forkVersion: forkVersion} } // GetForkVersion returns the fork version of the versionable object. func (v *versionable) GetForkVersion() common.Version { return v.forkVersion } ================================================ FILE: consensus-types/types/voluntary_exits.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // separate file for ease of future implementation package types import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure VoluntaryExit implements necessary interfaces. var ( _ ssz.StaticObject = (*VoluntaryExit)(nil) _ constraints.SSZMarshallableRootable = (*VoluntaryExit)(nil) _ common.UnusedEnforcer = (*VoluntaryExits)(nil) ) type ( VoluntaryExit = common.UnusedType VoluntaryExits []*VoluntaryExit ) // SizeSSZ returns the SSZ encoded size in bytes for the VoluntaryExits. func (vs VoluntaryExits) SizeSSZ(siz *ssz.Sizer, _ bool) uint32 { return ssz.SizeSliceOfStaticObjects(siz, vs) } // DefineSSZ defines the SSZ encoding for the VoluntaryExits object. func (vs VoluntaryExits) DefineSSZ(c *ssz.Codec) { c.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*VoluntaryExit)(&vs), constants.MaxVoluntaryExits) }) c.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfStaticObjectsContent(c, (*[]*VoluntaryExit)(&vs), constants.MaxVoluntaryExits) }) c.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfStaticObjectsOffset(c, (*[]*VoluntaryExit)(&vs), constants.MaxVoluntaryExits) }) } // HashTreeRoot returns the hash tree root of the VoluntaryExits. func (vs VoluntaryExits) HashTreeRoot() common.Root { return ssz.HashSequential(vs) } // EnforceUnused return true if the length of the VoluntaryExits is 0. // As long as this type remains unimplemented and unvalidated by consensus, // we must enforce that it contains no data. func (vs VoluntaryExits) EnforceUnused() error { if len(vs) != 0 { return errors.New("VoluntaryExits must be unused") } return nil } ================================================ FILE: consensus-types/types/withdrawal_credentials.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "bytes" "github.com/berachain/beacon-kit/primitives/common" ) const ( // EthSecp256k1CredentialPrefix is the prefix for an Ethereum secp256k1. EthSecp256k1CredentialPrefix = byte(1) // numZeroBytesInEth1WithdrawalCredentials is the number of zero bytes in a valid eth1 // withdrawal credentials. numZeroBytesInEth1WithdrawalCredentials = 11 ) // WithdrawalCredentials is a staking credential that is used to identify a validator. type WithdrawalCredentials common.Bytes32 // NewCredentialsFromExecutionAddress creates a new valid Eth1 WithdrawalCredentials // from an execution address. func NewCredentialsFromExecutionAddress(address common.ExecutionAddress) WithdrawalCredentials { credentials := WithdrawalCredentials{} credentials[0] = EthSecp256k1CredentialPrefix copy(credentials[12:], address[:]) return credentials } // IsValidEth1WithdrawalCredentials checks if the withdrawal credentials are valid // eth1 withdrawal credentials as defined in the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/validator.md#eth1_address_withdrawal_prefix func (wc WithdrawalCredentials) IsValidEth1WithdrawalCredentials() bool { zeroBytes := make([]byte, numZeroBytesInEth1WithdrawalCredentials) return wc[0] == EthSecp256k1CredentialPrefix && bytes.Equal(wc[1:12], zeroBytes) } // ToExecutionAddress converts the WithdrawalCredentials to an ExecutionAddress. // Returns error if the withdrawal credentials are not valid. func (wc WithdrawalCredentials) ToExecutionAddress() (common.ExecutionAddress, error) { if !wc.IsValidEth1WithdrawalCredentials() { return common.ExecutionAddress{}, ErrInvalidWithdrawalCredentials } return common.ExecutionAddress(wc[12:]), nil } // UnmarshalJSON implements the json.Unmarshaler interface for Bytes32. // TODO: Figure out how to not have to do this. func (wc *WithdrawalCredentials) UnmarshalJSON(input []byte) error { return (*common.Bytes32)(wc).UnmarshalJSON(input) } // String returns the hex string representation of Bytes32. // TODO: Figure out how to not have to do this. func (wc WithdrawalCredentials) String() string { return common.Bytes32(wc).String() } // MarshalText implements the encoding.TextMarshaler interface for Bytes32. // TODO: Figure out how to not have to do this. func (wc WithdrawalCredentials) MarshalText() ([]byte, error) { return common.Bytes32(wc).MarshalText() } // UnmarshalText implements the encoding.TextUnmarshaler interface for Bytes32. // TODO: Figure out how to not have to do this. func (wc *WithdrawalCredentials) UnmarshalText(text []byte) error { return (*common.Bytes32)(wc).UnmarshalText(text) } ================================================ FILE: consensus-types/types/withdrawal_credentials_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "testing" types "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/stretchr/testify/require" ) func TestNewCredentialsFromExecutionAddress(t *testing.T) { t.Parallel() address := common.ExecutionAddress{0xde, 0xad, 0xbe, 0xef} expectedCredentials := types.WithdrawalCredentials{} expectedCredentials[0] = 0x01 // EthSecp256k1CredentialPrefix copy(expectedCredentials[12:], address[:]) for i := 1; i < 12; i++ { expectedCredentials[i] = 0x00 } require.Len( t, expectedCredentials, 32, "Expected credentials to be 32 bytes long", ) require.Equal( t, byte(0x01), expectedCredentials[0], "Expected prefix to be 0x01", ) require.Equal( t, address, common.ExecutionAddress(expectedCredentials[12:]), "Expected address to be set correctly", ) credentials := types. NewCredentialsFromExecutionAddress(address) require.Equal( t, expectedCredentials, credentials, "Generated credentials do not match expected", ) } func TestIsValidEth1WithdrawalCredentials(t *testing.T) { t.Parallel() tests := []struct { name string wc types.WithdrawalCredentials expected bool }{ { name: "valid eth1 withdrawal credentials", wc: func() types.WithdrawalCredentials { wc := types.WithdrawalCredentials{} wc[0] = types.EthSecp256k1CredentialPrefix // bytes 1-11 should be zero for i := 1; i < 12; i++ { wc[i] = 0x00 } // rest can be any value addr := common.ExecutionAddress{0xde, 0xad, 0xbe, 0xef} copy(wc[12:], addr[:]) return wc }(), expected: true, }, { name: "invalid prefix", wc: func() types.WithdrawalCredentials { wc := types.WithdrawalCredentials{} wc[0] = 0x02 // wrong prefix return wc }(), expected: false, }, { name: "non-zero padding bytes", wc: func() types.WithdrawalCredentials { wc := types.WithdrawalCredentials{} wc[0] = types.EthSecp256k1CredentialPrefix wc[5] = 0x01 // non-zero byte in padding area return wc }(), expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.wc.IsValidEth1WithdrawalCredentials() require.Equal(t, tt.expected, result, "Test case %s", tt.name) }) } } func TestToExecutionAddress(t *testing.T) { t.Parallel() expectedAddress := common.ExecutionAddress{0xde, 0xad, 0xbe, 0xef} credentials := types.WithdrawalCredentials{} for i := range credentials { // First byte should be 0x01 switch { case i == 0: credentials[i] = 0x01 // EthSecp256k1CredentialPrefix case i > 0 && i < 12: credentials[i] = 0x00 // then we have 11 bytes of padding default: credentials[i] = expectedAddress[i-12] // then the address } } address, err := credentials.ToExecutionAddress() require.NoError(t, err, "Conversion to execution address should not error") require.Equal( t, expectedAddress, address, "Converted address does not match expected", ) } func TestToExecutionAddress_InvalidPrefix(t *testing.T) { t.Parallel() credentials := types.WithdrawalCredentials{} for i := range credentials { credentials[i] = 0x00 // Invalid prefix } _, err := credentials.ToExecutionAddress() require.Error(t, err, "Expected an error due to invalid prefix") } func TestWithdrawalCredentials_UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input string expected types.WithdrawalCredentials wantErr bool }{ { name: "valid JSON", input: `"0x0100000000000000000000000000000` + `000000000000000000000000000000000"`, expected: types.WithdrawalCredentials{0x01}, wantErr: false, }, { name: "invalid JSON", input: `"invalid"`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var wc types.WithdrawalCredentials err := wc.UnmarshalJSON([]byte(tt.input)) if tt.wantErr { require.Error(t, err, "Test case %s", tt.name) } else { require.NoError(t, err, "Test case %s", tt.name) require.Equal(t, tt.expected, wc, "Test case %s", tt.name) } }) } } func TestWithdrawalCredentials_String(t *testing.T) { t.Parallel() tests := []struct { name string wc types.WithdrawalCredentials expected string }{ { name: "valid string", wc: types.WithdrawalCredentials{0x01}, expected: "0x010000000000000000000000000000" + "0000000000000000000000000000000000", }, { name: "valid string with full address", wc: types.WithdrawalCredentials{0x01, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, expected: "0x01deadbeef00000000000000000000000" + "0000000000000000000000000000000", }, { name: "empty credentials", wc: types.WithdrawalCredentials{}, expected: "0x0000000000000000000000000000000000" + "000000000000000000000000000000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal(t, tt.expected, tt.wc.String(), "Test case %s", tt.name) }) } } func TestWithdrawalCredentials_MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string wc types.WithdrawalCredentials expected []byte wantErr bool }{ { name: "valid marshal", wc: types.WithdrawalCredentials{0x01}, expected: []byte("0x010000000000000000000000000000000000" + "0000000000000000000000000000"), wantErr: false, }, { name: "valid marshal with different prefix", wc: types.WithdrawalCredentials{0x02}, expected: []byte("0x020000000000000000000000000000000000" + "0000000000000000000000000000"), wantErr: false, }, { name: "valid marshal with full address", wc: types.WithdrawalCredentials{0x01, 0xde, 0xad, 0xbe, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, expected: []byte("0x01deadbeef00000000000000000000000000000" + "0000000000000000000000000"), wantErr: false, }, { name: "empty credentials", wc: types.WithdrawalCredentials{}, expected: []byte("0x0000000000000000000000000000000000000000" + "000000000000000000000000"), wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := tt.wc.MarshalText() if tt.wantErr { require.Error(t, err, "Test case %s", tt.name) } else { require.NoError(t, err, "Test case %s", tt.name) require.Equal(t, tt.expected, result, "Test case %s", tt.name) } }) } } func TestWithdrawalCredentials_UnmarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expected types.WithdrawalCredentials wantErr bool }{ { name: "valid unmarshal", input: []byte("0x010000000000000000000000000000000" + "0000000000000000000000000000000"), expected: types.WithdrawalCredentials{0x01}, wantErr: false, }, { name: "invalid unmarshal", input: []byte("invalid"), wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var wc types.WithdrawalCredentials err := wc.UnmarshalText(tt.input) if tt.wantErr { require.Error(t, err, "Test case %s", tt.name) } else { require.NoError(t, err, "Test case %s", tt.name) require.Equal(t, tt.expected, wc, "Test case %s", tt.name) } }) } } ================================================ FILE: consensus-types/types/withdrawal_request.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" sszutil "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/karalabe/ssz" ) const sszWithdrawRequestSize = 76 // ExecutionAddress = 20, ValidatorPubKey = 48, Amount = 8 // Compile-time check to ensure WithdrawalRequest implements the necessary interfaces. var ( _ ssz.StaticObject = (*WithdrawalRequest)(nil) _ constraints.SSZMarshallable = (*WithdrawalRequest)(nil) ) // WithdrawalRequest is introduced in EIP7002 which we use for withdrawals. type WithdrawalRequest struct { SourceAddress common.ExecutionAddress ValidatorPubKey crypto.BLSPubkey Amount math.Gwei } /* -------------------------------------------------------------------------- */ /* Withdrawal Request SSZ */ /* -------------------------------------------------------------------------- */ func (w *WithdrawalRequest) ValidateAfterDecodingSSZ() error { return nil } func (w *WithdrawalRequest) DefineSSZ(codec *ssz.Codec) { ssz.DefineStaticBytes(codec, &w.SourceAddress) ssz.DefineStaticBytes(codec, &w.ValidatorPubKey) ssz.DefineUint64(codec, &w.Amount) } func (w *WithdrawalRequest) SizeSSZ(_ *ssz.Sizer) uint32 { return sszWithdrawRequestSize } func (w *WithdrawalRequest) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(w)) return buf, ssz.EncodeToBytes(buf, w) } // HashTreeRoot returns the hash tree root of the Deposits. func (w *WithdrawalRequest) HashTreeRoot() common.Root { return ssz.HashSequential(w) } /* -------------------------------------------------------------------------- */ /* Withdrawal Requests SSZ */ /* -------------------------------------------------------------------------- */ // Compile-time check to ensure WithdrawalRequests implements the necessary interfaces. var _ constraints.SSZMarshaler = (*WithdrawalRequests)(nil) // WithdrawalRequests is used for SSZ unmarshalling a list of WithdrawalRequest type WithdrawalRequests []*WithdrawalRequest // MarshalSSZ marshals the WithdrawalRequests object to SSZ format by encoding each deposit individually. func (wr WithdrawalRequests) MarshalSSZ() ([]byte, error) { return sszutil.MarshalItemsEIP7685(wr) } // ValidateAfterDecodingSSZ validates the WithdrawalRequests object after decoding. func (wr WithdrawalRequests) ValidateAfterDecodingSSZ() error { if len(wr) > constants.MaxWithdrawalRequestsPerPayload { return fmt.Errorf( "invalid number of withdrawal requests, got %d max %d", len(wr), constants.MaxWithdrawalRequestsPerPayload, ) } return nil } // DecodeWithdrawalRequests decodes SSZ data by decoding each withdrawal individually. func DecodeWithdrawalRequests(data []byte) (WithdrawalRequests, error) { maxSize := constants.MaxWithdrawalRequestsPerPayload * sszWithdrawRequestSize if len(data) > maxSize { return nil, fmt.Errorf( "invalid withdrawal requests SSZ size, requests should not be more "+ "than the max per payload, got %d max %d", len(data), maxSize, ) } if len(data) < sszWithdrawRequestSize { return nil, fmt.Errorf( "invalid withdrawal requests SSZ size, got %d expected at least %d", len(data), sszWithdrawRequestSize, ) } // Use the EIP-7685 unmarshalItems helper. return sszutil.UnmarshalItemsEIP7685( data, sszWithdrawRequestSize, func() *WithdrawalRequest { return new(WithdrawalRequest) }, ) } ================================================ FILE: consensus-types/types/withdrawals_request_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "fmt" "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/ssz" enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" "github.com/stretchr/testify/require" ) func TestWithdrawalRequest_ValidValuesSSZ(t *testing.T) { t.Parallel() testCases := []struct { name string withdrawalRequest *types.WithdrawalRequest }{ { name: "basic", withdrawalRequest: &types.WithdrawalRequest{ // 20-byte execution address SourceAddress: common.ExecutionAddress{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, }, // 48-byte public key ValidatorPubKey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, Amount: 1000, }, }, { name: "zero amount", withdrawalRequest: &types.WithdrawalRequest{ SourceAddress: common.ExecutionAddress{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, }, ValidatorPubKey: crypto.BLSPubkey{ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, }, Amount: 0, }, }, { name: "max values", withdrawalRequest: &types.WithdrawalRequest{ SourceAddress: common.ExecutionAddress{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, ValidatorPubKey: crypto.BLSPubkey{ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }, Amount: 1<<64 - 1, }, }, { name: "random-ish values", withdrawalRequest: &types.WithdrawalRequest{ SourceAddress: common.ExecutionAddress{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, }, ValidatorPubKey: crypto.BLSPubkey{ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, }, Amount: 54321, }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // Marshal the original withdrawal request. withdrawalRequestBytes, err := tc.withdrawalRequest.MarshalSSZ() require.NoError(t, err) // Unmarshal into a Prysm withdrawal request. var prysmWithdrawal enginev1.WithdrawalRequest err = prysmWithdrawal.UnmarshalSSZ(withdrawalRequestBytes) require.NoError(t, err) prysmHTR, err := prysmWithdrawal.HashTreeRoot() require.NoError(t, err) withdrawalHTR := tc.withdrawalRequest.HashTreeRoot() // Compare the HashTreeRoots. Effectively a test for comparing all field values. require.Equal(t, withdrawalHTR[:], prysmHTR[:]) // Marshal the Prysm withdrawal request. prysmWithdrawalBytes, err := prysmWithdrawal.MarshalSSZ() require.NoError(t, err) // Unmarshal back into a new WithdrawalRequest. var recomputedWithdrawalRequest types.WithdrawalRequest err = ssz.Unmarshal(prysmWithdrawalBytes, &recomputedWithdrawalRequest) require.NoError(t, err) // Compare that the original and recomputed values match. require.Equal(t, *tc.withdrawalRequest, recomputedWithdrawalRequest) }) } } //nolint:paralleltest // Invalid SSZ values cannot be run in parallel due to zeroalloc, which is global shared memory. func TestWithdrawalRequest_InvalidValuesUnmarshalSSZ(t *testing.T) { // Build a valid withdrawal request to obtain a baseline valid payload. validWithdrawal := &types.WithdrawalRequest{ SourceAddress: common.ExecutionAddress{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, }, ValidatorPubKey: crypto.BLSPubkey{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, }, Amount: 1000, } validBytes, err := validWithdrawal.MarshalSSZ() require.NoError(t, err) // Build a slice of invalid payloads. invalidPayloads := [][]byte{ nil, // nil slice {}, // empty slice []byte("this is not ssz"), // arbitrary non-SSZ data {0x00, 0x01}, // too short to be valid // A truncated valid payload: remove last 5 bytes. func() []byte { if len(validBytes) > 5 { return validBytes[:len(validBytes)-5] } return validBytes }(), // A valid payload with extra trailing bytes. func() []byte { extra := []byte{0xAA, 0xBB, 0xCC, 0xDD} return append(validBytes, extra...) }(), } for i, payload := range invalidPayloads { i, payload := i, payload // capture loop variables t.Run(fmt.Sprintf("invalidWithdrawal_%d", i), func(t *testing.T) { // Ensure that calling UnmarshalSSZ does not panic and returns an error. require.NotPanics(t, func() { var w types.WithdrawalRequest err = ssz.Unmarshal(payload, &w) require.Error(t, err, "expected error for payload %v", payload) }) }) } } ================================================ FILE: contracts/.gas-snapshot ================================================ BeaconVerifierTest:test_verifyBeaconBlockProposer() (gas: 155057) BeaconVerifierTest:test_verifyCoinbase() (gas: 49435) BeaconVerifierTest:test_verifyExecutionNumber() (gas: 49540) DepositContractTest:testFuzz_DepositCount(uint256) (runs: 256, μ: 3248621, ~: 3269529) DepositContractTest:testFuzz_DepositNativeNotDivisibleByGwei(uint256) (runs: 256, μ: 56864, ~: 56870) DepositContractTest:testFuzz_DepositNativeWrongMinAmount(uint256) (runs: 256, μ: 88553, ~: 88567) DepositContractTest:testFuzz_DepositWrongAmount(uint256) (runs: 256, μ: 50030, ~: 50110) DepositContractTest:testFuzz_DepositWrongCredentials(bytes) (runs: 256, μ: 38885, ~: 38895) DepositContractTest:testFuzz_DepositsWrongPubKey(bytes) (runs: 256, μ: 42781, ~: 42781) DepositContractTest:test_Deposit() (gas: 107673) DepositContractTest:test_DepositNative() (gas: 107602) DepositContractTest:test_DepositNativeNotDivisibleByGwei() (gas: 92838) DepositContractTest:test_DepositNativeWrongMinAmount() (gas: 88040) DepositContractTest:test_DepositWrongAmount() (gas: 49193) DepositContractTest:test_DepositWrongCredentials() (gas: 44349) DepositContractTest:test_DepositWrongPubKey() (gas: 42198) DepositContractTest:test__codesize() (gas: 14224) SSZTest:test_ValidatorPubkeyRoot() (gas: 3495) SSZTest:test_addressHashTreeRoot() (gas: 3731) SSZTest:test_uint64HashTreeRoot() (gas: 4955) ================================================ FILE: contracts/Makefile ================================================ #!/usr/bin/make -f ################# # forge # ################# forge-build: | @forge build --extra-output-files bin --extra-output-files abi --root $(CONTRACTS_DIR) forge-clean: | @forge clean --root $(CONTRACTS_DIR) test-forge-unit: @echo "Running forge unit tests..." @cd $(CONTRACTS_DIR) && FOUNDRY_PROFILE=coverage forge test test-forge-cover: @echo "Running forge test with coverage..." @cd $(CONTRACTS_DIR) && FOUNDRY_PROFILE=coverage forge build && forge coverage --nmt testFuzz --report lcov --report-file ../test-forge-cover.txt test-forge-fuzz: @echo "Running forge fuzz tests..." @cd $(CONTRACTS_DIR) && FOUNDRY_PROFILE=fuzz forge test forge-snapshot: @echo "Running forge snapshot..." @cd $(CONTRACTS_DIR) && forge snapshot --isolate --fuzz-runs 1 forge-snapshot-diff: @echo "Running forge snapshot diff..." @cd $(CONTRACTS_DIR) && forge snapshot --diff --isolate --fuzz-runs 1 forge-lint-fix: @echo "--> Running forge fmt" @cd $(CONTRACTS_DIR) && forge fmt --root $(CONTRACTS_DIR) . forge-lint: @echo "--> Running forge lint" @cd $(CONTRACTS_DIR) && forge fmt --check ================================================ FILE: contracts/README.md ================================================ # BeaconKit Contracts ## Mock PoL Contracts Mock Proof-of-Liquidity contracts for testing execution client integration. ### Usage Generate bytecode for genesis deployment: ```bash # Build contracts forge build # Extract SimplePoLDistributor bytecode cat out/MockPoL.sol/SimplePoLDistributor.json | jq -r .deployedBytecode.object # Extract ValidatorRegistry bytecode cat out/MockValidatorRegistry.sol/ValidatorRegistry.json | jq -r .deployedBytecode.object ``` The same pattern can be used to extract bytecode for other contracts in the `brip0004/` directory. ### Contracts - `MockPoL.sol` - Basic PoL distributor with multi-contract state changes - `MockPoLReverting.sol` - PoL distributor that reverts after 10 distributions - `MockPoLGasEnforcer.sol` - Gas-constrained PoL distributor for gas limit testing - `MockValidatorRegistry.sol` - Registry contract for testing cross-contract calls ================================================ FILE: contracts/foundry.toml ================================================ # Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config [profile.default] auto_detect_solc = false solc = "0.8.26" evm_version = "cancun" fuzz = { runs = 256, seed = "42" } gas_reports = ["*"] cache = true optimizer = true optimizer_runs = 4294967295 via_ir = false out = "out" script = "script" src = "src" test = "test" verbosity = 3 fs_permissions = [{ access = "read", path = "./"}] [profile.fuzz] fuzz = { runs = 1024 } verbosity = 1 [profile.coverage] fuzz = { runs = 16 } [fmt] bracket_spacing = true int_types = "long" line_length = 80 multiline_func_header = "all" number_underscore = "thousands" quote_style = "double" tab_width = 4 wrap_comments = false [rpc_endpoints] localhost = "http://localhost:8545" sepolia = "https://sepolia.gateway.tenderly.co" ================================================ FILE: contracts/remappings.txt ================================================ @forge-std/=lib/forge-std/src/ @solady/src/=lib/solady/src/ @solady/test/=lib/solady/test/ @interfaces/=interfaces/ @src/=src/ ================================================ FILE: contracts/slither.config.json ================================================ { "detectors_to_exclude": "assembly,calls-loop,low-level-calls,naming-convention,similar-names,solc-version,timestamp,unused-return", "exclude_informational": true, "exclude_low": false, "exclude_medium": false, "exclude_high": false, "filter_paths": "lib|node_modules|script|test" } ================================================ FILE: contracts/src/brip0004/MockPoL.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; import "./MockValidatorRegistry.sol"; /// @title SimplePoLDistributor /// @notice Mock PoL distributor for testing execution client integration /// @dev Interacts with ValidatorRegistry to test multi-contract state changes contract SimplePoLDistributor { /// @notice System address that can call distributeFor (execution layer client) address private constant SYSTEM_ADDRESS = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE; /// @notice The validator registry contract address (hardcoded for genesis deployment) ValidatorRegistry private constant VALIDATOR_REGISTRY = ValidatorRegistry(0x4200000000000000000000000000000000000043); /// @notice Event emitted when distributeFor is called event PoLDistributed(bytes pubkey); /// @notice Counter for total distributions uint256 public totalDistributions; /// @notice Error thrown when caller is not the system address error NotSystemAddress(); /// @dev Restricts access to system address (execution layer client only) modifier onlySystemCall() { if (msg.sender != SYSTEM_ADDRESS) { revert NotSystemAddress(); } _; } /// @notice Main function called by execution client /// @param pubkey The validator public key /// @dev Calls ValidatorRegistry to test multi-contract state changes // slither-disable-next-line reentrancy-events function distributeFor(bytes calldata pubkey) external onlySystemCall { totalDistributions++; VALIDATOR_REGISTRY.recordValidatorActivity(pubkey); emit PoLDistributed(pubkey); } } ================================================ FILE: contracts/src/brip0004/MockPoLGasEnforcer.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; /// @title GasEnforcedPoLDistributor /// @notice PoL distributor requiring exactly 29,999,646 gas for testing gas limits /// @dev Reverts if called with incorrect gas amount contract GasEnforcedPoLDistributor { function distributeFor(bytes calldata /*pubkey*/ ) public view { uint256 start_gas = gasleft(); require(start_gas == 29_999_646, "Insufficient gas"); } } ================================================ FILE: contracts/src/brip0004/MockPoLReverting.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; import "./MockValidatorRegistry.sol"; /// @title RevertingPoLDistributor /// @notice Mock PoL distributor that reverts after 10 distributions for testing /// @dev Interacts with ValidatorRegistry to test multi-contract state changes contract RevertingPoLDistributor { /// @notice System address that can call distributeFor (execution layer client) address private constant SYSTEM_ADDRESS = 0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE; /// @notice The validator registry contract address (hardcoded for genesis deployment) ValidatorRegistry private constant VALIDATOR_REGISTRY = ValidatorRegistry(0x4200000000000000000000000000000000000043); /// @notice Event emitted when distributeFor is called event PoLDistributed(bytes pubkey); /// @notice Counter for total distributions uint256 public totalDistributions; /// @notice Error thrown when caller is not the system address error NotSystemAddress(); /// @dev Restricts access to system address (execution layer client only) modifier onlySystemCall() { if (msg.sender != SYSTEM_ADDRESS) { revert NotSystemAddress(); } _; } /// @notice Main function called by execution client /// @param pubkey The validator public key /// @dev Calls ValidatorRegistry to test multi-contract state changes // slither-disable-next-line reentrancy-events function distributeFor(bytes calldata pubkey) external onlySystemCall { require(totalDistributions < 10, "Max distributions reached"); totalDistributions++; VALIDATOR_REGISTRY.recordValidatorActivity(pubkey); emit PoLDistributed(pubkey); } } ================================================ FILE: contracts/src/brip0004/MockValidatorRegistry.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; /// @title ValidatorRegistry /// @notice Simple registry contract for testing multi-contract state changes /// @dev Called by PoL distributors to increment activity counter contract ValidatorRegistry { /// @notice Activity counter incremented on each call uint256 public callCount; /// @notice Event emitted when activity is recorded event RegistryCalled(uint256 newCount); /// @notice Records validator activity by incrementing counter function recordValidatorActivity(bytes calldata /* pubkey */ ) external { callCount++; emit RegistryCalled(callCount); } } ================================================ FILE: contracts/src/eip4399/RandaoTester.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; /// @title RandaoTester /// @dev This contract is used during the integration testing of /// EIP-4399 in BeaconKit. /// DO NOT USE THIS FOR GENERATING RANDOMNESS IN PRODUCTION // FOR ANYTHING IMPORTANT. /// @author https://eips.ethereum.org/EIPS/eip-4399 /// @author itsdevbear@berachain.com contract RandaoTester { /// @notice Stores the last retrieved RANDAO mix. uint256 public lastValue; /// @notice Retrieves and stores the previous RANDAO mix. /// @dev Accesses the `prevrandao` property from the block global variable. /// @return The last retrieved RANDAO mix. function storePrevRandao() external returns (uint256) { lastValue = block.prevrandao; return block.prevrandao; } } ================================================ FILE: contracts/src/eip4788/README.md ================================================ # ERC-4788 Bytecode As taken from: [https://etherscan.io/address/0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02#code](https://etherscan.io/address/0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02#code) ================================================ FILE: contracts/src/eip4788/SSZ.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity ^0.8.21; /// @notice Library for SSZ (Simple Serialize) proof verification. /// @author [madlabman](https://github.com/madlabman/eip-4788-proof) library SSZ { /// @dev SHA256 precompile address. uint8 internal constant SHA256 = 0x02; error BranchHasMissingItem(); error BranchHasExtraItem(); /// @notice Modified version of `verify` from `MerkleProofLib` to support /// generalized indices and sha256 precompile. /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, /// given `proof`. function verifyProof( bytes32[] calldata proof, bytes32 root, bytes32 leaf, uint256 index ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. for { } 1 { } { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, and(index, 1)) index := shr(1, index) if iszero(index) { // revert BranchHasExtraItem() mstore(0x00, 0x5849603f) revert(0x1c, 0x04) } // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements // are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Call sha256 precompile let result := staticcall(gas(), SHA256, 0x00, 0x40, 0x00, 0x20) if eq(result, 0) { revert(0, 0) } // Reuse `leaf` to store the hash to reduce stack operations. leaf := mload(0x00) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } // index != 1 if gt(sub(index, 1), 0) { // revert BranchHasMissingItem() mstore(0x00, 0x1b6661c3) revert(0x1c, 0x04) } isValid := eq(leaf, root) } } } /// @notice Contract for testing SSZ (Simple Serialize) proof verification with the `SSZ` library. /// @author Inspired by [madlabman](https://github.com/madlabman/eip-4788-proof). contract SSZTest { /// @notice The address of the EIP-4788 Beacon Roots contract. address public constant BEACON_ROOTS = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02; // Signature: 0x3033b0ff error RootNotFound(); /// @notice Verifies a proof of inclusion for a given leaf in a Merkle tree. /// @param proof The proof of inclusion. /// @param root The root of the Merkle tree. /// @param leaf The leaf to verify. /// @param index The index of the leaf in the Merkle tree. /// @return isValid Whether the proof is valid. function verifyProof( bytes32[] calldata proof, bytes32 root, bytes32 leaf, uint256 index ) external view returns (bool isValid) { isValid = SSZ.verifyProof(proof, root, leaf, index); } /// @notice Verifies a proof of inclusion for a given leaf in a Merkle tree. Reverts if the proof is invalid. /// @param proof The proof of inclusion. /// @param root The root of the Merkle tree. /// @param leaf The leaf to verify. /// @param index The index of the leaf in the Merkle tree. function mustVerifyProof( bytes32[] calldata proof, bytes32 root, bytes32 leaf, uint256 index ) external view { if (!SSZ.verifyProof(proof, root, leaf, index)) { revert("Proof is invalid"); } } /// @notice Get the parent block root at a given timestamp. /// @dev Reverts with `RootNotFound()` if the root is not found. function getParentBlockRootAt(uint64 ts) external view returns (bytes32 root) { assembly ("memory-safe") { mstore(0, ts) let success := staticcall(gas(), BEACON_ROOTS, 0, 0x20, 0, 0x20) if iszero(success) { mstore(0, 0x3033b0ff) // RootNotFound() revert(0x1c, 0x04) } root := mload(0) } } } ================================================ FILE: contracts/src/eip4788/deployment.json ================================================ { "type": "0x0", "nonce": "0x0", "to": null, "gas": "0x3d090", "gasPrice": "0xe8d4a51000", "maxPriorityFeePerGas": null, "maxFeePerGas": null, "value": "0x0", "input": "0x60618060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", "v": "0x1b", "r": "0x539", "s": "0x1b9b6eb1f0", "hash": "0xdf52c2d3bbe38820fff7b5eaab3db1b91f8e1412b56497d88388fb5d4ea1fde0" } ================================================ FILE: contracts/src/staking/DepositContract.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; import { ERC165 } from "./IERC165.sol"; import { IDepositContract } from "./IDepositContract.sol"; /** * @title DepositContract * @author Berachain Team * @notice A contract that handles validators deposits. * @dev Its events are used by the beacon chain to manage the staking process. * @dev This contract does not implement the deposit merkle tree. */ contract DepositContract is IDepositContract, ERC165 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The minimum amount of `BERA` to deposit. /// @dev This is 1 ether in Gwei since our deposit contract denominates in Gwei. 1e9 * 1e9 = 1e18. uint64 internal constant MIN_DEPOSIT_AMOUNT_IN_GWEI = 1e9; /// @dev The length of the public key, PUBLIC_KEY_LENGTH bytes. uint8 internal constant PUBLIC_KEY_LENGTH = 48; /// @dev The length of the signature, SIGNATURE_LENGTH bytes. uint8 internal constant SIGNATURE_LENGTH = 96; /// @dev The length of the credentials, 1 byte prefix + 11 bytes padding + 20 bytes address = 32 bytes. uint8 internal constant CREDENTIALS_LENGTH = 32; /// @dev 1 day in seconds. /// @dev This is the delay before a new operator can accept a change. uint96 private constant ONE_DAY = 86_400; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev QueuedOperator is a struct that represents an operator address change request. struct QueuedOperator { uint96 queuedTimestamp; address newOperator; } /// @dev depositCount represents the number of deposits that /// have been made to the contract. /// @dev The index of the next deposit will use this value. uint64 public depositCount; /// @dev The hash tree root of the genesis deposits. /// @dev Should be set in deployment (predeploy state or constructor). // slither-disable-next-line constable-states bytes32 public genesisDepositsRoot; /// @dev The mapping of public keys to operator addresses. mapping(bytes => address) private _operatorByPubKey; /// @dev The mapping of public keys to operator change requests. mapping(bytes => QueuedOperator) public queuedOperator; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VIEWS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @inheritdoc ERC165 function supportsInterface(bytes4 interfaceId) external pure override returns (bool) { return interfaceId == type(ERC165).interfaceId || interfaceId == type(IDepositContract).interfaceId; } /// @inheritdoc IDepositContract function getOperator(bytes calldata pubkey) external view returns (address) { return _operatorByPubKey[pubkey]; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DEPOSIT */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @inheritdoc IDepositContract function deposit( bytes calldata pubkey, bytes calldata credentials, bytes calldata signature, address operator ) public payable virtual { if (pubkey.length != PUBLIC_KEY_LENGTH) { revert InvalidPubKeyLength(); } if (credentials.length != CREDENTIALS_LENGTH) { revert InvalidCredentialsLength(); } if (signature.length != SIGNATURE_LENGTH) { revert InvalidSignatureLength(); } // Set operator on the first deposit. // zero `_operatorByPubKey[pubkey]` means the pubkey is not registered. if (_operatorByPubKey[pubkey] == address(0)) { if (operator == address(0)) { revert ZeroOperatorOnFirstDeposit(); } _operatorByPubKey[pubkey] = operator; emit OperatorUpdated(pubkey, operator, address(0)); } // If not the first deposit, operator address must be 0. // This prevents from the front-running of the first deposit to set the operator. else if (operator != address(0)) { revert OperatorAlreadySet(); } uint64 amountInGwei = _deposit(); if (amountInGwei < MIN_DEPOSIT_AMOUNT_IN_GWEI) { revert InsufficientDeposit(); } // slither-disable-next-line reentrancy-benign,reentrancy-events emit Deposit( pubkey, credentials, amountInGwei, signature, depositCount++ ); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATOR CHANGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @inheritdoc IDepositContract function requestOperatorChange( bytes calldata pubkey, address newOperator ) external { // Cache the current operator. address currentOperator = _operatorByPubKey[pubkey]; // Only the current operator can request a change. // This will also revert if the pubkey is not registered. if (msg.sender != currentOperator) { revert NotOperator(); } // Revert if the new operator is zero address. if (newOperator == address(0)) { revert ZeroAddress(); } QueuedOperator storage qO = queuedOperator[pubkey]; qO.newOperator = newOperator; qO.queuedTimestamp = uint96(block.timestamp); emit OperatorChangeQueued( pubkey, newOperator, currentOperator, block.timestamp ); } /// @inheritdoc IDepositContract function cancelOperatorChange(bytes calldata pubkey) external { // Only the current operator can cancel the change. if (msg.sender != _operatorByPubKey[pubkey]) { revert NotOperator(); } delete queuedOperator[pubkey]; emit OperatorChangeCancelled(pubkey); } /// @inheritdoc IDepositContract function acceptOperatorChange(bytes calldata pubkey) external { QueuedOperator storage qO = queuedOperator[pubkey]; (address newOperator, uint96 queuedTimestamp) = (qO.newOperator, qO.queuedTimestamp); // Only the new operator can accept the change. // This will revert if nothing is queued as newOperator will be zero address. if (msg.sender != newOperator) { revert NotNewOperator(); } // Check if the queue delay has passed. if (queuedTimestamp + ONE_DAY > uint96(block.timestamp)) { revert NotEnoughTime(); } // Cache the old operator. address oldOperator = _operatorByPubKey[pubkey]; _operatorByPubKey[pubkey] = newOperator; delete queuedOperator[pubkey]; emit OperatorUpdated(pubkey, newOperator, oldOperator); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Validates the deposit amount and sends the native asset to the zero address. function _deposit() internal virtual returns (uint64) { if (msg.value % 1 gwei != 0) { revert DepositNotMultipleOfGwei(); } uint256 amountInGwei = msg.value / 1 gwei; if (amountInGwei > type(uint64).max) { revert DepositValueTooHigh(); } _safeTransferETH(address(0), msg.value); return uint64(amountInGwei); } /** * @notice Safely transfers ETH to the given address. * @dev From the Solady library. * @param to The address to transfer the ETH to. * @param amount The amount of ETH to transfer. */ function _safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if iszero( call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00) ) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } } ================================================ FILE: contracts/src/staking/IDepositContract.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; /// @title IDepositContract /// @author Berachain Team. interface IDepositContract { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Signature: 0xe8966d7a error NotEnoughTime(); // Signature: 0xd92e233d error ZeroAddress(); // Signature: 0x7c214f04 error NotOperator(); /// @dev Error thrown when the deposit amount is too small, to prevent dust deposits. // Signature: 0x0e1eddda error InsufficientDeposit(); /// @dev Error thrown when the deposit amount is not a multiple of Gwei. // Signature: 0x40567b38 error DepositNotMultipleOfGwei(); /// @dev Error thrown when the deposit amount is too high, since it is a uint64. // Signature: 0x2aa66734 error DepositValueTooHigh(); /// @dev Error thrown when the public key length is not 48 bytes. // Signature: 0x9f106472 error InvalidPubKeyLength(); /// @dev Error thrown when the withdrawal credentials length is not 32 bytes. // Signature: 0xb39bca16 error InvalidCredentialsLength(); /// @dev Error thrown when the signature length is not 96 bytes. // Signature: 0x4be6321b error InvalidSignatureLength(); /// @dev Error thrown when the input operator is zero address on the first deposit. // Signature: 0x51969a7a error ZeroOperatorOnFirstDeposit(); /// @dev Error thrown when the operator is already set and caller passed non-zero operator. // Signature: 0xc4142b41 error OperatorAlreadySet(); /// @dev Error thrown when the caller is not the current operator. // Signature: 0x819a0d0b error NotNewOperator(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @dev Emitted when a deposit is made, which could mean a new validator or a top up of an existing one. * @param pubkey the public key of the validator who is being deposited for if not a new validator. * @param credentials the public key of the operator if new validator or the depositor if top up. * @param amount the amount of stake being deposited, in Gwei. * @param signature the signature of the deposit message, only checked when creating a new validator. * @param index the index of the deposit. */ event Deposit( bytes pubkey, bytes credentials, uint64 amount, bytes signature, uint64 index ); /** * @notice Emitted when the operator change of a validator is queued. * @param pubkey The pubkey of the validator. * @param queuedOperator The new queued operator address. * @param currentOperator The current operator address. * @param queuedTimestamp The timestamp when the change was queued. */ event OperatorChangeQueued( bytes indexed pubkey, address queuedOperator, address currentOperator, uint256 queuedTimestamp ); /** * @notice Emitted when the operator change of a validator is cancelled. * @param pubkey The pubkey of the validator. */ event OperatorChangeCancelled(bytes indexed pubkey); /** * @notice Emitted when the operator of a validator is updated. * @param pubkey The pubkey of the validator. * @param newOperator The new operator address. * @param previousOperator The previous operator address. */ event OperatorUpdated( bytes indexed pubkey, address newOperator, address previousOperator ); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* VIEWS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @notice Get the operator address for a given pubkey. * @dev Returns zero address if the pubkey is not registered. * @param pubkey The pubkey of the validator. * @return The operator address for the given pubkey. */ function getOperator(bytes calldata pubkey) external view returns (address); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WRITES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /** * @notice Submit a deposit message to the Beaconchain. * @notice This will be used to create a new validator or to top up an existing one, increasing stake. * @param pubkey is the consensus public key of the validator. If subsequent deposit, its ignored. * @param credentials is the staking credentials of the validator. If this is the first deposit it is * validator operator public key, if subsequent deposit it is the depositor's public key. * @param signature is the signature used only on the first deposit. * @param operator is the address of the operator. * @dev emits the Deposit event upon successful deposit. * @dev Reverts if the operator is already set and caller passed non-zero operator. */ function deposit( bytes calldata pubkey, bytes calldata credentials, bytes calldata signature, address operator ) external payable; /** * @notice Request to change the operator of a validator. * @dev Only the current operator can request a change. * @param pubkey The pubkey of the validator. * @param newOperator The new operator address. */ function requestOperatorChange( bytes calldata pubkey, address newOperator ) external; /** * @notice Cancel the operator change of a validator. * @dev Only the current operator can cancel the change. * @param pubkey The pubkey of the validator. */ function cancelOperatorChange(bytes calldata pubkey) external; /** * @notice Accept the operator change of a validator. * @dev Only the new operator can accept the change. * @dev Reverts if the queue delay has not passed. * @param pubkey The pubkey of the validator. */ function acceptOperatorChange(bytes calldata pubkey) external; } ================================================ FILE: contracts/src/staking/IERC165.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; // Based on official specification in https://eips.ethereum.org/EIPS/eip-165 interface ERC165 { /// @notice Query if a contract implements an interface /// @param interfaceId The interface identifier, as specified in ERC-165 /// @dev Interface identification is specified in ERC-165. This function /// uses less than 30,000 gas. /// @return `true` if the contract implements `interfaceId` and /// `interfaceId` is not 0xffffffff, `false` otherwise function supportsInterface(bytes4 interfaceId) external pure returns (bool); } ================================================ FILE: contracts/test/staking/DepositContract.t.sol ================================================ // SPDX-License-Identifier: MIT pragma solidity ^0.8.25; import "forge-std/Test.sol"; import { SoladyTest } from "@solady/test/utils/SoladyTest.sol"; import { IDepositContract } from "@src/staking/IDepositContract.sol"; import { DepositContract } from "@src/staking/DepositContract.sol"; contract DepositContractTest is SoladyTest, StdCheats { /// @dev The depositor address. address internal depositor = 0x20f33CE90A13a4b5E7697E3544c3083B8F8A51D4; /// @dev The owner address. address owner = 0x6969696969696969696969696969696969696969; /// @dev The validator public key. bytes internal VALIDATOR_PUBKEY = _create48Byte(); /// @dev The withdrawal credentials that we will use. bytes internal WITHDRAWAL_CREDENTIALS = _credential(address(this)); /// @dev The staking credentials that are right. bytes internal STAKING_CREDENTIALS = _credential(depositor); bytes32 internal constant STAKING_ASSET_SLOT = bytes32(0); /// @dev the deposit contract. DepositContract internal depositContract; function setUp() public virtual { depositContract = new DepositContract(); } function testFuzz_DepositsWrongPubKey(bytes calldata pubKey) public { vm.assume(pubKey.length != 96); vm.expectRevert(IDepositContract.InvalidPubKeyLength.selector); vm.deal(depositor, 32 ether); vm.prank(depositor); depositContract.deposit{ value: 32 ether }( bytes("wrong_public_key"), STAKING_CREDENTIALS, _create96Byte(), depositor ); } function test_DepositWrongPubKey() public { vm.expectRevert(IDepositContract.InvalidPubKeyLength.selector); vm.deal(depositor, 32 ether); vm.prank(depositor); depositContract.deposit{ value: 32 ether }( bytes("wrong_public_key"), STAKING_CREDENTIALS, _create96Byte(), depositor ); } function testFuzz_DepositWrongCredentials(bytes calldata credentials) public { vm.assume(credentials.length != 32); vm.deal(depositor, 32 ether); vm.expectRevert(IDepositContract.InvalidCredentialsLength.selector); vm.prank(depositor); depositContract.deposit{ value: 32 ether }( _create48Byte(), credentials, _create96Byte(), depositor ); } function test_DepositWrongCredentials() public { vm.expectRevert(IDepositContract.InvalidCredentialsLength.selector); vm.deal(depositor, 32 ether); vm.prank(depositor); depositContract.deposit{ value: 32 ether }( VALIDATOR_PUBKEY, bytes("wrong_credentials"), _create96Byte(), depositor ); } function test_DepositWrongAmount() public { vm.expectRevert(IDepositContract.InsufficientDeposit.selector); vm.prank(depositor); // send with 0 ether depositContract.deposit( VALIDATOR_PUBKEY, STAKING_CREDENTIALS, _create96Byte(), depositor ); } function testFuzz_DepositNativeWrongMinAmount(uint256 amountInEther) public { amountInEther = _bound(amountInEther, 1, 31); uint256 amountInGwei = amountInEther * 1 gwei; vm.deal(depositor, amountInGwei); vm.prank(depositor); vm.expectRevert(IDepositContract.InsufficientDeposit.selector); depositContract.deposit{ value: amountInGwei }( VALIDATOR_PUBKEY, STAKING_CREDENTIALS, _create96Byte(), depositor ); } function test_DepositNativeWrongMinAmount() public { uint256 amount = 31 gwei; vm.deal(depositor, amount); vm.prank(depositor); vm.expectRevert(IDepositContract.InsufficientDeposit.selector); depositContract.deposit{ value: amount }( VALIDATOR_PUBKEY, STAKING_CREDENTIALS, _create96Byte(), depositor ); } function testFuzz_DepositNativeNotDivisibleByGwei(uint256 amount) public { amount = _bound(amount, 31e9 + 1, uint256(type(uint64).max)); vm.assume(amount % 1e9 != 0); vm.deal(depositor, amount); vm.prank(depositor); vm.expectRevert(IDepositContract.DepositNotMultipleOfGwei.selector); depositContract.deposit{ value: amount }( VALIDATOR_PUBKEY, STAKING_CREDENTIALS, _create96Byte(), depositor ); } function test_DepositNativeNotDivisibleByGwei() public { uint256 amount = 32e9 + 1; vm.deal(depositor, amount); vm.expectRevert(IDepositContract.DepositNotMultipleOfGwei.selector); vm.prank(depositor); depositContract.deposit{ value: amount }( VALIDATOR_PUBKEY, STAKING_CREDENTIALS, _create96Byte(), depositor ); amount = 32e9 - 1; vm.deal(depositor, amount); vm.expectRevert(IDepositContract.DepositNotMultipleOfGwei.selector); vm.prank(depositor); depositContract.deposit{ value: amount }( VALIDATOR_PUBKEY, STAKING_CREDENTIALS, _create96Byte(), depositor ); } function test_DepositNative() public { vm.deal(depositor, 32 ether); vm.prank(depositor); vm.expectEmit(true, true, true, true); emit IDepositContract.Deposit( VALIDATOR_PUBKEY, STAKING_CREDENTIALS, 32 gwei, _create96Byte(), 0 ); depositContract.deposit{ value: 32 ether }( VALIDATOR_PUBKEY, STAKING_CREDENTIALS, _create96Byte(), depositor ); } function testFuzz_DepositCount(uint256 count) public { count = _bound(count, 1, 100); uint64 depositCount; for (uint256 i; i < count; ++i) { depositor = makeAddr(vm.toString(i)); vm.deal(depositor, 32 ether); vm.startPrank(depositor); vm.expectEmit(true, true, true, true); emit IDepositContract.Deposit( _newPubkey(i), STAKING_CREDENTIALS, 32 gwei, _create96Byte(), depositCount++ ); depositContract.deposit{ value: 32 ether }( _newPubkey(i), STAKING_CREDENTIALS, _create96Byte(), depositor ); vm.stopPrank(); } assertEq(depositContract.depositCount(), depositCount); } function _credential(address addr) internal pure returns (bytes memory) { return abi.encodePacked(bytes1(0x01), bytes11(0x0), addr); } function _create96Byte() internal pure returns (bytes memory) { return abi.encodePacked(bytes32("32"), bytes32("32"), bytes32("32")); } function _create48Byte() internal pure returns (bytes memory) { return abi.encodePacked(bytes32("32"), bytes16("16")); } function _newPubkey(uint256 i) internal pure returns (bytes memory) { return abi.encodePacked(bytes32(i), bytes16("16")); } } ================================================ FILE: da/blob/factory.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blob import ( "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/merkle" "golang.org/x/sync/errgroup" ) // SidecarFactory is a factory for sidecars. type SidecarFactory struct { // metrics is used to collect and report factory metrics. metrics *factoryMetrics } // NewSidecarFactory creates a new sidecar factory. func NewSidecarFactory( telemetrySink TelemetrySink, ) *SidecarFactory { return &SidecarFactory{ metrics: newFactoryMetrics(telemetrySink), } } // BuildSidecars builds a sidecar. func (f *SidecarFactory) BuildSidecars( signedBlk *ctypes.SignedBeaconBlock, bundle engineprimitives.BlobsBundle, ) (types.BlobSidecars, error) { var ( blobs = bundle.GetBlobs() commitments = bundle.GetCommitments() proofs = bundle.GetProofs() numBlobs = uint64(len(blobs)) sidecars = make([]*types.BlobSidecar, numBlobs) blk = signedBlk.GetBeaconBlock() body = blk.GetBody() header = blk.GetHeader() g = errgroup.Group{} ) startTime := time.Now() defer f.metrics.measureBuildSidecarsDuration( startTime, math.U64(numBlobs), ) // We can reuse the signature from the SignedBeaconBlock. Verifying the // signature will require the corresponding BeaconBlock to reconstruct the // signing root. sigHeader := ctypes.NewSignedBeaconBlockHeader(header, signedBlk.GetSignature()) for i := range numBlobs { g.Go(func() error { inclusionProof, err := f.BuildKZGInclusionProof(body, math.U64(i)) if err != nil { return err } sidecars[i] = types.BuildBlobSidecar( math.U64(i), sigHeader, blobs[i], commitments[i], proofs[i], inclusionProof, ) return nil }) } return sidecars, g.Wait() } // BuildKZGInclusionProof builds a KZG inclusion proof. func (f *SidecarFactory) BuildKZGInclusionProof( body *ctypes.BeaconBlockBody, index math.U64, ) ([]common.Root, error) { startTime := time.Now() defer f.metrics.measureBuildKZGInclusionProofDuration(startTime) // Build the merkle proof to the commitment within the // list of commitments. commitmentsProof, err := f.BuildCommitmentProof(body, index) if err != nil { return nil, err } // Build the merkle proof for the body root. bodyProof, err := f.BuildBlockBodyProof(body) if err != nil { return nil, err } // By property of the merkle tree, we can concatenate the // two proofs to get the final proof. return append(commitmentsProof, bodyProof...), nil } // BuildBlockBodyProof builds a block body proof. func (f *SidecarFactory) BuildBlockBodyProof( body *ctypes.BeaconBlockBody, ) ([]common.Root, error) { startTime := time.Now() defer f.metrics.measureBuildBlockBodyProofDuration(startTime) tlrs, err := body.GetTopLevelRoots() if err != nil { return nil, err } tree, err := merkle.NewTreeWithMaxLeaves[common.Root]( tlrs, body.Length()-1, ) if err != nil { return nil, err } return tree.MerkleProof(ctypes.KZGPosition) } // BuildCommitmentProof builds a commitment proof. func (f *SidecarFactory) BuildCommitmentProof( body *ctypes.BeaconBlockBody, index math.U64, ) ([]common.Root, error) { startTime := time.Now() defer f.metrics.measureBuildCommitmentProofDuration(startTime) bodyTree, err := merkle.NewTreeWithMaxLeaves[common.Root]( body.GetBlobKzgCommitments().Leafify(), constants.MaxBlobCommitmentsPerBlock, ) if err != nil { return nil, err } return bodyTree.MerkleProofWithMixin(index.Unwrap()) } ================================================ FILE: da/blob/factory_metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blob import ( "time" "github.com/berachain/beacon-kit/primitives/math" ) // factoryMetrics is a struct that contains metrics for the factory. type factoryMetrics struct { // TelemetrySink is the sink for the metrics. sink TelemetrySink } // newFactoryMetrics creates a new factoryMetrics. func newFactoryMetrics( sink TelemetrySink, ) *factoryMetrics { return &factoryMetrics{ sink: sink, } } // measureBuildSidecarsDuration measures the duration of the build sidecars. func (fm *factoryMetrics) measureBuildSidecarsDuration( startTime time.Time, numSidecars math.U64, ) { fm.sink.MeasureSince( "beacon_kit.da.blob.factory.build_sidecar_duration", startTime, "num_sidecars", numSidecars.Base10(), ) } // measureBuildKZGInclusionProofDuration measures the duration of the build KZG // inclusion proof. func (fm *factoryMetrics) measureBuildKZGInclusionProofDuration( startTime time.Time, ) { fm.sink.MeasureSince( "beacon_kit.da.blob.factory.build_kzg_inclusion_proof_duration", startTime, ) } // measureBuildBlockBodyProofDuration measures the duration of the build block // body proof. func (fm *factoryMetrics) measureBuildBlockBodyProofDuration( startTime time.Time, ) { fm.sink.MeasureSince( "beacon_kit.da.blob.factory.build_block_body_proof_duration", startTime, ) } // measureBuildCommitmentProofDuration measures the duration of the build // commitment proof. func (fm *factoryMetrics) measureBuildCommitmentProofDuration( startTime time.Time, ) { fm.sink.MeasureSince( "beacon_kit.da.blob.factory.build_commitment_proof_duration", startTime, ) } ================================================ FILE: da/blob/factory_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blob_test // TODO: Create a mock such that core/types doesn't need // to be imported here. // MockSpec is a mock implementation of the ChainSpec interface used for // testing. type MockSpec struct{} // MaxBlobCommitmentsPerBlock returns the maximum number of blob commitments per // block. // This mock implementation always returns 16. func (m *MockSpec) MaxBlobCommitmentsPerBlock() uint64 { return 16 } // TODO: Re-enable once we can easily decouple from core/types. // func TestBuildKZGInclusionProof(t *testing.T) { // chainspec := &MockSpec{} // factory := da.NewSidecarFactory[da.BeaconBlockBody]( // chainspec, // 5, // ) // body := mockBody() // // Test for a valid index // // index := uint64(0) // proof, err := factory.BuildKZGInclusionProof(body, index) // require.NoError( // t, // err, // "Building KZG inclusion proof should not produce an error", // ) // require.NotNil(t, proof, "Proof should not be nil") // bodyRoot, err := body.HashTreeRoot() // require.NoError(t, err, "Hashing the body should not produce an error") // // Verify the valid KZG inclusion proof // validProof := merkle.VerifyProof( // bodyRoot, // body.GetBlobKzgCommitments()[index].ToHashChunks()[0], // types.KZGOffset(chainspec.MaxBlobCommitmentsPerBlock())+index, // proof, // ) // require.True(t, validProof, "The KZG inclusion proof should be valid") // // Test for an invalid index // invalidIndex := uint64(100) // Assuming this is out of range // _, err = factory.BuildKZGInclusionProof(body, invalidIndex) // require.Error( // t, // err, // "Building KZG inclusion proof with invalid index should produce an error", // ) // require.True(t, validProof, "The KZG inclusion proof should be valid") // // Attempt to verify the invalid KZG inclusion proof and expect failure // invalidProof, err := factory.BuildKZGInclusionProof(body, invalidIndex) // require.Error( // t, // err, // "Building KZG inclusion proof should produce an error", // ) // validInvalidProof := merkle.VerifyProof( // bodyRoot, // body.GetBlobKzgCommitments()[index].ToHashChunks()[0], // types.KZGOffset(chainspec.MaxBlobCommitmentsPerBlock())+index, // invalidProof, // ) // require.False( // t, // validInvalidProof, // "The KZG inclusion proof for an invalid index should be invalid", // ) // } // func mockBody() da.BeaconBlockBody { // // Create a real ExecutionPayloadDeneb and BeaconBlockBody // executionPayload := &engineprimitives.ExecutionPayload{ // ParentHash: common.HexToHash("0x01"), // FeeRecipient: common.HexToAddress("0x02"), // StateRoot: common.HexToHash("0x03"), // ReceiptsRoot: common.HexToHash("0x04"), // LogsBloom: bytes.Repeat([]byte("b"), 256), // Random: common.HexToHash("0x05"), // BaseFeePerGas: math.Wei(bytes.Repeat([]byte("f"), 32)), // BlockHash: common.HexToHash("0x06"), // Transactions: [][]byte{[]byte("tx1"), []byte("tx2")}, // ExtraData: []byte("extra"), // } // return &types.BeaconBlockBodyDeneb{ // RandaoReveal: [96]byte{0x01}, // Eth1Data: &primitives.Eth1Data{ // DepositRoot: common.Root{}, // DepositCount: 0, // BlockHash: common.ZeroHash, // }, // ExecutionPayload: executionPayload, // BlobKzgCommitments: kzg.Commitments{ // [48]byte(bytes.Repeat([]byte{0x01}, 48)), // [48]byte(bytes.Repeat([]byte{0x10}, 48)), // [48]byte(bytes.Repeat([]byte{0x11}, 48)), // }, // } // } ================================================ FILE: da/blob/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blob import ( "time" ) // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { // MeasureSince measures the time since the provided start time, // identified by the provided keys. MeasureSince(key string, start time.Time, args ...string) } ================================================ FILE: da/blob/processor.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blob import ( "context" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/kzg" dastore "github.com/berachain/beacon-kit/da/store" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" ) // Processor is the blob processor that handles the processing and verification // of blob sidecars. type Processor struct { // logger is used to log information and errors. logger log.Logger // verifier is responsible for verifying the blobs. verifier *verifier // metrics is used to collect and report processor metrics. metrics *processorMetrics } // NewProcessor creates a new blob processor. func NewProcessor( logger log.Logger, proofVerifier kzg.BlobProofVerifier, telemetrySink TelemetrySink, ) *Processor { verifier := newVerifier(proofVerifier, telemetrySink) return &Processor{ logger: logger, verifier: verifier, metrics: newProcessorMetrics(telemetrySink), } } // VerifySidecars verifies the blobs and ensures they match the local state. func (sp *Processor) VerifySidecars( ctx context.Context, sidecars datypes.BlobSidecars, blkHeader *ctypes.BeaconBlockHeader, kzgCommitments eip4844.KZGCommitments[common.ExecutionHash], ) error { defer sp.metrics.measureVerifySidecarsDuration( time.Now(), math.U64(len(sidecars)), ) // Abort if there are no blobs to store. if len(sidecars) == 0 { return nil } // Verify the blobs and ensure they match the local state. return sp.verifier.verifySidecars( ctx, sidecars, blkHeader, kzgCommitments, ) } // ProcessSidecars processes the blobs and ensures they match the local state. func (sp *Processor) ProcessSidecars( avs *dastore.Store, sidecars datypes.BlobSidecars, ) error { defer sp.metrics.measureProcessSidecarsDuration( time.Now(), math.U64(len(sidecars)), ) // Abort if there are no blobs to store. if len(sidecars) == 0 { return nil } // If we have reached this point, we can safely assume that the blobs are // valid and can be persisted, as well as that index 0 is filled. return avs.Persist(sidecars) } ================================================ FILE: da/blob/processor_metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blob import ( "time" "github.com/berachain/beacon-kit/primitives/math" ) // processorMetrics is a struct that contains metrics for the processor. type processorMetrics struct { // TelemetrySink is the sink for the metrics. sink TelemetrySink } // newProcessorMetrics creates a new processorMetrics. func newProcessorMetrics( sink TelemetrySink, ) *processorMetrics { return &processorMetrics{ sink: sink, } } // measureVerifySidecarsDuration measures the duration of the blob verification. func (pm *processorMetrics) measureVerifySidecarsDuration( startTime time.Time, numSidecars math.U64, ) { pm.sink.MeasureSince( "beacon_kit.da.blob.processor.verify_blobs_duration", startTime, "num_sidecars", numSidecars.Base10(), ) } // measureProcessSidecarsDuration measures the duration of the blob processing. func (pm *processorMetrics) measureProcessSidecarsDuration( startTime time.Time, numSidecars math.U64, ) { pm.sink.MeasureSince( "beacon_kit.da.blob.processor.process_blob_duration", startTime, "num_sidecars", numSidecars.Base10(), ) } ================================================ FILE: da/blob/verifier.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blob import ( "context" "fmt" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/kzg" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "golang.org/x/sync/errgroup" ) // verifier is responsible for verifying blobs, including their // inclusion and KZG proofs. type verifier struct { // proofVerifier is used to verify the KZG proofs of the blobs. proofVerifier kzg.BlobProofVerifier // metrics collects and reports metrics related to the verification process. metrics *verifierMetrics } // newVerifier creates a new Verifier with the given proof verifier. func newVerifier( proofVerifier kzg.BlobProofVerifier, telemetrySink TelemetrySink, ) *verifier { return &verifier{ proofVerifier: proofVerifier, metrics: newVerifierMetrics(telemetrySink), } } // verifySidecars verifies the blobs for both inclusion as well // as the KZG proofs. func (bv *verifier) verifySidecars( ctx context.Context, sidecars datypes.BlobSidecars, blkHeader *ctypes.BeaconBlockHeader, kzgCommitments eip4844.KZGCommitments[common.ExecutionHash], ) error { numSidecars := uint64(len(sidecars)) defer bv.metrics.measureVerifySidecarsDuration( time.Now(), math.U64(numSidecars), bv.proofVerifier.GetImplementation(), ) g, _ := errgroup.WithContext(ctx) // Create lookup table for each blob sidecar commitment and indicies. blobSidecarCommitments := make(map[eip4844.KZGCommitment]struct{}) blobSidecarIndicies := make(map[uint64]struct{}) // Validate sidecar fields against data from the BeaconBlock. for i, s := range sidecars { // Fill lookup table with commitments from the blob sidecars. blobSidecarCommitments[s.GetKzgCommitment()] = struct{}{} // We should only have unique indexes. if _, exists := blobSidecarIndicies[s.GetIndex()]; exists { return fmt.Errorf("duplicate sidecar Index: %d", i) } blobSidecarIndicies[s.GetIndex()] = struct{}{} // This check happens outside the goroutines so that we do not // process the inclusion proofs before validating the index. if s.GetIndex() >= numSidecars { return fmt.Errorf("invalid sidecar Index: %d", i) } // Check BlobSidecar.Header equality with BeaconBlockHeader if !s.GetBeaconBlockHeader().Equals(blkHeader) { return fmt.Errorf("unequal block header: idx: %d", i) } } // Ensure each commitment from the BeaconBlock has a corresponding sidecar commitment. for _, kzgCommitment := range kzgCommitments { if _, exists := blobSidecarCommitments[kzgCommitment]; !exists { return fmt.Errorf("missing kzg commitment: %s", kzgCommitment) } } // Verify the inclusion proofs on the blobs concurrently. g.Go(func() error { return bv.verifyInclusionProofs(sidecars) }) // Verify the KZG proofs on the blobs concurrently. g.Go(func() error { return bv.verifyKZGProofs(sidecars) }) // Wait for all goroutines to finish and return the result. return g.Wait() } func (bv *verifier) verifyInclusionProofs( scs datypes.BlobSidecars, ) error { startTime := time.Now() defer bv.metrics.measureVerifyInclusionProofsDuration( startTime, math.U64(len(scs)), ) return scs.VerifyInclusionProofs() } // verifyKZGProofs verifies the sidecars. func (bv *verifier) verifyKZGProofs( scs datypes.BlobSidecars, ) error { start := time.Now() defer bv.metrics.measureVerifyKZGProofsDuration( start, math.U64(len(scs)), bv.proofVerifier.GetImplementation(), ) switch len(scs) { case 0: return nil case 1: blob := scs[0].GetBlob() // This method is fastest for a single blob. return bv.proofVerifier.VerifyBlobProof( &blob, scs[0].GetKzgProof(), scs[0].GetKzgCommitment(), ) default: // For multiple blobs batch verification is more performant // than verifying each blob individually (even when done in parallel). return bv.proofVerifier.VerifyBlobProofBatch(kzg.ArgsFromSidecars(scs)) } } ================================================ FILE: da/blob/verifier_metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package blob import ( "time" "github.com/berachain/beacon-kit/primitives/math" ) // verifierMetrics is a struct that contains metrics for the verifier. type verifierMetrics struct { // TelemetrySink is the sink for the metrics. sink TelemetrySink } // newVerifierMetrics creates a new verifierMetrics. func newVerifierMetrics( sink TelemetrySink, ) *verifierMetrics { return &verifierMetrics{ sink: sink, } } // measureVerifySidecarsDuration measures the duration of the blob verification. func (vm *verifierMetrics) measureVerifySidecarsDuration( startTime time.Time, numSidecars math.U64, kzgImplementation string, ) { vm.sink.MeasureSince( "beacon_kit.da.blob.verifier.verify_blobs_duration", startTime, "num_sidecars", numSidecars.Base10(), "kzg_implementation", kzgImplementation, ) } // measureVerifyInclusionProofsDuration measures the duration of the inclusion // proofs verification. func (vm *verifierMetrics) measureVerifyInclusionProofsDuration( startTime time.Time, numSidecars math.U64, ) { vm.sink.MeasureSince( "beacon_kit.da.blob.verifier.verify_inclusion_proofs_duration", startTime, "num_sidecars", numSidecars.Base10(), ) } // measureVerifyKZGProofsDuration measures the duration of the KZG proofs // verification. func (vm *verifierMetrics) measureVerifyKZGProofsDuration( startTime time.Time, numSidecars math.U64, kzgImplementation string, ) { vm.sink.MeasureSince( "beacon_kit.da.blob.verifier.verify_kzg_proofs_duration", startTime, "num_sidecars", numSidecars.Base10(), "kzg_implementation", kzgImplementation, ) } ================================================ FILE: da/kzg/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package kzg const ( // defaultTrustedSetupPath is the default path to the trusted setup. defaultTrustedSetupPath = "./testing/files/kzg-trusted-setup.json" // defaultImplementation is the default KZG implementation to use. // Options are `crate-crypto/go-kzg-4844`. defaultImplementation = "crate-crypto/go-kzg-4844" ) type Config struct { // TrustedSetupPath is the path to the trusted setup. TrustedSetupPath string `mapstructure:"trusted-setup-path"` // Implementation is the KZG implementation to use. Implementation string `mapstructure:"implementation"` } // DefaultConfig returns the default configuration. func DefaultConfig() Config { return Config{ TrustedSetupPath: defaultTrustedSetupPath, Implementation: defaultImplementation, } } ================================================ FILE: da/kzg/config_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package kzg_test import ( "testing" "github.com/berachain/beacon-kit/da/kzg" "github.com/stretchr/testify/require" ) func TestDefaultConfig(t *testing.T) { t.Parallel() cfg := kzg.DefaultConfig() require.Equal( t, "./testing/files/kzg-trusted-setup.json", cfg.TrustedSetupPath, ) require.Equal( t, "crate-crypto/go-kzg-4844", cfg.Implementation, ) } ================================================ FILE: da/kzg/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package kzg import "github.com/berachain/beacon-kit/errors" var ( // ErrUnsupportedKzgImplementation is returned when an unsupported KZG // implementation is requested. ErrUnsupportedKzgImplementation = errors.New( "unsupported KZG implementation", ) ) ================================================ FILE: da/kzg/gokzg/gokzg.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package gokzg import ( "unsafe" "github.com/berachain/beacon-kit/da/kzg/types" "github.com/berachain/beacon-kit/primitives/eip4844" gokzg4844 "github.com/crate-crypto/go-kzg-4844" ) const Implementation = "crate-crypto/go-kzg-4844" // Verifier is a KZG verifier that uses the Go implementation of KZG. type Verifier struct { *gokzg4844.Context } // NewVerifier creates a new GoKZGVerifier. func NewVerifier(ts *gokzg4844.JSONTrustedSetup) (*Verifier, error) { ctx, err := gokzg4844.NewContext4096(ts) if err != nil { return nil, err } return &Verifier{ctx}, nil } // GetImplementation returns the implementation of the verifier. func (v Verifier) GetImplementation() string { return Implementation } // VerifyBlobProof verifies the KZG proof that the polynomial represented by the // blob evaluated at the given point is the claimed value. func (v Verifier) VerifyBlobProof( blob *eip4844.Blob, proof eip4844.KZGProof, commitment eip4844.KZGCommitment, ) error { return v.Context. VerifyBlobKZGProof( (*gokzg4844.Blob)(blob), (gokzg4844.KZGCommitment)(commitment), (gokzg4844.KZGProof)(proof)) } // VerifyBlobProofBatch verifies the KZG proof that the polynomial represented // by the blob evaluated at the given point is the claimed value. // It is more efficient than VerifyBlobProof when verifying multiple proofs. func (v Verifier) VerifyBlobProofBatch( args *types.BlobProofArgs, ) error { blobs := make([]gokzg4844.Blob, len(args.Blobs)) for i := range args.Blobs { blobs[i] = *(*gokzg4844.Blob)(args.Blobs[i]) } //#nosec:G103 // "use of unsafe calls should be audited" lmeow. return v.Context. VerifyBlobKZGProofBatch( blobs, *(*[]gokzg4844.KZGCommitment)( unsafe.Pointer(&args.Commitments)), *(*[]gokzg4844.KZGProof)(unsafe.Pointer(&args.Proofs)), ) } ================================================ FILE: da/kzg/gokzg/gokzg_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package gokzg_test import ( "path/filepath" "testing" "github.com/berachain/beacon-kit/da/kzg/gokzg" "github.com/berachain/beacon-kit/da/kzg/types" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/encoding/json" gokzg4844 "github.com/crate-crypto/go-kzg-4844" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) var baseDir = "../../../testing/files/" func TestVerifyBlobProof(t *testing.T) { t.Parallel() verifier, err := setupVerifier() require.NoError(t, err) validBlob, validProof, validCommitment := setupTestData( t, "test_data.json") testCases := []struct { name string blob *eip4844.Blob proof eip4844.KZGProof commitment eip4844.KZGCommitment expectError bool }{ { name: "Valid Proof", blob: validBlob, proof: validProof, commitment: validCommitment, expectError: false, }, { name: "Short buffer for commitment", blob: &eip4844.Blob{}, proof: eip4844.KZGProof{}, commitment: eip4844.KZGCommitment{}, expectError: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() errVerify := verifier.VerifyBlobProof( tc.blob, tc.proof, tc.commitment, ) if tc.expectError { require.Error(t, errVerify) } else { require.NoError(t, errVerify) } }) } } // TestVerifyBlobProofBatch tests the VerifyBlobProofBatch function // for valid proofs. func TestVerifyBlobProofBatch(t *testing.T) { t.Parallel() // Load the test data verifier, err := setupVerifier() require.NoError(t, err) fs := afero.NewOsFs() fullPath := filepath.Join(baseDir, "test_data_batch.json") file, err := afero.ReadFile(fs, fullPath) require.NoError(t, err) // Unmarshal the JSON data var data struct { Blobs []string `json:"blobs"` Proofs []string `json:"proofs"` Commitments []string `json:"commitments"` } err = json.Unmarshal(file, &data) require.NoError(t, err) // Convert the data to the types expected by VerifyBlobProofBatch args := &types.BlobProofArgs{ Blobs: make([]*eip4844.Blob, len(data.Blobs)), Proofs: make([]eip4844.KZGProof, len(data.Proofs)), Commitments: make([]eip4844.KZGCommitment, len(data.Commitments)), } for i := range data.Blobs { var blob eip4844.Blob err = blob.UnmarshalJSON([]byte(`"` + data.Blobs[i] + `"`)) require.NoError(t, err) args.Blobs[i] = &blob var proof eip4844.KZGProof err = proof.UnmarshalJSON([]byte(`"` + data.Proofs[i] + `"`)) require.NoError(t, err) args.Proofs[i] = proof var commitment eip4844.KZGCommitment err = commitment.UnmarshalJSON([]byte(`"` + data.Commitments[i] + `"`)) require.NoError(t, err) args.Commitments[i] = commitment } err = verifier.VerifyBlobProofBatch(args) require.NoError(t, err) } func TestGetImplementation(t *testing.T) { t.Parallel() verifier, err := setupVerifier() require.NoError(t, err) impl := verifier.GetImplementation() require.Equal(t, gokzg.Implementation, impl) } // setupVerifier reads the trusted setup file and creates a new GoKZGVerifier. func setupVerifier() (*gokzg.Verifier, error) { fs := afero.NewOsFs() fileName := "kzg-trusted-setup.json" fullPath := filepath.Join(baseDir, fileName) file, err := afero.ReadFile(fs, fullPath) if err != nil { return nil, err } var ts gokzg4844.JSONTrustedSetup if errUnmarshal := json.Unmarshal(file, &ts); errUnmarshal != nil { return nil, errUnmarshal } verifier, errVerifier := gokzg.NewVerifier(&ts) if errVerifier != nil { return nil, errVerifier } return verifier, nil } func setupTestData(t *testing.T, fileName string) ( *eip4844.Blob, eip4844.KZGProof, eip4844.KZGCommitment, ) { t.Helper() filePath := filepath.Join(baseDir, fileName) data, err := afero.ReadFile(afero.NewOsFs(), filePath) require.NoError(t, err) type Test struct { Input struct { Blob string `json:"blob"` Commitment string `json:"commitment"` Proof string `json:"proof"` } `json:"input"` } var test Test err = json.Unmarshal(data, &test) require.NoError(t, err) var blob eip4844.Blob errBlob := blob.UnmarshalJSON([]byte(`"` + test.Input.Blob + `"`)) require.NoError(t, errBlob) var commitment eip4844.KZGCommitment errCommitment := commitment.UnmarshalJSON([]byte( `"` + test.Input.Commitment + `"`)) require.NoError(t, errCommitment) var proof eip4844.KZGProof errProof := proof.UnmarshalJSON([]byte(`"` + test.Input.Proof + `"`)) require.NoError(t, errProof) return &blob, proof, commitment } ================================================ FILE: da/kzg/noop/noop.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package noop import ( "github.com/berachain/beacon-kit/da/kzg/types" "github.com/berachain/beacon-kit/primitives/eip4844" ) // Verifier is a no-op KZG proof verifier. type Verifier struct{} // NewVerifier creates a new GoKZGVerifier. func NewVerifier() *Verifier { return &Verifier{} } // GetImplementation returns the implementation of the verifier. func (v Verifier) GetImplementation() string { return "noop" } // VerifyBlobProof is a no-op. func (v Verifier) VerifyBlobProof( *eip4844.Blob, eip4844.KZGProof, eip4844.KZGCommitment, ) error { return nil } // VerifyBlobProofBatch is a no-op. func (v Verifier) VerifyBlobProofBatch( *types.BlobProofArgs, ) error { return nil } ================================================ FILE: da/kzg/noop/noop_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package noop_test import ( "testing" "github.com/berachain/beacon-kit/da/kzg/noop" "github.com/berachain/beacon-kit/da/kzg/types" "github.com/berachain/beacon-kit/primitives/eip4844" ) func TestVerifyBlobProof(t *testing.T) { t.Parallel() verifier := noop.NewVerifier() err := verifier.VerifyBlobProof( &eip4844.Blob{}, eip4844.KZGProof{}, eip4844.KZGCommitment{}, ) if err != nil { t.Fatalf("expected no error, got %v", err) } } func TestVerifyBlobProofBatch(t *testing.T) { t.Parallel() verifier := noop.NewVerifier() args := &types.BlobProofArgs{ Blobs: []*eip4844.Blob{{}}, Proofs: []eip4844.KZGProof{{}}, Commitments: []eip4844.KZGCommitment{{}}, } err := verifier.VerifyBlobProofBatch(args) if err != nil { t.Fatalf("expected no error, got %v", err) } } ================================================ FILE: da/kzg/proof.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package kzg import ( "github.com/berachain/beacon-kit/da/kzg/gokzg" kzgtypes "github.com/berachain/beacon-kit/da/kzg/types" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/eip4844" gokzg4844 "github.com/crate-crypto/go-kzg-4844" ) // BlobProofVerifier is a verifier for blobs. type BlobProofVerifier interface { // GetImplementation returns the implementation of the verifier. GetImplementation() string // VerifyBlobProof verifies that the blob data corresponds to the provided // commitment. VerifyBlobProof( blob *eip4844.Blob, proof eip4844.KZGProof, commitment eip4844.KZGCommitment, ) error // VerifyBlobProofBatch verifies the KZG proof that the polynomial // represented // by the blob evaluated at the given point is the claimed value. // For most implementations it is more efficient than VerifyBlobProof when // verifying multiple proofs. VerifyBlobProofBatch(*kzgtypes.BlobProofArgs) error } // NewBlobProofVerifier creates a new BlobVerifier with the given // implementation. func NewBlobProofVerifier( impl string, ts *gokzg4844.JSONTrustedSetup, ) (BlobProofVerifier, error) { switch impl { case gokzg.Implementation: return gokzg.NewVerifier(ts) default: return nil, errors.Wrapf( ErrUnsupportedKzgImplementation, "supplied: %s, supported: %s", impl, gokzg.Implementation, ) } } // ArgsFromSidecars converts a BlobSidecars to a slice of BlobProofArgs. func ArgsFromSidecars( scs datypes.BlobSidecars, ) *kzgtypes.BlobProofArgs { proofArgs := &kzgtypes.BlobProofArgs{ Blobs: make([]*eip4844.Blob, len(scs)), Proofs: make([]eip4844.KZGProof, len(scs)), Commitments: make([]eip4844.KZGCommitment, len(scs)), } for i, sidecar := range scs { blob := sidecar.GetBlob() proofArgs.Blobs[i] = &blob proofArgs.Proofs[i] = sidecar.GetKzgProof() proofArgs.Commitments[i] = sidecar.GetKzgCommitment() } return proofArgs } ================================================ FILE: da/kzg/proof_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package kzg_test import ( "os" "path/filepath" "testing" "github.com/berachain/beacon-kit/da/kzg" "github.com/berachain/beacon-kit/da/kzg/gokzg" "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/encoding/json" gokzg4844 "github.com/crate-crypto/go-kzg-4844" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) var baseDir = "../../testing/files/" func TestNewBlobProofVerifier_KzgImpl(t *testing.T) { t.Parallel() ts, err := loadTrustedSetupFromFile() require.NoError(t, err) verifier, err := kzg.NewBlobProofVerifier(gokzg.Implementation, ts) require.NoError(t, err) require.NotNil(t, verifier) require.Equal(t, gokzg.Implementation, verifier.GetImplementation()) } func TestNewBlobProofVerifier_InvalidImpl(t *testing.T) { t.Parallel() ts, err := loadTrustedSetupFromFile() require.NoError(t, err) invalidImpl := "invalid-implementation" _, err = kzg.NewBlobProofVerifier(invalidImpl, ts) require.ErrorIs(t, err, kzg.ErrUnsupportedKzgImplementation) } // loadTrustedSetupFromFile is the helper function. func loadTrustedSetupFromFile() (*gokzg4844.JSONTrustedSetup, error) { fileName := "kzg-trusted-setup.json" fullPath := filepath.Join(baseDir, fileName) data, err := os.ReadFile(fullPath) if err != nil { return nil, err } var ts gokzg4844.JSONTrustedSetup err = json.Unmarshal(data, &ts) if err != nil { return nil, err } return &ts, nil } func TestArgsFromSidecars(t *testing.T) { t.Parallel() fs := afero.NewOsFs() fullPath := filepath.Join(baseDir, "test_data.json") file, err := afero.ReadFile(fs, fullPath) require.NoError(t, err) type Data struct { Input struct { Blob string `json:"blob"` Commitment string `json:"commitment"` Proof string `json:"proof"` } `json:"input"` } var data Data err = json.Unmarshal(file, &data) require.NoError(t, err) scs := types.BlobSidecars{ { Blob: eip4844.Blob{data.Input.Blob[0]}, KzgProof: eip4844.KZGProof{data.Input.Proof[0]}, KzgCommitment: eip4844.KZGCommitment{data.Input.Commitment[0]}, }, } args := kzg.ArgsFromSidecars(scs) require.Len(t, args.Blobs, 1) require.Len(t, args.Proofs, 1) require.Len(t, args.Commitments, 1) } ================================================ FILE: da/kzg/types/args.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/eip4844" ) // BlobProofArgs represents the arguments for a blob proof. type BlobProofArgs struct { // Blob is the blob. Blobs []*eip4844.Blob // Proof is the KZG proof. Proofs []eip4844.KZGProof // Commitment is the KZG commitment. Commitments []eip4844.KZGCommitment } ================================================ FILE: da/store/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package store import "github.com/berachain/beacon-kit/errors" var ( // ErrAttemptedToStoreNilSidecar is returned when an attempt is made to // store a // nil sidecar. ErrAttemptedToStoreNilSidecar = errors.New("attempted to store nil sidecar") // ErrAttemptedToVerifyNilSidecars is returned when an attempt is made to // verify // nil sidecars. ErrAttemptedToVerifyNilSidecars = errors.New( "attempted to verify nil sidecars", ) ) ================================================ FILE: da/store/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package store // IndexDB is a database that allows prefixing by index. type IndexDB interface { Has(index uint64, key []byte) (bool, error) Get(index uint64, key []byte) ([]byte, error) Set(index uint64, key []byte, value []byte) error // Prune returns error if start > end. Prune(start uint64, end uint64) error // GetByIndex takes the database index and returns all associated entries, // expecting database keys to follow the prefix() format. If index does not // exist in the DB for any reason (pruned, invalid index), an empty list is // returned with no error. GetByIndex(index uint64) ([][]byte, error) // DeleteByIndex removes all entries at the specified index DeleteByIndex(index uint64) error } ================================================ FILE: da/store/store.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package store import ( "context" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" ) // Store is the default implementation of the AvailabilityStore. type Store struct { // IndexDB is a basic database interface. IndexDB // logger is used for logging. logger log.Logger } // New creates a new instance of the AvailabilityStore. func New( db IndexDB, logger log.Logger, ) *Store { return &Store{ IndexDB: db, logger: logger, } } // IsDataAvailable ensures that all blobs referenced in the block are // stored before it returns without an error. func (s *Store) IsDataAvailable( _ context.Context, slot math.Slot, body *ctypes.BeaconBlockBody, ) bool { for _, commitment := range body.GetBlobKzgCommitments() { // Check if the block data is available in the IndexDB blockData, err := s.IndexDB.Has(slot.Unwrap(), commitment[:]) if err != nil || !blockData { return false } } return true } // GetBlobSidecars fetches the sidecars for a specific slot. func (s *Store) GetBlobSidecars(slot math.Slot) (types.BlobSidecars, error) { sidecarBzs, err := s.IndexDB.GetByIndex(slot.Unwrap()) if err != nil { return nil, err } sidecars := make(types.BlobSidecars, 0, len(sidecarBzs)) for _, sidecarBz := range sidecarBzs { sidecar := new(types.BlobSidecar) if err = ssz.Unmarshal(sidecarBz, sidecar); err != nil { return sidecars, err } sidecars = append(sidecars, sidecar) } return sidecars, nil } // Persist ensures the sidecar data remains accessible, utilizing parallel // processing for efficiency. func (s *Store) Persist(sidecars types.BlobSidecars) error { var slot math.Slot // Store each sidecar sequentially. The store's underlying RangeDB is not // built to handle concurrent writes. for _, sidecar := range sidecars { if sidecar == nil { return ErrAttemptedToStoreNilSidecar } bz, err := sidecar.MarshalSSZ() if err != nil { return err } slot = sidecar.GetBeaconBlockHeader().GetSlot() err = s.IndexDB.Set(slot.Unwrap(), sidecar.KzgCommitment[:], bz) if err != nil { return err } } // Slots should all be the same at this point. Just use the slot from the // last sidecar. s.logger.Info("Successfully stored all blob sidecars 🚗", "slot", slot.Base10(), "num_sidecars", len(sidecars), ) return nil } // DeleteBlobSidecars removes all blob sidecars for the specified slot. func (s *Store) DeleteBlobSidecars(slot math.Slot) error { return s.IndexDB.DeleteByIndex(slot.Unwrap()) } ================================================ FILE: da/store/store_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package store_test import ( "testing" "cosmossdk.io/log" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/store" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/storage/filedb" "github.com/stretchr/testify/require" ) func setSlot(scs datypes.BlobSidecars, slot math.Slot) { for _, sc := range scs { hdr := sc.GetBeaconBlockHeader() hdr.SetSlot(slot) } } func TestStore_PersistRace(t *testing.T) { t.Parallel() // This test case needs to be run with the '-race' flag tmpFilePath := t.TempDir() logger := log.NewNopLogger() // Create the DB s := store.New( filedb.NewRangeDB( filedb.NewDB(filedb.WithRootDirectory(tmpFilePath), filedb.WithFileExtension("ssz"), filedb.WithDirectoryPermissions(0700), filedb.WithLogger(logger), ), ), logger.With("service", "da-store"), ) // This many blobs is not currently possible, but it doesn't hurt eh sc := make([]*datypes.BlobSidecar, 20) for i := range sc { sc[i] = &datypes.BlobSidecar{ Index: uint64(i), SignedBeaconBlockHeader: &types.SignedBeaconBlockHeader{ Header: &types.BeaconBlockHeader{}, }, InclusionProof: make([]common.Root, types.KZGInclusionProofDepth), } } var sidecars datypes.BlobSidecars = sc // Multiple writes to DB setSlot(sidecars, 0) err := s.Persist(sidecars) require.NoError(t, err) setSlot(sidecars, 1) err = s.Persist(sidecars) require.NoError(t, err) // Pruning here primes the race condition for db.firstNonNilIndex err = s.Prune(0, 1) require.NoError(t, err) setSlot(sidecars, 0) err = s.Persist(sidecars) require.NoError(t, err) } ================================================ FILE: da/types/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import "github.com/berachain/beacon-kit/errors" var ( // ErrSidecarContainsDifferingBlockRoots is returned when a sidecar contains // blobs with differing block roots. ErrSidecarContainsDifferingBlockRoots = errors.New( "sidecar contains blobs with differing block roots") // ErrAttemptedToVerifyNilSidecar is returned when // an attempt is made to store a nil sidecar. ErrAttemptedToVerifyNilSidecar = errors.New( "attempted to verify nil sidecar", ) // ErrInvalidInclusionProof is returned when an invalid KZG commitment // inclusion. ErrInvalidInclusionProof = errors.New( "invalid KZG commitment inclusion proof") ) ================================================ FILE: da/types/sidecar.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/merkle" "github.com/karalabe/ssz" ) // Compile-time assertions to ensure BlobSidecar implements necessary interfaces. var ( _ ssz.StaticObject = (*BlobSidecar)(nil) _ constraints.SSZMarshallableRootable = (*BlobSidecar)(nil) ) // BlobSidecar as per the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/p2p-interface.md#blobsidecar // // NOTE: This struct is only ever (un)marshalled with SSZ and NOT with JSON. type BlobSidecar struct { // Index represents the index of the blob in the block. Index uint64 // Blob represents the blob data. Blob eip4844.Blob // KzgCommitment is the KZG commitment of the blob. KzgCommitment eip4844.KZGCommitment // Kzg proof allows folr the verification of the KZG commitment. KzgProof eip4844.KZGProof // BeaconBlockHeader represents the beacon block header for which this blob // is being included. SignedBeaconBlockHeader *ctypes.SignedBeaconBlockHeader // InclusionProof is the inclusion proof of the blob in the beacon block // body. InclusionProof []common.Root } // BuildBlobSidecar creates a blob sidecar from the given blobs and // beacon block. func BuildBlobSidecar( index math.U64, header *ctypes.SignedBeaconBlockHeader, blob *eip4844.Blob, commitment eip4844.KZGCommitment, proof eip4844.KZGProof, inclusionProof []common.Root, ) *BlobSidecar { return &BlobSidecar{ Index: index.Unwrap(), Blob: *blob, KzgCommitment: commitment, KzgProof: proof, SignedBeaconBlockHeader: header, InclusionProof: inclusionProof, } } // HasValidInclusionProof verifies the inclusion proof of the // blob in the beacon body. func (b *BlobSidecar) HasValidInclusionProof() bool { header := b.GetBeaconBlockHeader() return header != nil && merkle.IsValidMerkleBranch( b.KzgCommitment.HashTreeRoot(), b.InclusionProof, ctypes.KZGInclusionProofDepth, ctypes.KZGOffset+b.Index, header.BodyRoot, ) } /* -------------------------------------------------------------------------- */ /* Getters */ /* -------------------------------------------------------------------------- */ func (b *BlobSidecar) GetIndex() uint64 { return b.Index } func (b *BlobSidecar) GetBlob() eip4844.Blob { return b.Blob } func (b *BlobSidecar) GetKzgProof() eip4844.KZGProof { return b.KzgProof } func (b *BlobSidecar) GetKzgCommitment() eip4844.KZGCommitment { return b.KzgCommitment } func (b *BlobSidecar) GetBeaconBlockHeader() *ctypes.BeaconBlockHeader { return b.SignedBeaconBlockHeader.Header } func (b *BlobSidecar) GetInclusionProof() []common.Root { return b.InclusionProof } func (b *BlobSidecar) GetSignature() crypto.BLSSignature { return b.SignedBeaconBlockHeader.Signature } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // DefineSSZ defines the SSZ encoding for the BlobSidecar object. func (b *BlobSidecar) DefineSSZ(codec *ssz.Codec) { ssz.DefineUint64(codec, &b.Index) ssz.DefineStaticBytes(codec, &b.Blob) ssz.DefineStaticBytes(codec, &b.KzgCommitment) ssz.DefineStaticBytes(codec, &b.KzgProof) ssz.DefineStaticObject(codec, &b.SignedBeaconBlockHeader) ssz.DefineCheckedArrayOfStaticBytes(codec, &b.InclusionProof, ctypes.KZGInclusionProofDepth) } // SizeSSZ returns the size of the BlobSidecar object in SSZ encoding. // TODO: get from accessible chainspec field params. func (b *BlobSidecar) SizeSSZ(sizer *ssz.Sizer) uint32 { ssize := (*ctypes.SignedBeaconBlockHeader)(nil).SizeSSZ(sizer) return 8 + // Index 131072 + // Blob 48 + // KzgCommitment 48 + // KzgProof ssize + // SignedBeaconBlockHeader ctypes.KZGInclusionProofDepth*32 // InclusionProof } // MarshalSSZ marshals the BlobSidecar object to SSZ format. func (b *BlobSidecar) MarshalSSZ() ([]byte, error) { if len(b.InclusionProof) != ctypes.KZGInclusionProofDepth { return []byte{}, errors.New("invalid inclusion proof length") } buf := make([]byte, ssz.Size(b)) return buf, ssz.EncodeToBytes(buf, b) } func (b *BlobSidecar) ValidateAfterDecodingSSZ() error { // Verify inclusion proof length if len(b.InclusionProof) != ctypes.KZGInclusionProofDepth { return fmt.Errorf("invalid inclusion proof length, got %d, expect %d", b.InclusionProof, ctypes.KZGInclusionProofDepth, ) } // Ensure SignedBeaconBlockHeader is not nil if b.SignedBeaconBlockHeader == nil { b.SignedBeaconBlockHeader = &ctypes.SignedBeaconBlockHeader{} } return nil } // MarshalSSZTo marshals the BlobSidecar object to the provided buffer in SSZ // format. func (b *BlobSidecar) MarshalSSZTo(buf []byte) ([]byte, error) { return buf, ssz.EncodeToBytes(buf, b) } // HashTreeRoot computes the SSZ hash tree root of the BlobSidecar object. func (b *BlobSidecar) HashTreeRoot() common.Root { return ssz.HashSequential(b) } ================================================ FILE: da/types/sidecar_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "strconv" "testing" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/blob" "github.com/berachain/beacon-kit/da/types" byteslib "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/math/log" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/testing/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSidecarMarshalling(t *testing.T) { t.Parallel() // Create a sample BlobSidecar blob := eip4844.Blob{} for i := range blob { blob[i] = byte(i % 256) } inclusionProof := make([]common.Root, 0, ctypes.KZGInclusionProofDepth) for i := 1; i <= ctypes.KZGInclusionProofDepth; i++ { it := byteslib.ExtendToSize([]byte(strconv.Itoa(i)), byteslib.B32Size) proof, errBytes := byteslib.ToBytes32(it) require.NoError(t, errBytes) inclusionProof = append(inclusionProof, common.Root(proof)) } sidecar := types.BuildBlobSidecar( 1, &ctypes.SignedBeaconBlockHeader{ Header: &ctypes.BeaconBlockHeader{}, Signature: crypto.BLSSignature{}, }, &blob, eip4844.KZGCommitment{}, eip4844.KZGProof{}, inclusionProof, ) // Marshal the sidecar marshalled, err := sidecar.MarshalSSZ() require.NoError(t, err, "Marshalling should not produce an error") require.NotNil(t, marshalled, "Marshalling should produce a result") // Unmarshal the sidecar unmarshalled := new(types.BlobSidecar) err = ssz.Unmarshal(marshalled, unmarshalled) require.NoError(t, err, "Unmarshalling should not produce an error") // Compare the original and unmarshalled sidecars assert.Equal( t, sidecar, unmarshalled, "The original and unmarshalled sidecars should be equal", ) } type InclusionSink struct{} func (is InclusionSink) MeasureSince(_ string, _ time.Time, _ ...string) {} func TestHasValidInclusionProof(t *testing.T) { t.Parallel() sink := InclusionSink{} tests := []struct { name string sidecars func(t *testing.T) types.BlobSidecars expectedResult bool }{ { name: "Invalid inclusion proof", sidecars: func(t *testing.T) types.BlobSidecars { t.Helper() inclusionProof := make([]common.Root, 0) for i := 1; i <= ctypes.KZGInclusionProofDepth; i++ { it := byteslib.ExtendToSize( []byte(strconv.Itoa(i)), byteslib.B32Size, ) proof, err2 := byteslib.ToBytes32(it) require.NoError(t, err2) inclusionProof = append(inclusionProof, common.Root(proof)) } return types.BlobSidecars{types.BuildBlobSidecar( math.U64(0), &ctypes.SignedBeaconBlockHeader{ Header: &ctypes.BeaconBlockHeader{ BodyRoot: [32]byte{3}, }, Signature: crypto.BLSSignature{}, }, &eip4844.Blob{}, eip4844.KZGCommitment{}, eip4844.KZGProof{}, inclusionProof, )} }, expectedResult: false, }, { name: "Empty inclusion proof", sidecars: func(*testing.T) types.BlobSidecars { return types.BlobSidecars{types.BuildBlobSidecar( math.U64(0), &ctypes.SignedBeaconBlockHeader{}, &eip4844.Blob{}, eip4844.KZGCommitment{}, eip4844.KZGProof{}, []common.Root{}, )} }, expectedResult: false, }, { name: "Valid inclusion proof", sidecars: func(t *testing.T) types.BlobSidecars { t.Helper() block := utils.GenerateValidBeaconBlock(t, version.Electra()) sidecarFactory := blob.NewSidecarFactory(sink) numBlobs := len(block.GetBody().GetBlobKzgCommitments()) sidecars := make(types.BlobSidecars, numBlobs) for i := range numBlobs { inclusionProof, incErr := sidecarFactory.BuildKZGInclusionProof( block.GetBody(), math.U64(i), ) require.NoError(t, incErr) sigHeader := ctypes.NewSignedBeaconBlockHeader(block.GetHeader(), crypto.BLSSignature{}) sidecars[i] = types.BuildBlobSidecar( math.U64(i), sigHeader, &eip4844.Blob{}, block.GetBody().BlobKzgCommitments[i], eip4844.KZGProof{}, inclusionProof, ) } return sidecars }, expectedResult: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() sidecars := tt.sidecars(t) for _, sidecar := range sidecars { result := sidecar.HasValidInclusionProof() require.Equal(t, tt.expectedResult, result, "Result should match expected value") } }) } } // Test taken from Prysm: // https://github.com/prysmaticlabs/prysm/blob/6ce6b869e54c2f98fab5cc836a24e493df19ec49/consensus-types/blocks/kzg_test.go#L107-L120 // This test explains the calculation of the KZG commitment root's Merkle index // in the Body's Merkle tree based on the index of the KZG commitment list in the Body. func Test_KZGRootIndex(t *testing.T) { t.Parallel() // Level of the KZG commitment root's parent. kzgParentRootLevel := log.ILog2Ceil(ctypes.KZGPosition) require.NotEqual(t, 0, kzgParentRootLevel) // Merkle index of the KZG commitment root's parent. // The parent's left child is the KZG commitment root, // and its right child is the KZG commitment size. kzgParentRootIndex := ctypes.KZGPosition + (1 << kzgParentRootLevel) require.Equal(t, uint64(ctypes.KZGGeneralizedIndex), kzgParentRootIndex) // The KZG commitment root is the left child of its parent. // Its Merkle index is the double of its parent's Merkle index. require.Equal(t, 2*kzgParentRootIndex, uint64(ctypes.KZGRootIndex)) } func TestHashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string sidecar func(t *testing.T) *types.BlobSidecar expectedResult common.Root expectError bool }{ { name: "Valid BlobSidecar", sidecar: func(t *testing.T) *types.BlobSidecar { t.Helper() inclusionProof := make([]common.Root, 0) for i := int(1); i <= 8; i++ { it := byteslib.ExtendToSize( []byte(strconv.Itoa(i)), byteslib.B32Size, ) proof, err := byteslib.ToBytes32(it) require.NoError(t, err) inclusionProof = append(inclusionProof, common.Root(proof)) } return types.BuildBlobSidecar( math.U64(1), &ctypes.SignedBeaconBlockHeader{ Header: &ctypes.BeaconBlockHeader{ BodyRoot: [32]byte{7, 8, 9}, }, Signature: crypto.BLSSignature{0xde, 0xad}, }, &eip4844.Blob{0, 1, 2, 3, 4, 5, 6, 7}, eip4844.KZGCommitment{1, 2, 3}, eip4844.KZGProof{4, 5, 6}, inclusionProof, ) }, expectedResult: [32]uint8{ 0xd8, 0xb2, 0x91, 0x39, 0x93, 0x75, 0x38, 0x1f, 0xd4, 0xdf, 0xef, 0xa7, 0x16, 0x91, 0xd9, 0x9, 0x3, 0x62, 0xee, 0x3a, 0x79, 0x96, 0x57, 0xc4, 0xc4, 0x6d, 0x86, 0x79, 0x78, 0x1b, 0xb4, 0xe3, }, expectError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.NotPanics(t, func() { sidecar := tt.sidecar(t) result := sidecar.HashTreeRoot() require.Equal( t, tt.expectedResult, result, "HashTreeRoot result should match expected value", ) }, "HashTreeRoot should not panic") }) } } ================================================ FILE: da/types/sidecars.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" "github.com/sourcegraph/conc/iter" ) // Compile-time check to ensure BlobSidecars implements the necessary interfaces. var ( _ ssz.DynamicObject = (*BlobSidecars)(nil) _ constraints.SSZMarshallable = (*BlobSidecars)(nil) ) // Sidecars is a slice of blob side cars to be included in the block. type BlobSidecars []*BlobSidecar // ValidateBlockRoots checks to make sure that // all blobs in the sidecar are from the same block. func (bs *BlobSidecars) ValidateBlockRoots() error { if bs == nil { return ErrAttemptedToVerifyNilSidecar } sidecars := *bs // We only need to check if there is more than // a single blob in the sidecar. if len(sidecars) > 1 { firstHtr := sidecars[0].SignedBeaconBlockHeader.HashTreeRoot() for i := 1; i < len(sidecars); i++ { if firstHtr != sidecars[i].SignedBeaconBlockHeader.HashTreeRoot() { return ErrSidecarContainsDifferingBlockRoots } } } return nil } // VerifyInclusionProofs verifies the inclusion proofs for all sidecars. func (bs *BlobSidecars) VerifyInclusionProofs() error { return errors.Join(iter.Map( *bs, func(sidecar **BlobSidecar) error { sc := *sidecar if sc == nil { return ErrAttemptedToVerifyNilSidecar } // Verify the KZG inclusion proof. if !sc.HasValidInclusionProof() { return ErrInvalidInclusionProof } return nil }, )...) } // DefineSSZ defines the SSZ encoding for the BlobSidecars object. func (bs *BlobSidecars) DefineSSZ(codec *ssz.Codec) { ssz.DefineSliceOfStaticObjectsOffset( codec, (*[]*BlobSidecar)(bs), constants.MaxBlobSidecarsPerBlock, ) ssz.DefineSliceOfStaticObjectsContent( codec, (*[]*BlobSidecar)(bs), constants.MaxBlobSidecarsPerBlock, ) } // SizeSSZ returns the size of the BlobSidecars object in SSZ encoding. func (bs *BlobSidecars) SizeSSZ(siz *ssz.Sizer, fixed bool) uint32 { if fixed { return constants.SSZOffsetSize } return constants.SSZOffsetSize + ssz.SizeSliceOfStaticObjects(siz, *bs) } // MarshalSSZ marshals the BlobSidecars object to SSZ format. func (bs *BlobSidecars) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(bs)) return buf, ssz.EncodeToBytes(buf, bs) } func (bs *BlobSidecars) ValidateAfterDecodingSSZ() error { if len(*bs) > constants.MaxBlobSidecarsPerBlock { return fmt.Errorf( "invalid number of blob sidecars, got %d max %d", len(*bs), constants.MaxBlobSidecarsPerBlock, ) } return nil } ================================================ FILE: da/types/sidecars_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "strconv" "testing" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/types" byteslib "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) func TestEmptySidecarMarshalling(t *testing.T) { t.Parallel() inclusionProof := make([]common.Root, 0) // Create an empty BlobSidecar for i := 1; i <= ctypes.KZGInclusionProofDepth; i++ { it := byteslib.ExtendToSize([]byte(strconv.Itoa(i)), byteslib.B32Size) proof, errBytes := byteslib.ToBytes32(it) require.NoError(t, errBytes) inclusionProof = append(inclusionProof, common.Root(proof)) } sidecar := types.BuildBlobSidecar( math.U64(0), &ctypes.SignedBeaconBlockHeader{ Header: &ctypes.BeaconBlockHeader{}, Signature: crypto.BLSSignature{}, }, &eip4844.Blob{}, eip4844.KZGCommitment{}, [48]byte{}, inclusionProof, ) // Marshal the empty sidecar marshalled, err := sidecar.MarshalSSZ() require.NoError( t, err, "Marshalling empty sidecar should not produce an error", ) require.NotNil( t, marshalled, "Marshalling empty sidecar should produce a result", ) // Unmarshal the empty sidecar unmarshalled := new(types.BlobSidecar) err = ssz.Unmarshal(marshalled, unmarshalled) require.NoError( t, err, "Unmarshalling empty sidecar should not produce an error", ) // Compare the original and unmarshalled empty sidecars require.Equal( t, sidecar, unmarshalled, "The original and unmarshalled empty sidecars should be equal", ) } func TestValidateBlockRoots(t *testing.T) { t.Parallel() inclusionProof := make([]common.Root, 0) // Create a sample BlobSidecar with valid roots for i := 1; i <= ctypes.KZGInclusionProofDepth; i++ { it := byteslib.ExtendToSize([]byte(strconv.Itoa(i)), byteslib.B32Size) proof, errBytes := byteslib.ToBytes32(it) require.NoError(t, errBytes) inclusionProof = append(inclusionProof, common.Root(proof)) } validSidecar := types.BuildBlobSidecar( math.U64(0), &ctypes.SignedBeaconBlockHeader{ Header: &ctypes.BeaconBlockHeader{ StateRoot: [32]byte{1}, BodyRoot: [32]byte{2}, }, Signature: crypto.BLSSignature{}, }, &eip4844.Blob{}, [48]byte{}, [48]byte{}, inclusionProof, ) // Validate the sidecar with valid roots sidecars := types.BlobSidecars{ validSidecar, } err := sidecars.ValidateBlockRoots() require.NoError( t, err, "Validating sidecar with valid roots should not produce an error", ) // Create a sample BlobSidecar with invalid roots differentBlockRootSidecar := types.BuildBlobSidecar( math.U64(0), &ctypes.SignedBeaconBlockHeader{ Header: &ctypes.BeaconBlockHeader{ StateRoot: [32]byte{1}, BodyRoot: [32]byte{3}, }, Signature: crypto.BLSSignature{}, }, &eip4844.Blob{}, eip4844.KZGCommitment{}, eip4844.KZGProof{}, inclusionProof, ) // Validate the sidecar with invalid roots sidecarsInvalid := types.BlobSidecars{ validSidecar, differentBlockRootSidecar, } err = sidecarsInvalid.ValidateBlockRoots() require.Error( t, err, "Validating sidecar with invalid roots should produce an error", ) } func TestZeroSidecarsInBlobSidecarsIsNotNil(t *testing.T) { t.Parallel() // This test exists to ensure that proposing a BlobSidecars with 0 // Sidecars is not considered IsNil(). sidecars := &types.BlobSidecars{} require.NotNil(t, sidecars) } ================================================ FILE: docs/.gitkeep ================================================ Coming soon... ================================================ FILE: engine-primitives/engine-primitives/attributes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" ) // PayloadAttributes is the attributes of a block payload. type PayloadAttributes struct { // Timestamp is the timestamp at which the block will be built at. Timestamp math.U64 `json:"timestamp"` // PrevRandao is the previous Randao value from the beacon chain as // per EIP-4399. PrevRandao common.Bytes32 `json:"prevRandao"` // SuggestedFeeRecipient is the suggested fee recipient for the block. If // the execution client has a different fee recipient, it will typically // ignore this value. SuggestedFeeRecipient common.ExecutionAddress `json:"suggestedFeeRecipient"` // Withdrawals is the list of withdrawals to be included in the block as per // EIP-4895 Withdrawals Withdrawals `json:"withdrawals"` // ParentBeaconBlockRoot is the root of the parent beacon block. (The block // prior) // to the block currently being processed. This field was added for // EIP-4788. ParentBeaconBlockRoot common.Root `json:"parentBeaconBlockRoot"` // ParentProposerPubkey carries the public key of previous block proposed // This field was added for BRIP-0004. Should be nil for fork versions // before Electra1. ParentProposerPubkey *crypto.BLSPubkey `json:"parentProposerPubKey"` } // NewPayloadAttributes creates a new PayloadAttributes and validates it for // the given fork version. func NewPayloadAttributes( forkVersion common.Version, timestamp math.U64, prevRandao common.Bytes32, suggestedFeeRecipient common.ExecutionAddress, withdrawals Withdrawals, parentBeaconBlockRoot common.Root, parentProposerPubkey *crypto.BLSPubkey, ) (*PayloadAttributes, error) { pa := &PayloadAttributes{ Timestamp: timestamp, PrevRandao: prevRandao, SuggestedFeeRecipient: suggestedFeeRecipient, Withdrawals: withdrawals, ParentBeaconBlockRoot: parentBeaconBlockRoot, ParentProposerPubkey: parentProposerPubkey, } if err := pa.validate(forkVersion); err != nil { return nil, err } return pa, nil } // GetSuggestedFeeRecipient returns the suggested fee recipient. func (p *PayloadAttributes) GetSuggestedFeeRecipient() common.ExecutionAddress { return p.SuggestedFeeRecipient } // Validate validates the PayloadAttributes for the given fork version. func (p *PayloadAttributes) validate(forkVersion common.Version) error { if p.Timestamp == 0 { return ErrInvalidTimestamp } if p.PrevRandao == [32]byte{} { return ErrEmptyPrevRandao } // For any fork version Capella onwards, withdrawals are required. if p.Withdrawals == nil && version.EqualsOrIsAfter(forkVersion, version.Capella()) { return ErrNilWithdrawals } // For any fork version Electra1 onwards, the parent proposer pubkey is required. if version.IsBefore(forkVersion, version.Electra1()) { if p.ParentProposerPubkey != nil { return ErrNonEmptyPrevProposerPubKey } } else { if p.ParentProposerPubkey == nil { return ErrEmptyPrevProposerPubKey } } return nil } ================================================ FILE: engine-primitives/engine-primitives/attributes_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives_test import ( "testing" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) type payloadAttributesInput struct { forkVersion common.Version timestamp math.U64 prevRandao common.Bytes32 suggestedFeeRecipient common.ExecutionAddress withdrawals engineprimitives.Withdrawals parentBeaconBlockRoot common.Root parentProposerPubKey *crypto.BLSPubkey } func TestPayloadAttributes(t *testing.T) { t.Parallel() // default valid data validInput := payloadAttributesInput{ forkVersion: version.Altair(), timestamp: math.U64(123456789), prevRandao: common.Bytes32{1, 2, 3}, suggestedFeeRecipient: common.ExecutionAddress{}, withdrawals: engineprimitives.Withdrawals{}, parentBeaconBlockRoot: common.Root{}, parentProposerPubKey: nil, } tests := []struct { name string input func() payloadAttributesInput wantErr error }{ { name: "Valid payload attributes", input: func() payloadAttributesInput { return validInput }, wantErr: nil, }, { name: "Invalid timestamp", input: func() payloadAttributesInput { res := validInput res.timestamp = 0 return res }, wantErr: engineprimitives.ErrInvalidTimestamp, }, { name: "Invalid PreRandao", input: func() payloadAttributesInput { res := validInput res.prevRandao = common.Bytes32{} return res }, wantErr: engineprimitives.ErrEmptyPrevRandao, }, { name: "Invalid nil withdrawals on Capella", input: func() payloadAttributesInput { res := validInput res.forkVersion = version.Capella() res.withdrawals = nil return res }, wantErr: engineprimitives.ErrNilWithdrawals, }, { name: "Invalid - parent proposer pubkey before Electra1", input: func() payloadAttributesInput { res := validInput res.forkVersion = version.Electra() res.parentProposerPubKey = &crypto.BLSPubkey{0x01} return res }, wantErr: engineprimitives.ErrNonEmptyPrevProposerPubKey, }, { name: "Invalid - no parent proposer pubkey after Electra1", input: func() payloadAttributesInput { res := validInput res.forkVersion = version.Electra1() return res }, wantErr: engineprimitives.ErrEmptyPrevProposerPubKey, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() in := tt.input() got, err := engineprimitives.NewPayloadAttributes( in.forkVersion, in.timestamp, in.prevRandao, in.suggestedFeeRecipient, in.withdrawals, in.parentBeaconBlockRoot, in.parentProposerPubKey, ) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.NotNil(t, got) require.Equal( t, in.suggestedFeeRecipient, got.GetSuggestedFeeRecipient(), ) } }) } } ================================================ FILE: engine-primitives/engine-primitives/blobs_bundle.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives import "github.com/berachain/beacon-kit/primitives/eip4844" // Compile-time assertion to ensure BlobsBundleV1 implements BlobsBundle. var _ BlobsBundle = (*BlobsBundleV1)(nil) // BlobsBundle is an interface for the blobs bundle. // // TODO: move interface definition to packages where it is used. type BlobsBundle interface { // GetCommitments returns the commitments in the blobs bundle. GetCommitments() []eip4844.KZGCommitment // GetProofs returns the proofs in the blobs bundle. GetProofs() []eip4844.KZGProof // GetBlobs returns the blobs in the blobs bundle. GetBlobs() []*eip4844.Blob } // BlobsBundleV1 represents a collection of commitments, proofs, and blobs. // Each field is a slice of bytes that are serialized for transmission or // storage. type BlobsBundleV1 struct { // Commitments are the KZG commitments included in the bundle. Commitments []eip4844.KZGCommitment `json:"commitments"` // Proofs are the KZG proofs corresponding to the commitments. Proofs []eip4844.KZGProof `json:"proofs"` // Blobs are arbitrary data blobs included in the bundle. Blobs []*eip4844.Blob `json:"blobs"` } // GetCommitments returns the slice of commitments in the bundle. func (b *BlobsBundleV1) GetCommitments() []eip4844.KZGCommitment { return b.Commitments } // GetProofs returns the slice of proofs in the bundle. func (b *BlobsBundleV1) GetProofs() []eip4844.KZGProof { return b.Proofs } // GetBlobs returns the slice of data blobs in the bundle. func (b *BlobsBundleV1) GetBlobs() []*eip4844.Blob { return b.Blobs } ================================================ FILE: engine-primitives/engine-primitives/blobs_bundle_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives_test import ( "testing" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/stretchr/testify/require" ) func TestBlobsBundleV1(t *testing.T) { t.Parallel() bundle := &engineprimitives.BlobsBundleV1{ Commitments: []eip4844.KZGCommitment{{1, 2, 3}, {4, 5, 6}}, Proofs: []eip4844.KZGProof{{7, 8, 9}, {10, 11, 12}}, Blobs: []*eip4844.Blob{{13, 14, 15}, {16, 17, 18}}, } commitments := bundle.GetCommitments() require.Equal(t, bundle.Commitments, commitments) proofs := bundle.GetProofs() require.Equal(t, bundle.Proofs, proofs) blobs := bundle.GetBlobs() require.Equal(t, bundle.Blobs, blobs) } ================================================ FILE: engine-primitives/engine-primitives/engine.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:gochecknoglobals // alias. package engineprimitives import ( "fmt" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" ) // ClientVersionV1 contains information which identifies a client // implementation. type ClientVersionV1 struct { Code string `json:"code"` Name string `json:"name"` Version string `json:"version"` Commit string `json:"commit"` } func (v *ClientVersionV1) String() string { return fmt.Sprintf("%s-%s-%s-%s", v.Code, v.Name, v.Version, v.Commit) } var ( // PayloadStatusValid is the status of a valid payload. PayloadStatusValid = "VALID" // PayloadStatusInvalid is the status of an invalid payload. PayloadStatusInvalid = "INVALID" // PayloadStatusSyncing is the status returned when the EL is syncing. PayloadStatusSyncing = "SYNCING" // PayloadStatusAccepted is the status returned when the EL has accepted the // payload. PayloadStatusAccepted = "ACCEPTED" ) // ForkchoiceResponseV1 as per the EngineAPI Specification: // https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#response-2 type ForkchoiceResponseV1 struct { // PayloadStatus is the payload status. PayloadStatus PayloadStatusV1 `json:"payloadStatus"` // PayloadID isthe identifier of the payload build process, it // can also be `nil`. PayloadID *PayloadID `json:"payloadId"` } // ForkchoiceStateV1 as per the EngineAPI Specification: // https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#forkchoicestatev1 type ForkchoiceStateV1 struct { // HeadBlockHash is the desired block hash of the head of the canonical // chain. HeadBlockHash common.ExecutionHash `json:"headBlockHash"` // SafeBlockHash is the "safe" block hash of the canonical chain under // certain // synchrony and honesty assumptions. This value MUST be either equal to // or an ancestor of `HeadBlockHash`. SafeBlockHash common.ExecutionHash `json:"safeBlockHash"` // FinalizedBlockHash is the desired block hash of the most recent finalized // block FinalizedBlockHash common.ExecutionHash `json:"finalizedBlockHash"` } func (fsv1 *ForkchoiceStateV1) Equals(rhs *ForkchoiceStateV1) bool { switch { case fsv1 != nil && rhs != nil: return fsv1.HeadBlockHash == rhs.HeadBlockHash && fsv1.SafeBlockHash == rhs.SafeBlockHash && fsv1.FinalizedBlockHash == rhs.FinalizedBlockHash case fsv1 == nil && rhs == nil: return true default: return false } } // PayloadStatusV1 represents the status of a payload as per the EngineAPI // Specification. For more details, see: // https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#payloadstatusv1 type PayloadStatusV1 struct { // Status string of the payload. Status string `json:"status"` // LatestValidHash is the hash of the most recent valid block // in the branch defined by payload and its ancestors LatestValidHash *common.ExecutionHash `json:"latestValidHash"` // ValidationError is a message providing additional details on // the validation error if the payload is classified as // INVALID or INVALID_BLOCK_HASH ValidationError *string `json:"validationError"` } // PayloadID is an identifier for the payload build process. type PayloadID = bytes.B8 ================================================ FILE: engine-primitives/engine-primitives/engine_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives_test import ( "testing" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/stretchr/testify/require" ) func TestPayloadID(t *testing.T) { t.Parallel() payloadID := engineprimitives.PayloadID{ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, } // Test marshaling marshaledID, err := json.Marshal(payloadID) require.NoError(t, err) require.Equal(t, "\"0x0102030405060708\"", string(marshaledID)) // Test unmarshaling var unmarshaledID engineprimitives.PayloadID err = json.Unmarshal(marshaledID, &unmarshaledID) require.NoError(t, err) require.Equal(t, payloadID, unmarshaledID) } func TestForkchoiceStateV1(t *testing.T) { t.Parallel() state := &engineprimitives.ForkchoiceStateV1{ HeadBlockHash: common.ExecutionHash{0x1}, SafeBlockHash: common.ExecutionHash{0x2}, FinalizedBlockHash: common.ExecutionHash{0x3}, } require.Equal(t, common.ExecutionHash{0x1}, state.HeadBlockHash) require.Equal(t, common.ExecutionHash{0x2}, state.SafeBlockHash) require.Equal( t, common.ExecutionHash{0x3}, state.FinalizedBlockHash, ) // Test marshaling marshaledState, err := json.Marshal(state) require.NoError(t, err) // Test unmarshaling var unmarshaledState engineprimitives.ForkchoiceStateV1 err = json.Unmarshal(marshaledState, &unmarshaledState) require.NoError(t, err) require.Equal(t, state, &unmarshaledState) } func TestPayloadStatusV1(t *testing.T) { t.Parallel() status := &engineprimitives.PayloadStatusV1{ Status: engineprimitives.PayloadStatusValid, LatestValidHash: &common.ExecutionHash{0x1}, } require.Equal(t, engineprimitives.PayloadStatusValid, status.Status) require.Equal(t, &common.ExecutionHash{0x1}, status.LatestValidHash) // Test marshaling marshaledStatus, err := json.Marshal(status) require.NoError(t, err) // Test unmarshaling var unmarshaledStatus engineprimitives.PayloadStatusV1 err = json.Unmarshal(marshaledStatus, &unmarshaledStatus) require.NoError(t, err) require.Equal(t, status, &unmarshaledStatus) } ================================================ FILE: engine-primitives/engine-primitives/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives import "github.com/berachain/beacon-kit/errors" var ( // ErrInvalidTimestamp indicates that the provided timestamp is not valid. ErrInvalidTimestamp = errors.New("invalid timestamp") // ErrNilWithdrawals indicates that the withdrawals are in a // Capella versioned payload. ErrNilWithdrawals = errors.New("nil withdrawals post capella") // ErrEmptyPrevRandao indicates that the previous RANDAO value is empty. ErrEmptyPrevRandao = errors.New("empty randao") // ErrInvalidVersionedHash indicates that the versioned hash is invalid. ErrInvalidVersionedHash = errors.New("invalid versioned hash") // ErrMismatchedNumVersionedHashes indicates that the number of blobs in the // payload does not match the expected number. ErrMismatchedNumVersionedHashes = errors.New( "mismatch in number of versioned hashes", ) // ErrPayloadBlockHashMismatch represents an error when the block hash // in the payload does not match from the assembled block. ErrPayloadBlockHashMismatch = errors.New("block hash in payload does not match assembled block") // ErrEmptyPrevProposerPubKey indicates that the previous proposer public key is empty. ErrEmptyPrevProposerPubKey = errors.New("empty public key for previous block proposer") // ErrNonEmptyPrevProposerPubKey indicates that the previous proposer public key is non-empty. ErrNonEmptyPrevProposerPubKey = errors.New("non-empty public key for previous block proposer") ) ================================================ FILE: engine-primitives/engine-primitives/mocks/blobs_bundle.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( eip4844 "github.com/berachain/beacon-kit/primitives/eip4844" mock "github.com/stretchr/testify/mock" ) // BlobsBundle is an autogenerated mock type for the BlobsBundle type type BlobsBundle struct { mock.Mock } type BlobsBundle_Expecter struct { mock *mock.Mock } func (_m *BlobsBundle) EXPECT() *BlobsBundle_Expecter { return &BlobsBundle_Expecter{mock: &_m.Mock} } // GetBlobs provides a mock function with no fields func (_m *BlobsBundle) GetBlobs() []*eip4844.Blob { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetBlobs") } var r0 []*eip4844.Blob if rf, ok := ret.Get(0).(func() []*eip4844.Blob); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*eip4844.Blob) } } return r0 } // BlobsBundle_GetBlobs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlobs' type BlobsBundle_GetBlobs_Call struct { *mock.Call } // GetBlobs is a helper method to define mock.On call func (_e *BlobsBundle_Expecter) GetBlobs() *BlobsBundle_GetBlobs_Call { return &BlobsBundle_GetBlobs_Call{Call: _e.mock.On("GetBlobs")} } func (_c *BlobsBundle_GetBlobs_Call) Run(run func()) *BlobsBundle_GetBlobs_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BlobsBundle_GetBlobs_Call) Return(_a0 []*eip4844.Blob) *BlobsBundle_GetBlobs_Call { _c.Call.Return(_a0) return _c } func (_c *BlobsBundle_GetBlobs_Call) RunAndReturn(run func() []*eip4844.Blob) *BlobsBundle_GetBlobs_Call { _c.Call.Return(run) return _c } // GetCommitments provides a mock function with no fields func (_m *BlobsBundle) GetCommitments() []eip4844.KZGCommitment { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetCommitments") } var r0 []eip4844.KZGCommitment if rf, ok := ret.Get(0).(func() []eip4844.KZGCommitment); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]eip4844.KZGCommitment) } } return r0 } // BlobsBundle_GetCommitments_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCommitments' type BlobsBundle_GetCommitments_Call struct { *mock.Call } // GetCommitments is a helper method to define mock.On call func (_e *BlobsBundle_Expecter) GetCommitments() *BlobsBundle_GetCommitments_Call { return &BlobsBundle_GetCommitments_Call{Call: _e.mock.On("GetCommitments")} } func (_c *BlobsBundle_GetCommitments_Call) Run(run func()) *BlobsBundle_GetCommitments_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BlobsBundle_GetCommitments_Call) Return(_a0 []eip4844.KZGCommitment) *BlobsBundle_GetCommitments_Call { _c.Call.Return(_a0) return _c } func (_c *BlobsBundle_GetCommitments_Call) RunAndReturn(run func() []eip4844.KZGCommitment) *BlobsBundle_GetCommitments_Call { _c.Call.Return(run) return _c } // GetProofs provides a mock function with no fields func (_m *BlobsBundle) GetProofs() []eip4844.KZGProof { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetProofs") } var r0 []eip4844.KZGProof if rf, ok := ret.Get(0).(func() []eip4844.KZGProof); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]eip4844.KZGProof) } } return r0 } // BlobsBundle_GetProofs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetProofs' type BlobsBundle_GetProofs_Call struct { *mock.Call } // GetProofs is a helper method to define mock.On call func (_e *BlobsBundle_Expecter) GetProofs() *BlobsBundle_GetProofs_Call { return &BlobsBundle_GetProofs_Call{Call: _e.mock.On("GetProofs")} } func (_c *BlobsBundle_GetProofs_Call) Run(run func()) *BlobsBundle_GetProofs_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *BlobsBundle_GetProofs_Call) Return(_a0 []eip4844.KZGProof) *BlobsBundle_GetProofs_Call { _c.Call.Return(_a0) return _c } func (_c *BlobsBundle_GetProofs_Call) RunAndReturn(run func() []eip4844.KZGProof) *BlobsBundle_GetProofs_Call { _c.Call.Return(run) return _c } // NewBlobsBundle creates a new instance of BlobsBundle. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBlobsBundle(t interface { mock.TestingT Cleanup(func()) }) *BlobsBundle { mock := &BlobsBundle{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: engine-primitives/engine-primitives/mocks/payload_attributer.mock.go ================================================ // Code generated by mockery v2.49.0. DO NOT EDIT. package mocks import ( bytes "github.com/berachain/beacon-kit/primitives/bytes" common "github.com/berachain/beacon-kit/primitives/common" mock "github.com/stretchr/testify/mock" ) // PayloadAttributer is an autogenerated mock type for the PayloadAttributer type type PayloadAttributer struct { mock.Mock } type PayloadAttributer_Expecter struct { mock *mock.Mock } func (_m *PayloadAttributer) EXPECT() *PayloadAttributer_Expecter { return &PayloadAttributer_Expecter{mock: &_m.Mock} } // GetSuggestedFeeRecipient provides a mock function with given fields: func (_m *PayloadAttributer) GetSuggestedFeeRecipient() common.ExecutionAddress { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetSuggestedFeeRecipient") } var r0 common.ExecutionAddress if rf, ok := ret.Get(0).(func() common.ExecutionAddress); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(common.ExecutionAddress) } } return r0 } // PayloadAttributer_GetSuggestedFeeRecipient_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSuggestedFeeRecipient' type PayloadAttributer_GetSuggestedFeeRecipient_Call struct { *mock.Call } // GetSuggestedFeeRecipient is a helper method to define mock.On call func (_e *PayloadAttributer_Expecter) GetSuggestedFeeRecipient() *PayloadAttributer_GetSuggestedFeeRecipient_Call { return &PayloadAttributer_GetSuggestedFeeRecipient_Call{Call: _e.mock.On("GetSuggestedFeeRecipient")} } func (_c *PayloadAttributer_GetSuggestedFeeRecipient_Call) Run(run func()) *PayloadAttributer_GetSuggestedFeeRecipient_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *PayloadAttributer_GetSuggestedFeeRecipient_Call) Return(_a0 common.ExecutionAddress) *PayloadAttributer_GetSuggestedFeeRecipient_Call { _c.Call.Return(_a0) return _c } func (_c *PayloadAttributer_GetSuggestedFeeRecipient_Call) RunAndReturn(run func() common.ExecutionAddress) *PayloadAttributer_GetSuggestedFeeRecipient_Call { _c.Call.Return(run) return _c } // IsNil provides a mock function with given fields: func (_m *PayloadAttributer) IsNil() bool { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for IsNil") } var r0 bool if rf, ok := ret.Get(0).(func() bool); ok { r0 = rf() } else { r0 = ret.Get(0).(bool) } return r0 } // PayloadAttributer_IsNil_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsNil' type PayloadAttributer_IsNil_Call struct { *mock.Call } // IsNil is a helper method to define mock.On call func (_e *PayloadAttributer_Expecter) IsNil() *PayloadAttributer_IsNil_Call { return &PayloadAttributer_IsNil_Call{Call: _e.mock.On("IsNil")} } func (_c *PayloadAttributer_IsNil_Call) Run(run func()) *PayloadAttributer_IsNil_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *PayloadAttributer_IsNil_Call) Return(_a0 bool) *PayloadAttributer_IsNil_Call { _c.Call.Return(_a0) return _c } func (_c *PayloadAttributer_IsNil_Call) RunAndReturn(run func() bool) *PayloadAttributer_IsNil_Call { _c.Call.Return(run) return _c } // Version provides a mock function with given fields: func (_m *PayloadAttributer) GetForkVersion() bytes.B4 { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetForkVersion") } var r0 bytes.B4 if rf, ok := ret.Get(0).(func() bytes.B4); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(bytes.B4) } } return r0 } // PayloadAttributer_Version_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetForkVersion' type PayloadAttributer_Version_Call struct { *mock.Call } // Version is a helper method to define mock.On call func (_e *PayloadAttributer_Expecter) Version() *PayloadAttributer_Version_Call { return &PayloadAttributer_Version_Call{Call: _e.mock.On("GetForkVersion")} } func (_c *PayloadAttributer_Version_Call) Run(run func()) *PayloadAttributer_Version_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *PayloadAttributer_Version_Call) Return(_a0 bytes.B4) *PayloadAttributer_Version_Call { _c.Call.Return(_a0) return _c } func (_c *PayloadAttributer_Version_Call) RunAndReturn(run func() bytes.B4) *PayloadAttributer_Version_Call { _c.Call.Return(run) return _c } // NewPayloadAttributer creates a new instance of PayloadAttributer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewPayloadAttributer(t interface { mock.TestingT Cleanup(func()) }) *PayloadAttributer { mock := &PayloadAttributer{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: engine-primitives/engine-primitives/transactions.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) var ( _ ssz.DynamicObject = (*Transactions)(nil) _ constraints.SSZRootable = (*Transactions)(nil) ) // Transactions is a type alias for [][]byte, which is how // transactions are received in the execution payload. type Transactions [][]byte /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the SSZ encoded size in bytes for the Transactions. func (txs Transactions) SizeSSZ(siz *ssz.Sizer, _ bool) uint32 { return ssz.SizeSliceOfDynamicBytes(siz, txs) } // DefineSSZ defines the SSZ encoding for the Transactions object. // TODO: This can accidentally decouple from the definition in // ExecutionPayload and we should be cognizant of that and/or // make a PR to allow for them to be defined in one place. func (txs Transactions) DefineSSZ(codec *ssz.Codec) { codec.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfDynamicBytesContent( codec, (*[][]byte)(&txs), constants.MaxTxsPerPayload, constants.MaxBytesPerTx, ) }) codec.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfDynamicBytesContent( codec, (*[][]byte)(&txs), constants.MaxTxsPerPayload, constants.MaxBytesPerTx, ) }) codec.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfDynamicBytesOffset( codec, (*[][]byte)(&txs), constants.MaxTxsPerPayload, constants.MaxBytesPerTx, ) }) } // HashTreeRoot returns the hash tree root of the Transactions object. func (txs Transactions) HashTreeRoot() common.Root { return ssz.HashConcurrent(txs) } ================================================ FILE: engine-primitives/engine-primitives/transactions_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives_test import ( "testing" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/constants" ) // Tests consistency of our HashTreeRoot implementation with Prysm's. // https://github.com/prysmaticlabs/prysm/blob/8070fc8ecef3c2003dea7e1fe6dba179ddf76151/encoding/ssz/htrutils_test.go#L67 // //nolint:lll // link. var prysmConsistencyTests = []struct { name string txs [][]byte want [32]byte wantErr bool }{ { name: "nil", txs: nil, want: [32]byte{ 127, 254, 36, 30, 166, 1, 135, 253, 176, 24, 123, 250, 34, 222, 53, 209, 249, 190, 215, 171, 6, 29, 148, 1, 253, 71, 227, 74, 84, 251, 237, 225, }, }, { name: "empty", txs: [][]byte{}, want: [32]byte{ 127, 254, 36, 30, 166, 1, 135, 253, 176, 24, 123, 250, 34, 222, 53, 209, 249, 190, 215, 171, 6, 29, 148, 1, 253, 71, 227, 74, 84, 251, 237, 225, }, }, { name: "3 non-nil txs", txs: [][]byte{ []byte("transaction1"), []byte("transaction2"), []byte("transaction3"), }, want: [32]byte{ 139, 213, 123, 109, 253, 176, 23, 93, 101, 51, 142, 198, 119, 250, 13, 242, 79, 219, 180, 165, 254, 181, 9, 178, 4, 253, 110, 75, 50, 25, 17, 141, }, }, { name: "max bytes per tx", txs: func() [][]byte { var tx []byte for i := range constants.MaxBytesPerTx { tx = append(tx, byte(i)) } return [][]byte{tx} }(), want: [32]byte{ 120, 150, 59, 37, 152, 101, 206, 102, 229, 69, 62, 176, 208, 159, 230, 109, 150, 65, 134, 25, 69, 61, 13, 45, 150, 78, 139, 155, 241, 18, 248, 222, }, }, { name: "one tx", txs: [][]byte{{1, 2, 3}}, want: [32]byte{ 102, 209, 140, 87, 217, 28, 68, 12, 133, 42, 77, 136, 191, 18, 234, 105, 166, 228, 216, 235, 230, 95, 200, 73, 85, 33, 134, 254, 219, 97, 82, 209, }, }, { name: "max txs", txs: func() [][]byte { var txs [][]byte for range int(constants.MaxTxsPerPayload) { txs = append(txs, []byte{0x01}) } return txs }(), want: [32]byte{ 168, 19, 62, 29, 232, 106, 28, 81, 99, 73, 236, 102, 94, 160, 44, 191, 122, 176, 38, 39, 139, 100, 136, 5, 48, 242, 34, 31, 60, 104, 191, 171, }, }, } func TestProperTransactions(t *testing.T) { t.Parallel() for _, tt := range prysmConsistencyTests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := engineprimitives.Transactions( tt.txs, ).HashTreeRoot() for i := range got { if got[i] != tt.want[i] { t.Errorf( "TransactionsRoot() got = %v, want %v, off at byte %d", [32]byte(got), tt.want, i, ) return } } }) } } ================================================ FILE: engine-primitives/engine-primitives/withdrawal.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives import ( "io" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/math" fastssz "github.com/ferranbt/fastssz" "github.com/karalabe/ssz" fastrlp "github.com/umbracle/fastrlp" ) // withdrawalSize is the size of the Withdrawal in bytes. const withdrawalSize = 44 var ( _ ssz.StaticObject = (*Withdrawal)(nil) _ constraints.SSZMarshallableRootable = (*Withdrawal)(nil) ) // Withdrawal represents a validator withdrawal from the consensus layer. type Withdrawal struct { // Index is the unique identifier for the withdrawal. Index math.U64 `json:"index"` // Validator is the index of the validator initiating the withdrawal. Validator math.ValidatorIndex `json:"validatorIndex"` // Address is the execution address where the withdrawal will be sent. // It has a fixed size of 20 bytes. Address common.ExecutionAddress `json:"address"` // Amount is the amount of Gwei to be withdrawn. Amount math.Gwei `json:"amount"` } func NewWithdrawal( index math.U64, validator math.ValidatorIndex, address common.ExecutionAddress, amount math.Gwei, ) *Withdrawal { return &Withdrawal{ Index: index, Validator: validator, Address: address, Amount: amount, } } /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of the Withdrawal in bytes when SSZ encoded. func (*Withdrawal) SizeSSZ(*ssz.Sizer) uint32 { return withdrawalSize } // MarshalSSZ marshals the Withdrawal into SSZ format. func (w *Withdrawal) DefineSSZ(c *ssz.Codec) { ssz.DefineUint64(c, &w.Index) // Field (0) - Index - 8 bytes ssz.DefineUint64(c, &w.Validator) // Field (1) - Validator - 8 bytes ssz.DefineStaticBytes(c, &w.Address) // Field (2) - Address - 20 bytes ssz.DefineUint64(c, &w.Amount) // Field (3) - Amount - 8 bytes } // HashTreeRoot. func (w *Withdrawal) HashTreeRoot() common.Root { return ssz.HashSequential(w) } // MarshalSSZ marshals the Withdrawal object to SSZ format. func (w *Withdrawal) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(w)) return buf, ssz.EncodeToBytes(buf, w) } func (*Withdrawal) ValidateAfterDecodingSSZ() error { return nil } /* -------------------------------------------------------------------------- */ /* FastSSZ */ /* -------------------------------------------------------------------------- */ // MarshalSSZTo ssz marshals the Withdrawal object to a target array. func (w *Withdrawal) MarshalSSZTo(dst []byte) ([]byte, error) { bz, err := w.MarshalSSZ() if err != nil { return nil, err } dst = append(dst, bz...) return dst, nil } // HashTreeRootWith ssz hashes the Withdrawal object with a hasher. func (w *Withdrawal) HashTreeRootWith(hh fastssz.HashWalker) error { indx := hh.Index() // Field (0) 'Index' hh.PutUint64(uint64(w.Index)) // Field (1) 'Validator' hh.PutUint64(uint64(w.Validator)) // Field (2) 'Address' hh.PutBytes(w.Address[:]) // Field (3) 'Amount' hh.PutUint64(uint64(w.Amount)) hh.Merkleize(indx) return nil } // GetTree ssz hashes the Withdrawal object. func (w *Withdrawal) GetTree() (*fastssz.Node, error) { return fastssz.ProofTree(w) } /* -------------------------------------------------------------------------- */ /* RLP */ /* -------------------------------------------------------------------------- */ // SetIndex sets the unique identifier for the withdrawal. func (w Withdrawal) EncodeRLP(_w io.Writer) error { a := fastrlp.DefaultArenaPool.Get() defer fastrlp.DefaultArenaPool.Put(a) v := a.NewArray() v.Set(a.NewUint(uint64(w.Index))) v.Set(a.NewUint(uint64(w.Validator))) v.Set(a.NewCopyBytes(w.Address[:])) v.Set(a.NewUint(uint64(w.Amount))) _, err := _w.Write(v.MarshalTo(nil)) return err } /* -------------------------------------------------------------------------- */ /* Getters and Setters */ /* -------------------------------------------------------------------------- */ // Equals returns true if the Withdrawal is equal to the other. func (w *Withdrawal) Equals(rhs *Withdrawal) bool { switch { case w == nil && rhs == nil: return true case w != nil && rhs != nil: return w.Index == rhs.Index && w.Validator == rhs.Validator && w.Address == rhs.Address && w.Amount == rhs.Amount default: return false } } // GetIndex returns the unique identifier for the withdrawal. func (w *Withdrawal) GetIndex() math.U64 { return w.Index } // GetValidatorIndex returns the index of the validator initiating the // withdrawal. func (w *Withdrawal) GetValidatorIndex() math.ValidatorIndex { return w.Validator } // GetAddress returns the execution address where the withdrawal will be sent. func (w *Withdrawal) GetAddress() common.ExecutionAddress { return w.Address } // GetAmount returns the amount of Gwei to be withdrawn. func (w *Withdrawal) GetAmount() math.Gwei { return w.Amount } ================================================ FILE: engine-primitives/engine-primitives/withdrawal_ssz_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives_test import ( "testing" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/berachain/beacon-kit/primitives/math" karalabessz "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) func TestWithdrawalSSZ(t *testing.T) { t.Parallel() withdrawal := &engineprimitives.Withdrawal{ Index: math.U64(1), Validator: math.ValidatorIndex(2), Address: [20]byte{}, Amount: math.Gwei(100), } data, err := withdrawal.MarshalSSZ() require.NoError(t, err) require.NotNil(t, data) unmarshalled := new(engineprimitives.Withdrawal) err = ssz.Unmarshal(data, unmarshalled) require.NoError(t, err) require.Equal(t, withdrawal, unmarshalled) size := karalabessz.Size(withdrawal) require.Equal(t, uint32(44), size) tree := withdrawal.HashTreeRoot() require.NotNil(t, tree) } func TestWithdrawalGetTree(t *testing.T) { t.Parallel() withdrawal := &engineprimitives.Withdrawal{ Index: math.U64(1), Validator: math.ValidatorIndex(2), Address: [20]byte{}, Amount: math.Gwei(100), } tree, err := withdrawal.GetTree() require.NoError(t, err) require.NotNil(t, tree) } func TestWithdrawalUnmarshalSSZ(t *testing.T) { t.Parallel() tests := []struct { name string input []byte want *engineprimitives.Withdrawal wantErr bool }{ { name: "Valid input little endian", input: []byte{ 1, 0, 0, 0, 0, 0, 0, 0, // Index: 1 2, 0, 0, 0, 0, 0, 0, 0, // Validator: 2 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, // Address 100, 0, 0, 0, 0, 0, 0, 0, // Amount: 100 }, want: &engineprimitives.Withdrawal{ Index: math.U64(1), Validator: math.ValidatorIndex(2), Address: [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, Amount: math.Gwei(100), }, wantErr: false, }, { name: "Invalid size - too short", input: []byte{0, 1, 2, 3}, want: &engineprimitives.Withdrawal{}, wantErr: true, }, { name: "Invalid size - too long", input: make([]byte, 45), want: &engineprimitives.Withdrawal{}, wantErr: true, }, { name: "Max values", input: []byte{ 255, 255, 255, 255, 255, 255, 255, 255, // Index: max uint64 255, 255, 255, 255, 255, 255, 255, 255, // Validator: max uint64 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // Address 255, 255, 255, 255, 255, 255, 255, 255, // Amount: max uint64 }, want: &engineprimitives.Withdrawal{ Index: math.U64(^uint64(0)), Validator: math.ValidatorIndex(^uint64(0)), Address: [20]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, Amount: math.Gwei(^uint64(0)), }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var w engineprimitives.Withdrawal err := ssz.Unmarshal(tt.input, &w) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want.Index, w.Index) require.Equal(t, tt.want.Validator, w.Validator) require.Equal(t, tt.want.Address, w.Address) require.Equal(t, tt.want.Amount, w.Amount) } }) } } ================================================ FILE: engine-primitives/engine-primitives/withdrawal_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives_test import ( "testing" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) func TestWithdrawal(t *testing.T) { t.Parallel() withdrawal := engineprimitives.NewWithdrawal( math.U64(1), math.ValidatorIndex(1), common.ExecutionAddress{1, 2, 3, 4, 5}, math.Gwei(1000), ) require.Equal(t, math.U64(1), withdrawal.GetIndex()) require.Equal(t, math.ValidatorIndex(1), withdrawal.GetValidatorIndex()) require.Equal(t, common.ExecutionAddress{1, 2, 3, 4, 5}, withdrawal.GetAddress(), ) require.Equal(t, math.Gwei(1000), withdrawal.GetAmount()) } func TestWithdrawal_Equals(t *testing.T) { t.Parallel() withdrawal1 := &engineprimitives.Withdrawal{ Index: math.U64(1), Validator: math.ValidatorIndex(1), Address: common.ExecutionAddress{1, 2, 3, 4, 5}, Amount: math.Gwei(1000), } withdrawal2 := &engineprimitives.Withdrawal{ Index: math.U64(1), Validator: math.ValidatorIndex(1), Address: common.ExecutionAddress{1, 2, 3, 4, 5}, Amount: math.Gwei(1000), } withdrawal3 := &engineprimitives.Withdrawal{ Index: math.U64(2), Validator: math.ValidatorIndex(2), Address: common.ExecutionAddress{2, 3, 4, 5, 6}, Amount: math.Gwei(2000), } // Test that Equals returns true for two identical withdrawals require.True(t, withdrawal1.Equals(withdrawal2)) // Test that Equals returns false for two different withdrawals require.False(t, withdrawal1.Equals(withdrawal3)) } func TestWithdrawalMethods(t *testing.T) { t.Parallel() withdrawal := &engineprimitives.Withdrawal{ Index: math.U64(1), Validator: math.ValidatorIndex(2), Address: [20]byte{1, 2, 3}, Amount: math.Gwei(100), } t.Run("Getters", func(t *testing.T) { t.Parallel() require.Equal(t, math.U64(1), withdrawal.GetIndex()) require.Equal(t, math.ValidatorIndex(2), withdrawal.GetValidatorIndex()) require.Equal(t, common.ExecutionAddress([20]byte{0x01, 0x02, 0x03}), withdrawal.GetAddress()) require.Equal(t, math.U64(100), withdrawal.GetAmount()) }) } ================================================ FILE: engine-primitives/engine-primitives/withdrawals.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives import ( "bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) var ( _ ssz.StaticObject = (*Withdrawals)(nil) _ constraints.SSZRootable = (*Withdrawals)(nil) ) // Withdrawals represents a list of withdrawals. type Withdrawals []*Withdrawal /* -------------------------------------------------------------------------- */ /* SSZ */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the SSZ encoded size in bytes for the Withdrawals. func (w Withdrawals) SizeSSZ(siz *ssz.Sizer) uint32 { return ssz.SizeSliceOfStaticObjects(siz, w) } // DefineSSZ defines the SSZ encoding for the Withdrawals object. func (w Withdrawals) DefineSSZ(codec *ssz.Codec) { codec.DefineEncoder(func(*ssz.Encoder) { ssz.DefineSliceOfStaticObjectsContent( codec, (*[]*Withdrawal)(&w), constants.MaxWithdrawalsPerPayload) }) codec.DefineDecoder(func(*ssz.Decoder) { ssz.DefineSliceOfStaticObjectsContent( codec, (*[]*Withdrawal)(&w), constants.MaxWithdrawalsPerPayload) }) codec.DefineHasher(func(*ssz.Hasher) { ssz.DefineSliceOfStaticObjectsOffset( codec, (*[]*Withdrawal)(&w), constants.MaxWithdrawalsPerPayload) }) } // HashTreeRoot returns the hash tree root of the Withdrawals. func (w Withdrawals) HashTreeRoot() common.Root { return ssz.HashSequential(w) } /* -------------------------------------------------------------------------- */ /* RLP */ /* -------------------------------------------------------------------------- */ // Len returns the length of s. func (w Withdrawals) Len() int { return len(w) } // EncodeIndex encodes the i'th withdrawal to w. Note that this does not check // for errors because we assume that *Withdrawal will only ever contain valid // withdrawals that were either // constructed by decoding or via public API in this package. func (w Withdrawals) EncodeIndex(i int, _w *bytes.Buffer) { // #nosec:G703 // its okay. _ = w[i].EncodeRLP(_w) } ================================================ FILE: engine-primitives/engine-primitives/withdrawals_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engineprimitives_test import ( "testing" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" karalabessz "github.com/karalabe/ssz" zrntcommon "github.com/protolambda/zrnt/eth2/beacon/common" zspec "github.com/protolambda/zrnt/eth2/configs" ztree "github.com/protolambda/ztyp/tree" "github.com/stretchr/testify/require" ) func TestWithdrawals(t *testing.T) { t.Parallel() t.Run("SizeSSZ", func(t *testing.T) { t.Parallel() withdrawals := engineprimitives.Withdrawals{ {Index: 1, Validator: 2, Address: [20]byte{1, 2, 3}, Amount: 100}, {Index: 3, Validator: 4, Address: [20]byte{4, 5, 6}, Amount: 200}, } require.Equal(t, uint32(len(withdrawals))*44, karalabessz.Size(withdrawals)) }) t.Run("HashTreeRoot", func(t *testing.T) { t.Parallel() withdrawals := engineprimitives.Withdrawals{ {Index: 1, Validator: 2, Address: [20]byte{1, 2, 3}, Amount: 100}, {Index: 3, Validator: 4, Address: [20]byte{4, 5, 6}, Amount: 200}, } root := withdrawals.HashTreeRoot() require.NotEmpty(t, root) }) t.Run("HashTreeRoot Comparison", func(t *testing.T) { t.Parallel() withdrawals := engineprimitives.Withdrawals{ {Index: 1, Validator: 2, Address: [20]byte{1, 2, 3}, Amount: 100}, } zwithdrawals := zrntcommon.Withdrawals{ { Index: zrntcommon.WithdrawalIndex(withdrawals[0].Index), ValidatorIndex: zrntcommon.ValidatorIndex(withdrawals[0].Validator), Address: zrntcommon.Eth1Address(withdrawals[0].Address), Amount: zrntcommon.Gwei(withdrawals[0].Amount), }, } root := withdrawals.HashTreeRoot() hFn := ztree.GetHashFn() spec := zspec.Mainnet zroot := zwithdrawals.HashTreeRoot(spec, hFn) require.NotEmpty(t, root) require.Equal(t, root[:], zroot[:]) }) t.Run("HashTreeRoot", func(t *testing.T) { t.Parallel() withdrawals := engineprimitives.Withdrawals{ { Index: math.U64(1), Validator: math.ValidatorIndex(2), Address: common.ExecutionAddress{1, 2, 3}, Amount: math.Gwei(100), }, { Index: math.U64(3), Validator: math.ValidatorIndex(4), Address: common.ExecutionAddress{4, 5, 6}, Amount: math.Gwei(200), }, } root := withdrawals.HashTreeRoot() require.NotEmpty(t, root) // Verify that the root changes when the withdrawals change withdrawals[0].Amount = math.Gwei(150) newRoot := withdrawals.HashTreeRoot() require.NotEqual(t, root, newRoot) // Verify that the order of withdrawals matters reversedWithdrawals := engineprimitives.Withdrawals{ withdrawals[1], withdrawals[0], } reversedRoot := reversedWithdrawals.HashTreeRoot() require.NotEqual(t, newRoot, reversedRoot) }) t.Run("HashTreeRoot of Empty List", func(t *testing.T) { t.Parallel() emptyWithdrawals := engineprimitives.Withdrawals{} emptyRoot := emptyWithdrawals.HashTreeRoot() require.NotEmpty(t, emptyRoot) // Verify that the root of an empty list is different from a non-empty // list nonEmptyWithdrawals := engineprimitives.Withdrawals{ { Index: math.U64(1), Validator: math.ValidatorIndex(2), Address: common.ExecutionAddress{1, 2, 3}, Amount: math.Gwei(100), }, } nonEmptyRoot := nonEmptyWithdrawals.HashTreeRoot() require.NotEqual(t, emptyRoot, nonEmptyRoot) }) } ================================================ FILE: engine-primitives/errors/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package errors import ( "github.com/berachain/beacon-kit/errors" ) var ( // ErrPreDefinedJSONRPC is a catch-all error for all pre-defined json-rpc // errors. ErrPreDefinedJSONRPC = errors.New( "json-rpc error", ) // ErrUnknownPayload indicates an unavailable or non-existent payload // (JSON-RPC code -38001). ErrUnknownPayload = errors.New( "payload does not exist or is not available") // ErrInvalidForkchoiceState indicates an invalid fork choice state // (JSON-RPC code -38002). ErrInvalidForkchoiceState = errors.New( "invalid forkchoice state") // ErrInvalidPayloadAttributes indicates invalid or inconsistent payload // attributes // (JSON-RPC code -38003). ErrInvalidPayloadAttributes = errors.New( "payload attributes are invalid / inconsistent") // ErrRequestTooLarge indicates that the request is too large // (JSON-RPC code -38004). ErrRequestTooLarge = errors.New( "request is too large", ) // ErrUnknownPayloadStatus indicates an unknown payload status. ErrUnknownPayloadStatus = errors.New( "unknown payload status") // ErrAcceptedPayloadStatus indicates a payload status of ACCEPTED. ErrAcceptedPayloadStatus = errors.New( "payload status is ACCEPTED") // ErrSyncingPayloadStatus indicates a payload status of SYNCING. ErrSyncingPayloadStatus = errors.New( "payload status is SYNCING", ) // ErrInvalidPayloadStatus indicates an invalid payload status. ErrInvalidPayloadStatus = errors.New( "payload status is INVALID", ) // ErrNilForkchoiceResponse indicates a nil forkchoice response. ErrNilForkchoiceResponse = errors.New( "nil forkchoice response", ) // ErrNilBlobsBundle is returned when nil blobs bundle is received. ErrNilBlobsBundle = errors.New( "nil blobs bundle received from execution client") // ErrNilPayloadStatus is returned when nil payload status is received. ErrNilPayloadStatus = errors.New( "nil payload status received from execution client", ) // ErrEngineAPITimeout is returned when the engine API call times out. ErrEngineAPITimeout = errors.New( "engine API call timed out", ) ) ================================================ FILE: errors/mod.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package errors import ( stderrors "errors" "slices" "github.com/pkg/errors" ) // TODO: eventually swap out via build flags if we believe there is value // to doing so. // //nolint:gochecknoglobals // used an alias. var ( New = errors.New Wrap = errors.Wrap Wrapf = errors.Wrapf Is = errors.Is As = errors.As Join = stderrors.Join ) // IsAny checks if the provided error is any of the provided errors. func IsAny(err error, errs ...error) bool { for _, e := range errs { if errors.Is(err, e) { return true } } return false } // DetailedError is a custom error type that includes a message and a flag // indicating if the error is fatal. type DetailedError struct { // Msg is the error message. error // fatal indicates if the error is fatal. fatal bool } // WrapNonFatal returns the error message. func WrapNonFatal(err error) error { return &DetailedError{ error: err, fatal: false, } } // WrapFatal creates a new DetailedError with the // provided message and fatal flag. func WrapFatal(err error) error { return &DetailedError{ error: err, fatal: true, } } // IsFatal checks if the provided error is a // DetailedError and if it is fatal. func IsFatal(err error) bool { // If the error is nil, obviouisly it is not fatal. if err == nil { return false } // Otherwise check for our custom error. var customErr *DetailedError if errors.As(err, &customErr) { if customErr == nil { return false } // If the underlying error is nil, we // return false. if customErr.error == nil { return false } // Otherwise check the custom fatal field. return customErr.fatal } // All other errors are fatal. return true } // JoinFatal checks if any of the provided errors is a // DetailedError and if it is fatal. func JoinFatal(errs ...error) error { fatal := slices.ContainsFunc(errs, IsFatal) retErr := stderrors.Join(errs...) if fatal { return WrapFatal(retErr) } return WrapNonFatal(retErr) } ================================================ FILE: execution/README.md ================================================ # execution module The execution module is responsible for housing the `engineclient` which allows the consensus client to connect to the execution client. It also contains `engine` which implements the `ExecutionEngine` as defined in the Ethereum 2.0 Specification. ================================================ FILE: execution/client/client.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package client import ( "context" "fmt" "math/big" "sync" "time" "github.com/berachain/beacon-kit/errors" ethclient "github.com/berachain/beacon-kit/execution/client/ethclient" ethclientrpc "github.com/berachain/beacon-kit/execution/client/ethclient/rpc" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/net/http" "github.com/berachain/beacon-kit/primitives/net/jwt" ) // EngineClient is a struct that holds a pointer to an Eth1Client. type EngineClient struct { *ethclient.Client // cfg is the supplied configuration for the engine client. cfg *Config // logger is the logger for the engine client. logger log.Logger // eth1ChainID is the chain ID of the execution client. eth1ChainID *big.Int // clientMetrics is the metrics for the engine client. metrics *clientMetrics // capabilities is a map of capabilities that the execution client has. capabilities map[string]struct{} // connected will be set to true when we have successfully connected // to the execution client. connectedMu sync.RWMutex connected bool } // New creates a new engine client EngineClient. // It takes an Eth1Client as an argument and returns a pointer to an // EngineClient. func New( cfg *Config, logger log.Logger, jwtSecret *jwt.Secret, telemetrySink TelemetrySink, eth1ChainID *big.Int, ) *EngineClient { ethClient := ethclientrpc.NewClient( cfg.RPCDialURL.String(), jwtSecret, cfg.RPCJWTRefreshInterval, logger, ) // Enforcing minimum rpc timeout // The reason we do it is that we previously suggested a // 900 ms default, which is unnecessarily strict. // TODO: Not great enforcing this here since, in principle, // other services may use this config (not currently the case) // and we pass cfg by pointer, hence we do a global change. // The altenative of validating every config in ProvideConfig // should be considered (but logging there is trickier) if cfg.RPCTimeout < MinRPCTimeout { logger.Warn("Automatically raising RPCTimeout", "configured", cfg.RPCTimeout, "minimum", MinRPCTimeout, ) } cfg.RPCTimeout = max(MinRPCTimeout, cfg.RPCTimeout) if cfg.DeprecatedRPCRetries != 0 { logger.Warn("ignoring deprecated setting rpc-retries") } return &EngineClient{ cfg: cfg, logger: logger, Client: ethclient.New(ethClient), capabilities: make(map[string]struct{}), eth1ChainID: eth1ChainID, metrics: newClientMetrics(telemetrySink, logger), connected: false, } } // Name returns the name of the engine client. func (s *EngineClient) Name() string { return "engine-client" } // Start the engine client. func (s *EngineClient) Start(ctx context.Context) error { // Initialize the JWT token before making any RPC calls if err := s.Client.Initialize(); err != nil { return fmt.Errorf("failed to initialize RPC client: %w", err) } // Start the Client background refresh loop. go s.Client.Start(ctx) s.logger.Info( "Initializing connection to the execution client...", "dial_url", s.cfg.RPCDialURL.String(), ) // If the connection connection succeeds, we can skip the // connection initialization loop. if err := s.verifyChainIDAndConnection(ctx); err == nil { return nil } // Attempt to initialize the connection to the execution client. ticker := time.NewTicker(s.cfg.RPCStartupCheckInterval) defer ticker.Stop() for { select { case <-ctx.Done(): return ctx.Err() case <-ticker.C: s.logger.Info( "Waiting for execution client to start... 🍺🕔", "dial_url", s.cfg.RPCDialURL, ) if err := s.verifyChainIDAndConnection(ctx); err != nil { if errors.Is(err, ErrMismatchedEth1ChainID) { s.logger.Error(err.Error()) } continue } s.connectedMu.Lock() s.connected = true s.connectedMu.Unlock() return nil } } } func (s *EngineClient) Stop() error { return nil } func (s *EngineClient) IsConnected() bool { s.connectedMu.RLock() defer s.connectedMu.RUnlock() return s.connected } func (s *EngineClient) HasCapability(capability string) bool { _, ok := s.capabilities[capability] return ok } /* -------------------------------------------------------------------------- */ /* Helpers */ /* -------------------------------------------------------------------------- */ // verifyChainID dials the execution client and // ensures the chain ID is correct. func (s *EngineClient) verifyChainIDAndConnection( ctx context.Context, ) error { var ( err error chainID math.U64 ) defer func() { if err != nil { err = s.Client.Close() } }() // After the initial dial, check to make sure the chain ID is correct. chainID, err = s.Client.ChainID(ctx) if err != nil { if errors.Is(err, http.ErrUnauthorized) { // We always log this error as it is a critical error. s.logger.Error(UnauthenticatedConnectionErrorStr) } return err } // TODO: consider validating once when config is set or // client is initialized if !s.eth1ChainID.IsUint64() { err = errors.Wrapf( errors.New("provided chain ID is not uint64"), s.eth1ChainID.String(), ) return err } if chainID.Unwrap() != s.eth1ChainID.Uint64() { err = errors.Wrapf( ErrMismatchedEth1ChainID, "wanted chain ID %d, got %d", s.eth1ChainID, chainID, ) return err } // Log the chain ID. s.logger.Info( "Connected to execution client 🔌", "dial_url", s.cfg.RPCDialURL.String(), "chain_id", chainID.Unwrap(), "required_chain_id", s.eth1ChainID, ) // Exchange capabilities with the execution client. if _, err = s.ExchangeCapabilities(ctx); err != nil { s.logger.Error("failed to exchange capabilities", "err", err) return err } return nil } /* -------------------------------------------------------------------------- */ /* Getters */ /* -------------------------------------------------------------------------- */ func (s *EngineClient) GetRPCRetryInterval() time.Duration { return s.cfg.RPCRetryInterval } func (s *EngineClient) GetRPCMaxRetryInterval() time.Duration { return s.cfg.RPCMaxRetryInterval } ================================================ FILE: execution/client/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package client import ( "time" "github.com/berachain/beacon-kit/primitives/net/url" ) const ( MinRPCTimeout = 2 * time.Second defaultDialURL = "http://localhost:8551" defaultRPCRetryInterval = 100 * time.Millisecond defaultRPCMaxRetryInterval = 10 * time.Second defaultRPCStartupCheckInterval = 3 * time.Second defaultRPCJWTRefreshInterval = 30 * time.Second //#nosec:G101 // false positive. defaultJWTSecretPath = "./jwt.hex" ) // DefaultConfig is the default configuration for the engine client. func DefaultConfig() Config { //#nosec:G703 // ignoring on purpose since it is the default URL. dialURL, _ := url.NewFromRaw(defaultDialURL) return Config{ RPCDialURL: dialURL, RPCRetryInterval: defaultRPCRetryInterval, RPCMaxRetryInterval: defaultRPCMaxRetryInterval, RPCTimeout: MinRPCTimeout, RPCStartupCheckInterval: defaultRPCStartupCheckInterval, RPCJWTRefreshInterval: defaultRPCJWTRefreshInterval, JWTSecretPath: defaultJWTSecretPath, } } // Config is the configuration struct for the execution client. type Config struct { // RPCDialURL is the HTTP url of the execution client JSON-RPC endpoint. RPCDialURL *url.ConnectionURL `mapstructure:"rpc-dial-url"` // DeprecatedRPCRetries is deprecated. DeprecatedRPCRetries uint64 `mapstructure:"rpc-retries"` // RPCRetryInterval is the initial RPC backoff for repeated execution client calls. RPCRetryInterval time.Duration `mapstructure:"rpc-retry-interval"` // MaxRPCRetryInterval is the maximum RPC backoff for repeated execution client calls. RPCMaxRetryInterval time.Duration `mapstructure:"rpc-max-retry-interval"` // RPCTimeout is the RPC timeout for individual execution client calls. RPCTimeout time.Duration `mapstructure:"rpc-timeout"` // RPCStartupCheckInterval is the Interval for the startup check. RPCStartupCheckInterval time.Duration `mapstructure:"rpc-startup-check-interval"` // JWTRefreshInterval is the Interval for the JWT refresh. RPCJWTRefreshInterval time.Duration `mapstructure:"rpc-jwt-refresh-interval"` // JWTSecretPath is the path to the JWT secret. JWTSecretPath string `mapstructure:"jwt-secret-path"` } ================================================ FILE: execution/client/engine.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package client import ( "context" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" engineerrors "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/errors" ethclient "github.com/berachain/beacon-kit/execution/client/ethclient" "github.com/berachain/beacon-kit/primitives/common" ) /* -------------------------------------------------------------------------- */ /* NewPayload */ /* -------------------------------------------------------------------------- */ // NewPayload calls the engine_newPayloadVX method via JSON-RPC. func (s *EngineClient) NewPayload( ctx context.Context, req ctypes.NewPayloadRequest, ) (*common.ExecutionHash, error) { var ( startTime = time.Now() cctx, cancel = s.createContextWithTimeout(ctx) ) defer s.metrics.measureNewPayloadDuration(startTime) defer cancel() // Call the appropriate RPC method based on the payload version. result, err := s.Client.NewPayload(cctx, req) if err != nil { if errors.Is(err, engineerrors.ErrEngineAPITimeout) { s.metrics.incrementNewPayloadTimeout() } return nil, s.handleRPCError(err) } if result == nil { return nil, engineerrors.ErrNilPayloadStatus } // This case is only true when the payload is invalid, so // `processPayloadStatusResult` below will return an error. if validationErr := result.ValidationError; validationErr != nil { s.logger.Error( "Got a validation error in newPayload", "err", errors.New(*validationErr), ) } return processPayloadStatusResult(result) } /* -------------------------------------------------------------------------- */ /* ForkchoiceUpdated */ /* -------------------------------------------------------------------------- */ // ForkchoiceUpdated calls the engine_forkchoiceUpdatedV1 method via JSON-RPC. func (s *EngineClient) ForkchoiceUpdated( ctx context.Context, state *engineprimitives.ForkchoiceStateV1, attrs *engineprimitives.PayloadAttributes, forkVersion common.Version, ) (*engineprimitives.PayloadID, error) { var ( startTime = time.Now() cctx, cancel = s.createContextWithTimeout(ctx) ) defer s.metrics.measureForkchoiceUpdateDuration(startTime) defer cancel() // If the suggested fee recipient is not set, log a warning. if attrs != nil && attrs.GetSuggestedFeeRecipient() == (common.ExecutionAddress{}) { s.logger.Warn( "Suggested fee recipient is not configured 🔆", "fee-recipient", attrs.GetSuggestedFeeRecipient(), ) } result, err := s.Client.ForkchoiceUpdated(cctx, state, attrs, forkVersion) if err != nil { if errors.Is(err, engineerrors.ErrEngineAPITimeout) { s.metrics.incrementForkchoiceUpdateTimeout() } return nil, s.handleRPCError(err) } if result == nil { return nil, engineerrors.ErrNilForkchoiceResponse } _, err = processPayloadStatusResult(&result.PayloadStatus) if err != nil { return nil, err } return result.PayloadID, nil } /* -------------------------------------------------------------------------- */ /* GetPayload */ /* -------------------------------------------------------------------------- */ // GetPayload calls the engine_getPayloadVX method via JSON-RPC. It returns // the execution data as well as the blobs bundle. func (s *EngineClient) GetPayload( ctx context.Context, payloadID engineprimitives.PayloadID, forkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) { var ( startTime = time.Now() cctx, cancel = s.createContextWithTimeout(ctx) ) defer s.metrics.measureGetPayloadDuration(startTime) defer cancel() // Call and check for errors. result, err := s.Client.GetPayload(cctx, payloadID, forkVersion) if err != nil { if errors.Is(err, engineerrors.ErrEngineAPITimeout) { s.metrics.incrementGetPayloadTimeout() } return result, s.handleRPCError(err) } if result == nil { // Engine API returns the Unknown Payload (-38001) error if a nil result is returned. return result, engineerrors.ErrUnknownPayload } if result.GetBlobsBundle() == nil { return result, engineerrors.ErrNilBlobsBundle } return result, nil } // ExchangeCapabilities calls the engine_exchangeCapabilities method via // JSON-RPC. func (s *EngineClient) ExchangeCapabilities( ctx context.Context, ) ([]string, error) { result, err := s.Client.ExchangeCapabilities( ctx, ethclient.BeaconKitSupportedCapabilities(), ) if err != nil { return nil, err } // Capture and log the capabilities that the execution client has. for _, capability := range result { s.logger.Info("Exchanged capability", "capability", capability) s.capabilities[capability] = struct{}{} } // Log the capabilities that the execution client does not have. for _, capability := range ethclient.BeaconKitSupportedCapabilities() { if !s.HasCapability(capability) { s.logger.Warn( "Your execution client may require an update 🚸", "unsupported_capability", capability, ) } } return result, nil } ================================================ FILE: execution/client/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package client import ( engineerrors "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/net/http" jsonrpc "github.com/berachain/beacon-kit/primitives/net/json-rpc" ) const ( UnauthenticatedConnectionErrorStr = `could not verify execution chain ID as your connection is not authenticated. If connecting to your execution client via HTTP, you will need to set up JWT authentication...` ) var ( // ErrMismatchedEth1ChainID is returned when the chainID does not // match the expected chain ID. ErrMismatchedEth1ChainID = errors.New("mismatched chain ID") // ErrBadConnection indicates that the http.Client was unable to // establish a connection. ErrBadConnection = errors.New("connection error") ) // Handles errors received from the RPC server according to the specification. func (s *EngineClient) handleRPCError( err error, ) error { if err == nil { //nolint:nilerr // appease nilaway return err } // Check for timeout errors. if errors.Is(err, engineerrors.ErrEngineAPITimeout) { s.metrics.incrementEngineAPITimeout() return err } if http.IsTimeoutError(err) { s.metrics.incrementHTTPTimeoutCounter() return http.ErrTimeout } // Check for authorization errors if errors.Is(err, http.ErrUnauthorized) { return err } // Check for connection errors. var e jsonrpc.Error ok := errors.As(err, &e) if !ok || e == nil { return errors.Join(ErrBadConnection, err) } // Otherwise check for our engine errors. switch e.ErrorCode() { case -32700: s.metrics.incrementParseErrorCounter() return jsonrpc.ErrParse case -32600: s.metrics.incrementInvalidRequestCounter() return jsonrpc.ErrInvalidRequest case -32601: s.metrics.incrementMethodNotFoundCounter() return jsonrpc.ErrMethodNotFound case -32602: s.metrics.incrementInvalidParamsCounter() return jsonrpc.ErrInvalidParams case -32603: s.metrics.incrementInternalErrorCounter() return jsonrpc.ErrInternal case -38001: s.metrics.incrementUnknownPayloadErrorCounter() return engineerrors.ErrUnknownPayload case -38002: s.metrics.incrementInvalidForkchoiceStateCounter() return engineerrors.ErrInvalidForkchoiceState case -38003: s.metrics.incrementInvalidPayloadAttributesCounter() return engineerrors.ErrInvalidPayloadAttributes case -38004: s.metrics.incrementRequestTooLargeCounter() return engineerrors.ErrRequestTooLarge case -32000: s.metrics.incrementInternalServerErrorCounter() // // Only -32000 status codes are data errors in the RPC specification. // var errWithData rpc.DataError // errWithData, ok = err.(rpc.DataError) //nolint:errorlint // from // prysm. // if !ok { // return errors.Wrapf( // errors.Join(jsonrpc.ErrServer, err), // "got an unexpected data error in JSON-RPC response", // ) // } return errors.Wrapf(jsonrpc.ErrServer, "%v", e.Error()) default: return err } } // IsFatalError defines errors that indicate a bad request or an otherwise // unusable client. func IsFatalError(err error) bool { return jsonrpc.IsPreDefinedError(err) || errors.IsAny( err, ErrBadConnection, ) } // IsNonFatalError defines errors that should be ephemeral and can be // recovered from simply by retrying. func IsNonFatalError(err error) bool { return errors.IsAny( err, engineerrors.ErrEngineAPITimeout, http.ErrTimeout, ) } ================================================ FILE: execution/client/ethclient/constants.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ethclient // BeaconKitSupportedCapabilities returns the full list of capabilities // of the beacon kit client. func BeaconKitSupportedCapabilities() []string { return []string{ NewPayloadMethodV3, NewPayloadMethodV4, NewPayloadMethodV4P11, ForkchoiceUpdatedMethodV3, ForkchoiceUpdatedMethodV3P11, GetPayloadMethodV3, GetPayloadMethodV4, GetPayloadMethodV4P11, GetClientVersionV1, } } // Constants for JSON-RPC method names. const ( // NewPayloadMethodV3 for creating a new payload in Deneb. NewPayloadMethodV3 = "engine_newPayloadV3" // NewPayloadMethodV4 for creating a new payload in Electra. NewPayloadMethodV4 = "engine_newPayloadV4" // NewPayloadMethodV4P11 for creating a new payload for Electra1 (Pectra11). NewPayloadMethodV4P11 = "engine_newPayloadV4P11" // ForkchoiceUpdatedMethodV3 for updating fork choice in Deneb. ForkchoiceUpdatedMethodV3 = "engine_forkchoiceUpdatedV3" // ForkchoiceUpdatedMethodV4P11 for updating fork choice in Electra1 (Pectra11). ForkchoiceUpdatedMethodV3P11 = "engine_forkchoiceUpdatedV3P11" // GetPayloadMethodV3 for retrieving a payload in Deneb. GetPayloadMethodV3 = "engine_getPayloadV3" // GetPayloadMethodV4 for retrieving a payload in Electra. GetPayloadMethodV4 = "engine_getPayloadV4" // GetPayloadMethodV4P11 for retrieving a payload in Electra1 (Pectra11). GetPayloadMethodV4P11 = "engine_getPayloadV4P11" // BlockByHashMethod for retrieving a block by its hash. BlockByHashMethod = "eth_getBlockByHash" // BlockByNumberMethod for retrieving a block by its number. BlockByNumberMethod = "eth_getBlockByNumber" // ExchangeCapabilities for exchanging capabilities with the peer. ExchangeCapabilities = "engine_exchangeCapabilities" // GetClientVersionV1 for retrieving the capabilities of the peer. GetClientVersionV1 = "engine_getClientVersionV1" ) ================================================ FILE: execution/client/ethclient/engine.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ethclient import ( "context" "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/version" "github.com/ethereum/go-ethereum/beacon/engine" ) /* -------------------------------------------------------------------------- */ /* NewPayload */ /* -------------------------------------------------------------------------- */ // NewPayload calls the appropriate version of the Engine API NewPayload method. func (s *Client) NewPayload( ctx context.Context, req ctypes.NewPayloadRequest, ) (*engineprimitives.PayloadStatusV1, error) { forkVersion := req.GetForkVersion() switch { case version.IsBefore(forkVersion, version.Deneb()): // Versions before Deneb are not supported for calling NewPayload. return nil, ErrInvalidVersion case version.Equals(forkVersion, version.Deneb()), version.Equals(forkVersion, version.Deneb1()): // Use V3 for Deneb versions (Deneb and Deneb1). return s.NewPayloadV3( ctx, req.GetExecutionPayload(), req.GetVersionedHashes(), req.GetParentBeaconBlockRoot(), ) case version.Equals(forkVersion, version.Electra()): // Use V4 for Electra versions. executionRequests, err := req.GetEncodedExecutionRequests() if err != nil { return nil, err } return s.NewPayloadV4( ctx, req.GetExecutionPayload(), req.GetVersionedHashes(), req.GetParentBeaconBlockRoot(), executionRequests, ) case version.Equals(forkVersion, version.Electra1()), version.Equals(forkVersion, version.Fulu()): // Use V4P11 for Electra1 and Fulu versions. executionRequests, err := req.GetEncodedExecutionRequests() if err != nil { return nil, err } return s.NewPayloadV4P11( ctx, req.GetExecutionPayload(), req.GetVersionedHashes(), req.GetParentBeaconBlockRoot(), executionRequests, req.GetParentProposerPubkey(), ) default: return nil, ErrInvalidVersion } } // NewPayloadV3 calls the engine_newPayloadV3 via JSON-RPC. func (s *Client) NewPayloadV3( ctx context.Context, payload *ctypes.ExecutionPayload, versionedHashes []common.ExecutionHash, parentBlockRoot common.Root, ) (*engineprimitives.PayloadStatusV1, error) { result := &engineprimitives.PayloadStatusV1{} if err := s.Call( ctx, result, NewPayloadMethodV3, payload, versionedHashes, parentBlockRoot, ); err != nil { return nil, err } return result, nil } // NewPayloadV4 calls the engine_newPayloadV4 via JSON-RPC. func (s *Client) NewPayloadV4( ctx context.Context, payload *ctypes.ExecutionPayload, versionedHashes []common.ExecutionHash, parentBlockRoot common.Root, executionRequests []ctypes.EncodedExecutionRequest, ) (*engineprimitives.PayloadStatusV1, error) { result := &engineprimitives.PayloadStatusV1{} if err := s.Call( ctx, result, NewPayloadMethodV4, payload, versionedHashes, parentBlockRoot, executionRequests, ); err != nil { return nil, err } return result, nil } // NewPayloadV4P11 calls the engine_newPayloadV4P11 via JSON-RPC. func (s *Client) NewPayloadV4P11( ctx context.Context, payload *ctypes.ExecutionPayload, versionedHashes []common.ExecutionHash, parentBlockRoot common.Root, executionRequests []ctypes.EncodedExecutionRequest, parentProposerPubKey *crypto.BLSPubkey, ) (*engineprimitives.PayloadStatusV1, error) { result := &engineprimitives.PayloadStatusV1{} if err := s.Call( ctx, result, NewPayloadMethodV4P11, payload, versionedHashes, parentBlockRoot, executionRequests, parentProposerPubKey, ); err != nil { return nil, err } return result, nil } /* -------------------------------------------------------------------------- */ /* ForkchoiceUpdated */ /* -------------------------------------------------------------------------- */ // ForkchoiceUpdated calls the appropriate version of the Engine API ForkchoiceUpdated method. func (s *Client) ForkchoiceUpdated( ctx context.Context, state *engineprimitives.ForkchoiceStateV1, attrs any, forkVersion common.Version, ) (*engineprimitives.ForkchoiceResponseV1, error) { // V3 is used for beacon versions Deneb and onwards. switch { case version.IsBefore(forkVersion, version.Deneb()): // Versions before Deneb are not supported for calling ForkchoiceUpdated. return nil, ErrInvalidVersion case version.Equals(forkVersion, version.Deneb()), version.Equals(forkVersion, version.Deneb1()), version.Equals(forkVersion, version.Electra()): // Deneb versions and Electra use ForkchoiceUpdatedV3. return s.ForkchoiceUpdatedV3(ctx, state, attrs) case version.Equals(forkVersion, version.Electra1()), version.Equals(forkVersion, version.Fulu()): // Electra1 and Fulu use ForkchoiceUpdatedV3P11. return s.ForkchoiceUpdatedV3P11(ctx, state, attrs) default: return nil, ErrInvalidVersion } } // ForkchoiceUpdatedV3 calls the engine_forkchoiceUpdatedV3 method via JSON-RPC. func (s *Client) ForkchoiceUpdatedV3( ctx context.Context, state *engineprimitives.ForkchoiceStateV1, attrs any, ) (*engineprimitives.ForkchoiceResponseV1, error) { result := &engineprimitives.ForkchoiceResponseV1{} if err := s.Call( ctx, result, ForkchoiceUpdatedMethodV3, state, attrs, ); err != nil { return nil, err } if (result.PayloadStatus == engineprimitives.PayloadStatusV1{}) { return nil, ErrNilResponse } return result, nil } // ForkchoiceUpdatedV3P11 calls the engine_forkchoiceUpdatedV3P11 method via JSON-RPC. func (s *Client) ForkchoiceUpdatedV3P11( ctx context.Context, state *engineprimitives.ForkchoiceStateV1, attrs any, ) (*engineprimitives.ForkchoiceResponseV1, error) { result := &engineprimitives.ForkchoiceResponseV1{} if err := s.Call( ctx, result, ForkchoiceUpdatedMethodV3P11, state, attrs, ); err != nil { return nil, err } if (result.PayloadStatus == engineprimitives.PayloadStatusV1{}) { return nil, ErrNilResponse } return result, nil } /* -------------------------------------------------------------------------- */ /* GetPayload */ /* -------------------------------------------------------------------------- */ // GetPayload calls the appropriate version of the Engine API GetPayload method. func (s *Client) GetPayload( ctx context.Context, payloadID engineprimitives.PayloadID, forkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) { switch { case version.IsBefore(forkVersion, version.Deneb()): // Versions before Deneb are not supported for calling GetPayload. return nil, ErrInvalidVersion case version.Equals(forkVersion, version.Deneb()), version.Equals(forkVersion, version.Deneb1()): return s.GetPayloadV3(ctx, payloadID, forkVersion) case version.Equals(forkVersion, version.Electra()): return s.GetPayloadV4(ctx, payloadID, forkVersion) case version.Equals(forkVersion, version.Electra1()), version.Equals(forkVersion, version.Fulu()): return s.GetPayloadV4P11(ctx, payloadID, forkVersion) default: return nil, ErrInvalidVersion } } // GetPayloadV3 calls the engine_getPayloadV3 method via JSON-RPC. func (s *Client) GetPayloadV3( ctx context.Context, payloadID engineprimitives.PayloadID, forkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) { result := ctypes.NewEmptyExecutionPayloadEnvelope[*engineprimitives.BlobsBundleV1](forkVersion) if err := s.Call(ctx, result, GetPayloadMethodV3, payloadID); err != nil { return nil, fmt.Errorf("failed GetPayloadV3 call: %w", err) } return result, nil } // GetPayloadV4 calls the engine_getPayloadV4 method via JSON-RPC. func (s *Client) GetPayloadV4( ctx context.Context, payloadID engineprimitives.PayloadID, forkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) { result := ctypes.NewEmptyExecutionPayloadEnvelope[*engineprimitives.BlobsBundleV1](forkVersion) if err := s.Call(ctx, result, GetPayloadMethodV4, payloadID); err != nil { return nil, fmt.Errorf("failed GetPayloadV4 call: %w", err) } return result, nil } // GetPayloadV4P11 calls the engine_getPayloadV4P11 method via JSON-RPC. func (s *Client) GetPayloadV4P11( ctx context.Context, payloadID engineprimitives.PayloadID, forkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) { result := ctypes.NewEmptyExecutionPayloadEnvelope[*engineprimitives.BlobsBundleV1](forkVersion) if err := s.Call(ctx, result, GetPayloadMethodV4P11, payloadID); err != nil { return nil, fmt.Errorf("failed GetPayloadV4P11 call: %w", err) } return result, nil } /* -------------------------------------------------------------------------- */ /* Other */ /* -------------------------------------------------------------------------- */ // ExchangeCapabilities calls the engine_exchangeCapabilities method via JSON-RPC. func (s *Client) ExchangeCapabilities( ctx context.Context, capabilities []string, ) ([]string, error) { result := make([]string, 0) if err := s.Call( ctx, &result, ExchangeCapabilities, &capabilities, ); err != nil { return nil, err } return result, nil } // GetClientVersionV1 calls the engine_getClientVersionV1 method via JSON-RPC. func (s *Client) GetClientVersionV1( ctx context.Context, ) ([]engineprimitives.ClientVersionV1, error) { result := make([]engineprimitives.ClientVersionV1, 0) // NOTE: although the ethereum spec does not require us passing a // clientversion as param, it seems some clients require it and even // enforce a valid Code. if err := s.Call( ctx, &result, GetClientVersionV1, engine.ClientVersionV1{Code: "GE"}, ); err != nil { return nil, err } return result, nil } ================================================ FILE: execution/client/ethclient/engine_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ethclient_test import ( "context" "testing" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus-types/types/mocks" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/execution/client/ethclient" "github.com/berachain/beacon-kit/execution/client/ethclient/rpc" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/testing/utils" "github.com/stretchr/testify/require" ) // TestGetPayloadV3NeverReturnsEmptyPayload shows that execution payload // returned by ethClient is not nil. func TestGetPayloadV3NeverReturnsEmptyPayload(t *testing.T) { t.Parallel() c := ethclient.New(&stubRPCClient{t: t}) var ( ctx = t.Context() payloadID engineprimitives.PayloadID forkVersion = version.Deneb1() ) pe, err := c.GetPayloadV3(ctx, payloadID, forkVersion) require.NoError(t, err) // check that execution payload is not nil require.NotNil(t, pe.GetExecutionPayload()) } // TestNewPayloadWithValidVersion tests that NewPayload correctly handles Deneb version. func TestNewPayloadWithValidVersion(t *testing.T) { t.Parallel() c := ethclient.New(&stubRPCClient{t: t}) ctx := t.Context() block := utils.GenerateValidBeaconBlock(t, version.Deneb1()) newPayloadRequest, err := ctypes.BuildNewPayloadRequestFromFork(block, nil) if err != nil { return } _, err = c.NewPayload(ctx, newPayloadRequest) require.NoError(t, err) } // TestNewPayloadWithInvalidVersion tests that NewPayload returns ErrInvalidVersion for Capella. func TestNewPayloadWithInvalidVersion(t *testing.T) { t.Parallel() c := ethclient.New(&stubRPCClient{t: t}) ctx := t.Context() n := mocks.NewPayloadRequest{} n.On("GetForkVersion").Return(version.Capella()) _, err := c.NewPayload(ctx, &n) require.ErrorIs(t, err, ethclient.ErrInvalidVersion) } // TestForkchoiceUpdatedWithValidVersion tests that ForkchoiceUpdated correctly handles Deneb version. func TestForkchoiceUpdatedWithValidVersion(t *testing.T) { t.Parallel() c := ethclient.New(&stubRPCClient{t: t}) ctx := t.Context() state := &engineprimitives.ForkchoiceStateV1{} attrs := struct{}{} forkVersion := version.Deneb1() _, err := c.ForkchoiceUpdated(ctx, state, attrs, forkVersion) require.NoError(t, err) } func TestForkchoiceUpdatedWithValidVersion2(t *testing.T) { t.Parallel() c := ethclient.New(&stubRPCClient{t: t}) ctx := t.Context() state := &engineprimitives.ForkchoiceStateV1{} attrs := struct{}{} forkVersion := version.Deneb1() _, err := c.ForkchoiceUpdated(ctx, state, attrs, forkVersion) require.NoError(t, err) } // TestForkchoiceUpdatedWithInvalidVersion tests that ForkchoiceUpdated returns ErrInvalidVersion for Capella. func TestForkchoiceUpdatedWithInvalidVersion(t *testing.T) { t.Parallel() c := ethclient.New(&stubRPCClient{t: t}) ctx := t.Context() state := &engineprimitives.ForkchoiceStateV1{} attrs := struct{}{} forkVersion := version.Capella() _, err := c.ForkchoiceUpdated(ctx, state, attrs, forkVersion) require.ErrorIs(t, err, ethclient.ErrInvalidVersion) } // TestGetPayloadWithValidVersion tests that GetPayload correctly handles >= Deneb version. func TestGetPayloadWithValidVersion(t *testing.T) { t.Parallel() c := ethclient.New(&stubRPCClient{t: t}) ctx := t.Context() var payloadID engineprimitives.PayloadID forkVersion := version.Deneb1() _, err := c.GetPayload(ctx, payloadID, forkVersion) require.NoError(t, err) } // TestGetPayloadWithInvalidVersion tests that GetPayload returns ErrInvalidVersion for Capella. func TestGetPayloadWithInvalidVersion(t *testing.T) { t.Parallel() c := ethclient.New(&stubRPCClient{t: t}) ctx := t.Context() var payloadID engineprimitives.PayloadID forkVersion := version.Capella() _, err := c.GetPayload(ctx, payloadID, forkVersion) require.ErrorIs(t, err, ethclient.ErrInvalidVersion) } var _ rpc.Client = (*stubRPCClient)(nil) type stubRPCClient struct { t *testing.T } func (tc *stubRPCClient) Initialize() error { return nil } func (tc *stubRPCClient) Start(context.Context) {} func (tc *stubRPCClient) Call(_ context.Context, target any, _ string, _ ...any) error { tc.t.Helper() require.NotNil(tc.t, target) // If calling ForkchoiceUpdated, set the PayloadStatus to not empty to // avoid returning ErrNilResponse. if fcu, ok := target.(*engineprimitives.ForkchoiceResponseV1); ok { fcu.PayloadStatus = engineprimitives.PayloadStatusV1{ Status: "not empty", } } return nil } func (tc *stubRPCClient) Close() error { return nil } ================================================ FILE: execution/client/ethclient/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ethclient import "github.com/berachain/beacon-kit/errors" var ( // ErrNilResponse is an error that is returned when the response is nil. ErrNilResponse = errors.New("nil response") // ErrNotImplemented is an error that is returned when a method is not // implemented. ErrNotImplemented = errors.New("not implemented") // ErrInvalidVersion is an error that is returned when the version is // invalid. ErrInvalidVersion = errors.New("invalid version") ) ================================================ FILE: execution/client/ethclient/eth.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ethclient import ( "context" "fmt" "math/big" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/math" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rpc" ) // ChainID retrieves the current chain ID. func (s *Client) ChainID( ctx context.Context, ) (math.U64, error) { var result math.U64 if err := s.Call(ctx, &result, "eth_chainId"); err != nil { return 0, err } return result, nil } // TODO: Figure out how to unhood all this. // FilterLogs executes a filter query. func (s *Client) FilterLogs( ctx context.Context, q ethereum.FilterQuery, ) ([]types.Log, error) { var result []types.Log arg, err := toFilterArg(q) if err != nil { return nil, err } return result, s.Call(ctx, &result, "eth_getLogs", arg) } // SubscribeFilterLogs(ctx context.Context, q FilterQuery, ch chan<- types.Log) // (Subscription, error) func (s *Client) SubscribeFilterLogs( context.Context, ethereum.FilterQuery, chan<- types.Log, ) (ethereum.Subscription, error) { return nil, errors.New("not implemented") } func toFilterArg(q ethereum.FilterQuery) (interface{}, error) { arg := map[string]interface{}{ "address": q.Addresses, "topics": q.Topics, } if q.BlockHash != nil { arg["blockHash"] = *q.BlockHash if q.FromBlock != nil || q.ToBlock != nil { return nil, errors.New( "cannot specify both BlockHash and FromBlock/ToBlock", ) } } else { if q.FromBlock == nil { arg["fromBlock"] = "0x0" } else { arg["fromBlock"] = toBlockNumArg(q.FromBlock) } arg["toBlock"] = toBlockNumArg(q.ToBlock) } return arg, nil } func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } if number.Sign() >= 0 { return hexutil.EncodeBig(number) } // It's negative. if number.IsInt64() { return rpc.BlockNumber(number.Int64()).String() } // It's negative and large, which is invalid. return fmt.Sprintf("", number) } ================================================ FILE: execution/client/ethclient/ethclient.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ethclient import ( "github.com/berachain/beacon-kit/execution/client/ethclient/rpc" ) // Client - Ethereum rpc client. type Client struct { rpc.Client } // New create new rpc client with given url. func New(client rpc.Client) *Client { rpc := &Client{ Client: client, } return rpc } ================================================ FILE: execution/client/ethclient/rpc/client.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package rpc import ( "bytes" "context" "fmt" "io" "net/http" "sync" "time" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/encoding/json" beaconhttp "github.com/berachain/beacon-kit/primitives/net/http" "github.com/berachain/beacon-kit/primitives/net/jwt" ) var _ Client = (*client)(nil) type Client interface { Initialize() error Start(context.Context) Call(ctx context.Context, target any, method string, params ...any) error Close() error } // client is an Ethereum RPC client that provides a // convenient way to interact with an Ethereum node. type client struct { // url is the URL of the RPC endpoint. url string // client is the HTTP client used to make RPC calls. client *http.Client // reqPool is a sync.Pool for reusing RPC request objects. reqPool *sync.Pool // jwtSecret is the JWT secret used for authentication. jwtSecret *jwt.Secret // jwtRefreshInterval is the interval at which the JWT token should be // refreshed. jwtRefreshInterval time.Duration // logger is the logger for the RPC client. logger log.Logger // mu protects header for concurrent access. mu sync.RWMutex // header is the HTTP header used for RPC requests. header http.Header } // New create new rpc client with given url. func NewClient( url string, secret *jwt.Secret, jwtRefreshInterval time.Duration, logger log.Logger, ) Client { rpc := &client{ url: url, client: http.DefaultClient, reqPool: &sync.Pool{ New: func() any { return &Request{ ID: 1, JSONRPC: "2.0", } }, }, jwtSecret: secret, jwtRefreshInterval: jwtRefreshInterval, header: http.Header{"Content-Type": {"application/json"}}, logger: logger, } return rpc } // Start starts the rpc client. func (rpc *client) Start(ctx context.Context) { ticker := time.NewTicker(rpc.jwtRefreshInterval) defer ticker.Stop() // Initial JWT update is done in Initialize() now for { select { case <-ctx.Done(): return case <-ticker.C: if err := rpc.updateHeader(); err != nil { rpc.logger.Error("Failed to refresh JWT token", "error", err) continue } } } } // Initialize sets up the initial JWT token. This should be called before // making any RPC calls to ensure a fresh token is available. func (rpc *client) Initialize() error { rpc.logger.Info("Initializing RPC client with fresh JWT token") if err := rpc.updateHeader(); err != nil { return fmt.Errorf("failed to initialize JWT token: %w", err) } return nil } // Close closes the RPC client. func (rpc *client) Close() error { rpc.client.CloseIdleConnections() return nil } // Call calls the given method with the given parameters. func (rpc *client) Call( ctx context.Context, target any, method string, params ...any, ) error { result, err := rpc.callRaw(ctx, method, params...) if err != nil { return err } if target == nil { return nil } return json.Unmarshal(result, target) } // Call returns raw response of method call. func (rpc *client) callRaw( ctx context.Context, method string, params ...any, ) (json.RawMessage, error) { // Pull a request from the pool, we know that it already has the correct // JSONRPC version and ID set. //nolint:errcheck // this is safe. request := rpc.reqPool.Get().(*Request) defer rpc.reqPool.Put(request) // Update the request with the method and params. request.Method = method request.Params = params body, err := json.Marshal(request) if err != nil { return nil, err } req, err := http.NewRequestWithContext( ctx, http.MethodPost, rpc.url, bytes.NewBuffer(body), ) if err != nil { return nil, err } rpc.mu.RLock() req.Header = rpc.header.Clone() rpc.mu.RUnlock() response, err := rpc.client.Do(req) //#nosec:G704 // URL is operator-configured RPC endpoint. if err != nil { return nil, err } if response == nil { return nil, ErrNilResponse } defer response.Body.Close() data, err := io.ReadAll(response.Body) if err != nil { return nil, err } switch response.StatusCode { case http.StatusOK: // OK: just proceed (no return) case http.StatusUnauthorized: return nil, beaconhttp.ErrUnauthorized default: // Return a default error return nil, fmt.Errorf("unexpected status code %d: %s", response.StatusCode, string(data)) } resp := new(Response) if err = json.Unmarshal(data, resp); err != nil { return nil, err } if resp.Error != nil { return nil, *resp.Error } return resp.Result, nil } ================================================ FILE: execution/client/ethclient/rpc/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package rpc import "errors" var ErrNilResponse = errors.New("nil response") ================================================ FILE: execution/client/ethclient/rpc/header.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package rpc // updateHeader builds an http.Header that has the JWT token // attached for authorization. func (rpc *client) updateHeader() error { // Build the JWT token. token, err := rpc.jwtSecret.BuildSignedToken() if err != nil { return err } // Add the JWT token to the headers. Access header safely. rpc.mu.Lock() defer rpc.mu.Unlock() rpc.header.Set("Authorization", "Bearer "+token) return nil } ================================================ FILE: execution/client/ethclient/rpc/types.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package rpc import ( "fmt" "github.com/berachain/beacon-kit/primitives/encoding/json" ) // Request represents an Ethereum JSON-RPC request. type Request struct { // ID is the request ID. ID int `json:"id"` // JSONRPC is the JSON-RPC version. JSONRPC string `json:"jsonrpc"` // Method is the RPC method to be called. Method string `json:"method"` // Params are the parameters for the RPC method. Params any `json:"params"` } // Response represents an Ethereum JSON-RPC response. type Response struct { // ID is the request ID. ID int `json:"id"` // JSONRPC is the JSON-RPC version. JSONRPC string `json:"jsonrpc"` // Result is the raw JSON-RPC response result. Result json.RawMessage `json:"result"` // Error is the JSON-RPC error, if any. Error *Error `json:"error"` } // Error represents an Ethereum JSON-RPC error. type Error struct { // Code is the error code. Code int `json:"code"` // Message is the error message. Message string `json:"message"` } // Error returns a formatted error string. func (err Error) Error() string { return fmt.Sprintf("Error %d (%s)", err.Code, err.Message) } // ErrorCode returns the number identifying the JSON-RPC error. func (err Error) ErrorCode() int { return err.Code } ================================================ FILE: execution/client/helpers.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package client import ( "context" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" engineerrors "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/primitives/common" ) // createContextWithTimeout creates a context with a timeout and returns it // along with the cancel function. func (s *EngineClient) createContextWithTimeout( ctx context.Context, ) (context.Context, context.CancelFunc) { dctx, cancel := context.WithTimeoutCause( ctx, s.cfg.RPCTimeout, engineerrors.ErrEngineAPITimeout, ) return dctx, cancel } // processPayloadStatusResult processes the payload status result and // returns the latest valid hash or an error. func processPayloadStatusResult( result *engineprimitives.PayloadStatusV1, ) (*common.ExecutionHash, error) { switch result.Status { case engineprimitives.PayloadStatusValid: return result.LatestValidHash, nil case engineprimitives.PayloadStatusAccepted: return nil, engineerrors.ErrAcceptedPayloadStatus case engineprimitives.PayloadStatusSyncing: return nil, engineerrors.ErrSyncingPayloadStatus case engineprimitives.PayloadStatusInvalid: return nil, engineerrors.ErrInvalidPayloadStatus default: return nil, engineerrors.ErrUnknownPayloadStatus } } ================================================ FILE: execution/client/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package client import ( "time" ) // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { // IncrementCounter increments a counter metric identified by the provided // keys. IncrementCounter(key string, args ...string) // MeasureSince measures the time since the provided start time, // identified by the provided keys. MeasureSince(key string, start time.Time, args ...string) } ================================================ FILE: execution/client/metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package client import ( "time" "github.com/berachain/beacon-kit/log" ) // clientMetrics is a struct that contains metrics for the engine. type clientMetrics struct { // TelemetrySink is the sink for the metrics. sink TelemetrySink // logger is the logger for the engineMetrics. logger log.Logger } // newClientMetrics creates a new engineMetrics. func newClientMetrics( sink TelemetrySink, logger log.Logger, ) *clientMetrics { return &clientMetrics{ sink: sink, logger: logger, } } // measureForkchoiceUpdateDuration measures the duration of the forkchoice // update. func (cm *clientMetrics) measureForkchoiceUpdateDuration(startTime time.Time) { // TODO: Add Labels. cm.sink.MeasureSince( "beacon_kit.execution.client.forkchoice_update_duration", startTime, ) } // measureNewPayloadDuration measures the duration of the new payload. func (cm *clientMetrics) measureNewPayloadDuration(startTime time.Time) { // TODO: Add Labels. cm.sink.MeasureSince( "beacon_kit.execution.client.new_payload_duration", startTime, ) } // measureGetPayloadDuration measures the duration of the get payload. func (cm *clientMetrics) measureGetPayloadDuration(startTime time.Time) { // TODO: Add Labels. cm.sink.MeasureSince( "beacon_kit.execution.client.get_payload_duration", startTime, ) } // incrementEngineAPITimeout increments the timeout counter for // general engine api timeouts. func (cm *clientMetrics) incrementEngineAPITimeout() { cm.incrementTimeoutCounter( "beacon_kit.execution.client.engine_api") } // incrementForkchoiceUpdateTimeout increments the timeout counter // for forkchoice update. func (cm *clientMetrics) incrementForkchoiceUpdateTimeout() { cm.incrementTimeoutCounter( "beacon_kit.execution.client.forkchoice_update_duration") } // incrementNewPayloadTimeout increments the timeout counter for // new payload. func (cm *clientMetrics) incrementNewPayloadTimeout() { cm.incrementTimeoutCounter( "beacon_kit.execution.client.new_payload_duration") } // incrementGetPayloadTimeout increments the timeout counter for // get payload. func (cm *clientMetrics) incrementGetPayloadTimeout() { cm.incrementTimeoutCounter( "beacon_kit.execution.client.get_payload_duration") } // incrementHTTPTimeout increments the timeout counter for HTTP. func (cm *clientMetrics) incrementHTTPTimeoutCounter() { cm.incrementTimeoutCounter("beacon_kit.execution.client.http") } // incrementTimeoutCounter increments the timeout counter for // the given metric. func (cm *clientMetrics) incrementTimeoutCounter(metricName string) { cm.sink.IncrementCounter(metricName + "_timeout") } // incrementParseErrorCounter increments the parse error counter // for the given metric. func (cm *clientMetrics) incrementParseErrorCounter() { cm.sink.IncrementCounter("beacon_kit.execution.client.parse_error") } // incrementInvalidRequestCounter increments the invalid request counter // for the given metric. func (cm *clientMetrics) incrementInvalidRequestCounter() { cm.incrementErrorCounter("beacon_kit.execution.client.invalid_request") } // incrementMethodNotFoundCounter increments the method not found counter // for the given metric. func (cm *clientMetrics) incrementMethodNotFoundCounter() { cm.incrementErrorCounter("beacon_kit.execution.client.method_not_found") } // incrementInvalidParamsCounter increments the invalid params counter // for the given metric. func (cm *clientMetrics) incrementInvalidParamsCounter() { cm.incrementErrorCounter("beacon_kit.execution.client.invalid_params") } // incrementInternalErrorCounter increments the internal error counter // for the given metric. func (cm *clientMetrics) incrementInternalErrorCounter() { cm.incrementErrorCounter("beacon_kit.execution.client.internal_error") } // incrementUnknownPayloadErrorCounter increments the unknown payload error // counter // for the given metric. func (cm *clientMetrics) incrementUnknownPayloadErrorCounter() { cm.incrementErrorCounter( "beacon_kit.execution.client.unknown_payload_error", ) } // incrementInvalidForkchoiceStateCounter increments the invalid forkchoice // state counter // for the given metric. func (cm *clientMetrics) incrementInvalidForkchoiceStateCounter() { cm.incrementErrorCounter( "beacon_kit.execution.client.invalid_forkchoice_state", ) } // incrementInvalidPayloadAttributesCounter increments the invalid payload // attributes counter // for the given metric. func (cm *clientMetrics) incrementInvalidPayloadAttributesCounter() { cm.incrementErrorCounter( "beacon_kit.execution.client.invalid_payload_attributes", ) } // incrementRequestTooLargeCounter increments the request too large counter // for the given metric. func (cm *clientMetrics) incrementRequestTooLargeCounter() { cm.incrementErrorCounter("beacon_kit.execution.client.request_too_large") } // incrementInternalServerErrorCounter increments the internal server error // counter // for the given metric. func (cm *clientMetrics) incrementInternalServerErrorCounter() { cm.incrementErrorCounter( "beacon_kit.execution.client.internal_server_error", ) } // incrementErrorCounter increments the error counter for // the given metric. func (cm *clientMetrics) incrementErrorCounter(metricName string) { cm.sink.IncrementCounter(metricName) } ================================================ FILE: execution/deposit/contract.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "context" "errors" "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/gethlib/deposit" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/ethereum/go-ethereum/accounts/abi/bind" gethcommon "github.com/ethereum/go-ethereum/common" ) // WrappedDepositContract is a struct that holds a pointer to an ABI. type WrappedDepositContract struct { // DepositContractFilterer is a pointer to the codegen ABI binding. deposit.DepositContractFilterer } // NewWrappedDepositContract creates a new DepositContract. func NewWrappedDepositContract( address common.ExecutionAddress, client bind.ContractFilterer, ) (*WrappedDepositContract, error) { contract, err := deposit.NewDepositContractFilterer( gethcommon.Address(address), client, ) if err != nil { return nil, err } else if contract == nil { return nil, errors.New("contract must not be nil") } return &WrappedDepositContract{ DepositContractFilterer: *contract, }, nil } // ReadDeposits reads deposits from the deposit contract. func (dc *WrappedDepositContract) ReadDeposits( ctx context.Context, fromBlock math.U64, toBlock math.U64, ) ([]*ctypes.Deposit, error) { logs, err := dc.FilterDeposit( &bind.FilterOpts{ Context: ctx, Start: fromBlock.Unwrap(), End: toBlock.UnwrapPtr(), }, ) if err != nil { return nil, err } deposits := make([]*ctypes.Deposit, 0) for logs.Next() { var ( cred bytes.B32 pubKey bytes.B48 sign bytes.B96 ) pubKey, err = bytes.ToBytes48(logs.Event.Pubkey) if err != nil { return nil, fmt.Errorf("failed reading pub key: %w", err) } cred, err = bytes.ToBytes32(logs.Event.Credentials) if err != nil { return nil, fmt.Errorf("failed reading credentials: %w", err) } sign, err = bytes.ToBytes96(logs.Event.Signature) if err != nil { return nil, fmt.Errorf("failed reading signature: %w", err) } deposit := &ctypes.Deposit{ Pubkey: pubKey, Credentials: ctypes.WithdrawalCredentials(cred), Amount: math.U64(logs.Event.Amount), Signature: sign, Index: logs.Event.Index, } deposits = append(deposits, deposit) } return deposits, nil } ================================================ FILE: execution/deposit/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "context" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/math" ) // Contract is the ABI for the deposit contract. type Contract interface { // ReadDeposits reads deposits from the deposit contract. ReadDeposits( ctx context.Context, fromBlock math.U64, toBlock math.U64, ) ([]*ctypes.Deposit, error) } ================================================ FILE: execution/engine/engine.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engine import ( "context" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" engineerrors "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" "github.com/cenkalti/backoff/v5" ) // Engine is Beacon-Kit's implementation of the `ExecutionEngine` // from the Ethereum 2.0 Specification. type Engine struct { // ec is the engine client that the engine will use to // interact with the execution layer. ec *client.EngineClient // logger is the logger for the engine. logger log.Logger // metrics is the metrics for the engine. metrics *engineMetrics } // New creates a new Engine. func New( engineClient *client.EngineClient, logger log.Logger, telemtrySink TelemetrySink, ) *Engine { return &Engine{ ec: engineClient, logger: logger, metrics: newEngineMetrics(telemtrySink, logger), } } // GetPayload returns the payload and blobs bundle for the given slot. func (ee *Engine) GetPayload( ctx context.Context, req *ctypes.GetPayloadRequest, ) (ctypes.BuiltExecutionPayloadEnv, error) { return ee.ec.GetPayload( ctx, req.PayloadID, req.ForkVersion, ) } // NotifyForkchoiceUpdate notifies the execution client of a forkchoice update. func (ee *Engine) NotifyForkchoiceUpdate( ctx context.Context, req *ctypes.ForkchoiceUpdateRequest, ) (*engineprimitives.PayloadID, error) { var ( engineAPIBackoff = ee.newBackoff() hasPayloadAttributes = req.PayloadAttributes != nil ) return backoff.Retry( ctx, func() (*engineprimitives.PayloadID, error) { // Log and call the forkchoice update. ee.metrics.markNotifyForkchoiceUpdateCalled(hasPayloadAttributes) payloadID, err := ee.ec.ForkchoiceUpdated( ctx, req.State, req.PayloadAttributes, req.ForkVersion, ) // NotifyForkchoiceUpdate gets called under two circumstances: // 1. Payload Building (During PrepareProposal or // optimistically in ProcessProposal) // 2. FinalizeBlock // We'll discriminate error handling based on these. switch { case err == nil: ee.metrics.markForkchoiceUpdateValid(req.State, hasPayloadAttributes, payloadID) // If we reached here, we have a VALID status and a nil payload ID, // we should log a warning and error. if payloadID == nil && hasPayloadAttributes { ee.logger.Warn( "Received nil payload ID on VALID engine response", "head_eth1_hash", req.State.HeadBlockHash, "safe_eth1_hash", req.State.SafeBlockHash, "finalized_eth1_hash", req.State.FinalizedBlockHash, ) // Do not retry, return the error. return nil, backoff.Permanent(ErrNilPayloadOnValidResponse) } // We've received a valid response, no more retries. return payloadID, nil case errors.IsAny(err, engineerrors.ErrSyncingPayloadStatus): ee.logger.Info("NotifyForkchoiceUpdate: EL syncing. Retrying...") ee.metrics.markForkchoiceUpdateSyncing(req.State, err) return nil, err case client.IsNonFatalError(err): ee.logger.Info( "NotifyForkchoiceUpdate: EL returns non fatal error. Retrying...", "err", err, ) ee.metrics.markForkchoiceUpdateNonFatalError(err) return nil, err case errors.Is(err, engineerrors.ErrInvalidPayloadStatus): // During payload building, then there is an invalid payload and should error. // During FinalizeBlock, something is broken because this should never happen. ee.logger.Error("NotifyForkchoiceUpdate: EL returned invalid payload.") ee.metrics.markForkchoiceUpdateInvalid(req.State, err) return nil, backoff.Permanent(err) case client.IsFatalError(err): ee.logger.Info( "NotifyForkchoiceUpdate: EL returns fatal error.", "err", err, ) ee.metrics.markForkchoiceUpdateFatalError(err) return nil, backoff.Permanent(err) default: ee.logger.Info( "NotifyForkchoiceUpdate: EL returns unknown error.", "err", err, ) ee.metrics.markForkchoiceUpdateUndefinedError(err) return nil, backoff.Permanent(err) } }, backoff.WithBackOff(engineAPIBackoff), backoff.WithMaxTries(0), // 0 for infinite retries. backoff.WithMaxElapsedTime(0), // 0 for infinite max elapsed time. ) } // NotifyNewPayload notifies the execution client of the new payload. // //nolint:funlen // error handling and logs func (ee *Engine) NotifyNewPayload( ctx context.Context, req ctypes.NewPayloadRequest, retryOnSyncingStatus bool, ) error { var ( engineAPIBackoff = ee.newBackoff() payloadHash = req.GetExecutionPayload().GetBlockHash() payloadParentHash = req.GetExecutionPayload().GetParentHash() ) _, err := backoff.Retry( ctx, func() (*common.ExecutionHash, error) { ee.metrics.markNewPayloadCalled(payloadHash, payloadParentHash) lastValidHash, err := ee.ec.NewPayload( ctx, req, ) // NotifyNewPayload gets called under three circumstances: // 1. ProcessProposal state transition // 2. FinalizeBlock state transition // We'll discriminate error handling based on these. switch { case err == nil: ee.metrics.markNewPayloadValid(payloadHash, payloadParentHash) // We've received a valid response, no more retries. return lastValidHash, nil case errors.IsAny(err, engineerrors.ErrSyncingPayloadStatus, engineerrors.ErrAcceptedPayloadStatus): ee.logger.Info( "NotifyNewPayload: EL returns non valid status. Retrying...", "err", err, ) ee.metrics.markNewPayloadAcceptedSyncingPayloadStatus(err, payloadHash, payloadParentHash) // During ProcessProposal, we must be able to verify the // block. Since we do not send a NotifyForkchoiceUpdate // during ProcessProposal, we must retry here until EL is // synced. if retryOnSyncingStatus { return nil, err } // During FinalizeBlock, we do not need to verify the block. // We do not need to retry here, as the following call to // NotifyForkchoiceUpdate will inform the EL of the new head // and then wait for it to sync. // Don't return error here, because we want to send the forkchoice update regardless. ee.logger.Warn( "NotifyNewPayload: pushed new payload to SYNCING node.", "error", err, "blockNum", req.GetExecutionPayload().GetNumber(), "blockHash", payloadHash, ) return &common.ExecutionHash{}, nil case client.IsNonFatalError(err): ee.logger.Info( "NotifyNewPayload: EL returns non fatal error. Retrying...", "err", err, ) // Protect against possible nil value. if lastValidHash == nil { lastValidHash = &common.ExecutionHash{} } ee.metrics.markNewPayloadNonFatalError(payloadHash, *lastValidHash, err) return nil, err case errors.Is(err, engineerrors.ErrInvalidPayloadStatus): ee.logger.Error("NotifyNewPayload: EL returned invalid payload.") ee.metrics.markNewPayloadInvalidPayloadStatus(payloadHash) // During payload building, then there is an invalid // payload and should error. // During FinalizeBlock, something is broken because // this should never happen. return nil, backoff.Permanent(err) case client.IsFatalError(err): ee.logger.Error( "NotifyNewPayload: EL returns fatal error.", "err", err, ) // Protect against possible nil value. if lastValidHash == nil { lastValidHash = &common.ExecutionHash{} } ee.metrics.markNewPayloadFatalError(payloadHash, *lastValidHash, err) return nil, backoff.Permanent(err) default: ee.logger.Error( "NotifyNewPayload: EL returns unknown error.", "err", err, ) ee.metrics.markNewPayloadUndefinedError(payloadHash, err) // Do not retry on unknown errors. return nil, backoff.Permanent(err) } }, backoff.WithBackOff(engineAPIBackoff), backoff.WithMaxTries(0), // 0 for infinite retries. backoff.WithMaxElapsedTime(0), // 0 for infinite max elapsed time. ) return err } func (ee *Engine) newBackoff() *backoff.ExponentialBackOff { // Configure backoff. This will retry maxRetries number of times. // Specifying 0 maxRetries will retry infinitely. Between each retry, it // will wait RPCRetryInterval amount of time. This backoff will increase // exponentially until it reaches RPCMaxRetryInterval. engineAPIBackoff := backoff.NewExponentialBackOff() engineAPIBackoff.InitialInterval = ee.ec.GetRPCRetryInterval() engineAPIBackoff.MaxInterval = ee.ec.GetRPCMaxRetryInterval() return engineAPIBackoff } ================================================ FILE: execution/engine/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engine import "github.com/berachain/beacon-kit/errors" var ( // ErrBadBlockProduced represents an error when the beacon // chain has produced a bad block. ErrBadBlockProduced = errors.New( "proposer has produced a bad block, RIP walrus", ) // ErrNilPayloadOnValidResponse is returned when a nil payload ID is // received on a VALID engine response. ErrNilPayloadOnValidResponse = errors.New( "received nil payload ID on VALID engine response", ) ) ================================================ FILE: execution/engine/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engine // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { // IncrementCounter increments a counter metric identified by the provided // keys. IncrementCounter(key string, args ...string) } ================================================ FILE: execution/engine/metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package engine import ( "fmt" "strconv" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" engineerrors "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" ) // engineMetrics is a struct that contains metrics for the engine. type engineMetrics struct { // TelemetrySink is the sink for the metrics. sink TelemetrySink // logger is the logger for the engineMetrics. logger log.Logger } // newEngineMetrics creates a new engineMetrics. func newEngineMetrics( sink TelemetrySink, logger log.Logger, ) *engineMetrics { return &engineMetrics{ sink: sink, logger: logger, } } // markNewPayloadCalled increments the counter for new payload calls. func (em *engineMetrics) markNewPayloadCalled( payloadHash common.ExecutionHash, parentHash common.ExecutionHash, ) { em.sink.IncrementCounter( "beacon_kit.execution.engine.new_payload", "payload_block_hash", payloadHash.Hex(), "payload_parent_block_hash", parentHash.Hex(), ) } // markNewPayloadValid increments the counter for valid payloads. func (em *engineMetrics) markNewPayloadValid( payloadHash common.ExecutionHash, parentHash common.ExecutionHash, ) { em.logger.Debug( "Inserted new payload into execution chain", "payload_block_hash", payloadHash, "payload_parent_block_hash", parentHash, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.new_payload_valid", ) } // markNewPayloadAcceptedSyncingPayloadStatus increments // the counter for accepted syncing payload status. func (em *engineMetrics) markNewPayloadAcceptedSyncingPayloadStatus( errStatus error, payloadHash common.ExecutionHash, parentHash common.ExecutionHash, ) { status := "accepted" if errors.Is(errStatus, engineerrors.ErrSyncingPayloadStatus) { status = "syncing" } em.logger.Warn( fmt.Sprintf("Received %s payload status during new payload. Awaiting execution client to finish sync.", status), "payload_block_hash", payloadHash, "parent_hash", parentHash, ) em.sink.IncrementCounter( fmt.Sprintf("beacon_kit.execution.engine.new_payload_%s_payload_status", status), ) } // markNewPayloadInvalidPayloadStatus increments the counter // for invalid payload status. func (em *engineMetrics) markNewPayloadInvalidPayloadStatus( payloadHash common.ExecutionHash, ) { em.logger.Error( "Received invalid payload status during new payload call", "payload_block_hash", payloadHash, "parent_hash", payloadHash, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.new_payload_invalid_payload_status", ) } // markNewPayloadFatalError increments the counter for JSON-RPC errors. func (em *engineMetrics) markNewPayloadNonFatalError( payloadHash common.ExecutionHash, lastValidHash common.ExecutionHash, err error, ) { em.logger.Error( "Received non-fatal error during new payload call", "payload_block_hash", payloadHash, "parent_hash", payloadHash, "last_valid_hash", lastValidHash, "error", err, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.new_payload_non_fatal_error", "error", err.Error(), ) } // markNewPayloadFatalError increments the counter for JSON-RPC errors. func (em *engineMetrics) markNewPayloadFatalError( payloadHash common.ExecutionHash, lastValidHash common.ExecutionHash, err error, ) { em.logger.Error( "Received fatal error during new payload call", "payload_block_hash", payloadHash, "parent_hash", payloadHash, "last_valid_hash", lastValidHash, "error", err, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.new_payload_fatal_error", "error", err.Error(), ) } // markNewPayloadUndefinedError increments the counter for undefined errors. func (em *engineMetrics) markNewPayloadUndefinedError( payloadHash common.ExecutionHash, err error, ) { em.logger.Error( "Received undefined error during new payload call", "payload_block_hash", payloadHash, "parent_hash", payloadHash, "error", err, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.new_payload_undefined_error", "error", err.Error(), ) } // markNotifyForkchoiceUpdateCalled increments the counter for // notify forkchoice update calls. func (em *engineMetrics) markNotifyForkchoiceUpdateCalled( hasPayloadAttributes bool, ) { em.sink.IncrementCounter( "beacon_kit.execution.engine.forkchoice_update", "has_payload_attributes", strconv.FormatBool(hasPayloadAttributes), ) } // markForkchoiceUpdateValid increments the counter for valid forkchoice // updates. func (em *engineMetrics) markForkchoiceUpdateValid( state *engineprimitives.ForkchoiceStateV1, hasPayloadAttributes bool, payloadID *engineprimitives.PayloadID, ) { args := []any{ "head_block_hash", state.HeadBlockHash, "safe_block_hash", state.SafeBlockHash, "finalized_block_hash", state.FinalizedBlockHash, "with_attributes", hasPayloadAttributes, } if hasPayloadAttributes { args = append(args, "payload_id", payloadID) } em.logger.Debug("Forkchoice updated", args...) em.sink.IncrementCounter( "beacon_kit.execution.engine.forkchoice_update_valid", ) } // markForkchoiceUpdateSyncing increments // the counter for accepted syncing forkchoice updates. func (em *engineMetrics) markForkchoiceUpdateSyncing( state *engineprimitives.ForkchoiceStateV1, err error, ) { em.logger.Warn( "Received syncing payload status during forkchoice update. Awaiting execution client to finish sync.", "head_block_hash", state.HeadBlockHash, "safe_block_hash", state.SafeBlockHash, "finalized_block_hash", state.FinalizedBlockHash, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.forkchoice_update_syncing", "error", err.Error(), ) } // markForkchoiceUpdateInvalid increments the counter // for invalid forkchoice updates. func (em *engineMetrics) markForkchoiceUpdateInvalid( state *engineprimitives.ForkchoiceStateV1, err error, ) { em.logger.Error( "Received invalid payload status during forkchoice update call", "head_block_hash", state.HeadBlockHash, "safe_block_hash", state.SafeBlockHash, "finalized_block_hash", state.FinalizedBlockHash, "error", err, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.forkchoice_update_invalid", "error", err.Error(), ) } // markForkchoiceUpdateFatalError increments the counter for JSON-RPC errors // during forkchoice updates. func (em *engineMetrics) markForkchoiceUpdateFatalError(err error) { em.logger.Error( "Received fatal error during forkchoice update call", "error", err, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.forkchoice_update_fatal_error", "error", err.Error(), ) } // markForkchoiceUpdateNonFatalError increments the counter for JSON-RPC errors // during forkchoice updates. func (em *engineMetrics) markForkchoiceUpdateNonFatalError(err error) { em.logger.Error( "Received non-fatal error during forkchoice update call", "error", err, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.forkchoice_update_non_fatal_error", "error", err.Error(), ) } // markForkchoiceUpdateUndefinedError increments the counter for undefined // errors during forkchoice updates. func (em *engineMetrics) markForkchoiceUpdateUndefinedError(err error) { em.logger.Error( "Received undefined execution engine error during forkchoice update call", "error", err, ) em.sink.IncrementCounter( "beacon_kit.execution.engine.forkchoice_update_undefined_error", "error", err.Error(), ) } ================================================ FILE: execution/requests/eip7002/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip7002 import "context" type rpcClient interface { Call(ctx context.Context, target any, method string, params ...any) error } ================================================ FILE: execution/requests/eip7002/withdrawal.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip7002 import ( "bytes" "context" "encoding/binary" "math/big" "github.com/berachain/beacon-kit/errors" beaconbytes "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/ethereum/go-ethereum/params" ) type feeOpts struct { To string `json:"to"` } // GetWithdrawalFee returns the withdrawal fee in wei. See https://eips.ethereum.org/EIPS/eip-7002 for more. // Only expected to be used in test cases. func GetWithdrawalFee(ctx context.Context, client rpcClient) (*big.Int, error) { var result string feeInput := &feeOpts{ To: params.WithdrawalQueueAddress.String(), } err := client.Call(ctx, &result, "eth_call", feeInput) if err != nil { return nil, err } n, ok := new(big.Int).SetString(result, 0) if !ok { return nil, errors.New("error converting hex string to big.Int") } return n, nil } // CreateWithdrawalRequestData returns the request body formatted as defined by the EIP-7002 specification. // Only expected to be used in test cases. func CreateWithdrawalRequestData(blsPubKey crypto.BLSPubkey, withdrawAmount math.Gwei) (beaconbytes.Bytes, error) { // Create a buffer to hold the packed encoding. var packed bytes.Buffer if _, err := packed.Write(blsPubKey[:]); err != nil { return nil, err } // Write the uint64 value in big-endian order. if err := binary.Write(&packed, binary.BigEndian, withdrawAmount); err != nil { return nil, err } return packed.Bytes(), nil } ================================================ FILE: execution/requests/eip7002/withdrawal_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip7002_test import ( "encoding/hex" "math" "testing" "github.com/berachain/beacon-kit/execution/requests/eip7002" "github.com/berachain/beacon-kit/primitives/crypto" beaconmath "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) func TestCreateWithdrawalRequestData(t *testing.T) { t.Parallel() tests := []struct { name string pubKey string withdrawAmount uint64 expected string }{ { name: "Normal case", pubKey: "acaf2e8ec309513be835104abc43c8ab27e0665701482d3ce11c592e6ec22910804e8378b0be0f6eb92f452d086599fd", withdrawAmount: 10, expected: "0xacaf2e8ec309513be835104abc43c8ab27e0665701482d3ce11c592e6ec22910804e8378b0be0f6eb92f452d086599fd000000000000000a", }, { name: "All zeros pubkey with zero withdrawal", pubKey: "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", withdrawAmount: 0, expected: "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, { name: "All f's pubkey with max withdrawal", pubKey: "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", withdrawAmount: math.MaxUint64, expected: "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() blsPubKeyBytes, err := hex.DecodeString(tt.pubKey) require.NoError(t, err) blsPubKey := crypto.BLSPubkey(blsPubKeyBytes) // Call the function under test. result, err := eip7002.CreateWithdrawalRequestData(blsPubKey, beaconmath.U64(tt.withdrawAmount)) require.NoError(t, err) // Compare the resulting bytes with the expected output. require.Equal(t, tt.expected, result.String()) }) } } ================================================ FILE: execution/requests/eip7251/consolidation.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip7251 import ( "bytes" "context" "math/big" "github.com/berachain/beacon-kit/errors" beaconbytes "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/ethereum/go-ethereum/params" ) type feeOpts struct { To string `json:"to"` } // GetConsolidationFee returns the consolidation fee in wei. See https://eips.ethereum.org/EIPS/eip-7251 for more. // This is only expected to be used in tests to form test scenarios. func GetConsolidationFee(ctx context.Context, client rpcClient) (*big.Int, error) { var result string feeInput := &feeOpts{ To: params.ConsolidationQueueAddress.String(), } err := client.Call(ctx, &result, "eth_call", feeInput) if err != nil { return nil, err } n, ok := new(big.Int).SetString(result, 0) if !ok { return nil, errors.New("error converting hex string to big.Int") } return n, nil } // CreateConsolidationRequestData returns the request body formatted as defined by the EIP-7251 specification. // This is only expected to be used in tests to form test scenarios. func CreateConsolidationRequestData(sourcePubKey, targetPubKey crypto.BLSPubkey) (beaconbytes.Bytes, error) { // Create a buffer to hold the packed encoding. var packed bytes.Buffer if _, err := packed.Write(sourcePubKey[:]); err != nil { return nil, err } if _, err := packed.Write(targetPubKey[:]); err != nil { return nil, err } return packed.Bytes(), nil } ================================================ FILE: execution/requests/eip7251/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip7251 import "context" type rpcClient interface { Call(ctx context.Context, target any, method string, params ...any) error } ================================================ FILE: gethlib/deposit/contract.abigen.go ================================================ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. package deposit import ( "errors" "math/big" "strings" ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" ) // Reference imports to suppress errors if they are not otherwise used. var ( _ = errors.New _ = big.NewInt _ = strings.NewReader _ = ethereum.NotFound _ = bind.Bind _ = common.Big1 _ = types.BloomLookup _ = event.NewSubscription _ = abi.ConvertType ) // DepositContractMetaData contains all meta data concerning the DepositContract contract. var DepositContractMetaData = &bind.MetaData{ ABI: "[{\"type\":\"function\",\"name\":\"acceptOperatorChange\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"cancelOperatorChange\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"deposit\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"credentials\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"signature\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"operator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"payable\"},{\"type\":\"function\",\"name\":\"depositCount\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"genesisDepositsRoot\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getOperator\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"queuedOperator\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"queuedTimestamp\",\"type\":\"uint96\",\"internalType\":\"uint96\"},{\"name\":\"newOperator\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"requestOperatorChange\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"newOperator\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"pure\"},{\"type\":\"event\",\"name\":\"Deposit\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"credentials\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"amount\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"},{\"name\":\"signature\",\"type\":\"bytes\",\"indexed\":false,\"internalType\":\"bytes\"},{\"name\":\"index\",\"type\":\"uint64\",\"indexed\":false,\"internalType\":\"uint64\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorChangeCancelled\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":true,\"internalType\":\"bytes\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorChangeQueued\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":true,\"internalType\":\"bytes\"},{\"name\":\"queuedOperator\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"currentOperator\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"queuedTimestamp\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"OperatorUpdated\",\"inputs\":[{\"name\":\"pubkey\",\"type\":\"bytes\",\"indexed\":true,\"internalType\":\"bytes\"},{\"name\":\"newOperator\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"},{\"name\":\"previousOperator\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"DepositNotMultipleOfGwei\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"DepositValueTooHigh\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InsufficientDeposit\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidCredentialsLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidPubKeyLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"InvalidSignatureLength\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotEnoughTime\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotNewOperator\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"NotOperator\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"OperatorAlreadySet\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ZeroAddress\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ZeroOperatorOnFirstDeposit\",\"inputs\":[]}]", Bin: "0x6080604052348015600e575f80fd5b506110f28061001c5f395ff3fe608060405260043610610093575f3560e01c8063577212fe11610066578063c53925d91161004c578063c53925d914610231578063e12cf4cb14610250578063fea7ab7714610263575f80fd5b8063577212fe146101cc5780639eaffa96146101ed575f80fd5b806301ffc9a7146100975780632dfdf0b5146100cb5780633523f9bd14610103578063560036ec14610126575b5f80fd5b3480156100a2575f80fd5b506100b66100b1366004610c22565b610282565b60405190151581526020015b60405180910390f35b3480156100d6575f80fd5b505f546100ea9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100c2565b34801561010e575f80fd5b5061011860015481565b6040519081526020016100c2565b348015610131575f80fd5b50610193610140366004610c95565b80516020818301810180516003825292820191909301209152546bffffffffffffffffffffffff8116906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1682565b604080516bffffffffffffffffffffffff909316835273ffffffffffffffffffffffffffffffffffffffff9091166020830152016100c2565b3480156101d7575f80fd5b506101eb6101e6366004610dca565b61031a565b005b3480156101f8575f80fd5b5061020c610207366004610dca565b6103f0565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c2565b34801561023c575f80fd5b506101eb61024b366004610dca565b610431565b6101eb61025e366004610e2c565b610658565b34801561026e575f80fd5b506101eb61027d366004610edb565b6109ab565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061031457507fffffffff0000000000000000000000000000000000000000000000000000000082167f136f920d00000000000000000000000000000000000000000000000000000000145b92915050565b6002828260405161032c929190610f2b565b908152604051908190036020019020543373ffffffffffffffffffffffffffffffffffffffff9091161461038c576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6003828260405161039e929190610f2b565b9081526040519081900360200181205f90556103bd9083908390610f2b565b604051908190038120907f1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db905f90a25050565b5f60028383604051610403929190610f2b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f60038383604051610444929190610f2b565b908152604051908190036020019020805490915073ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000820416906bffffffffffffffffffffffff163382146104c6576040517f819a0d0b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6bffffffffffffffffffffffff42166104e26201518083610f67565b6bffffffffffffffffffffffff161115610528576040517fe8966d7a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6002868660405161053b929190610f2b565b9081526040519081900360200181205473ffffffffffffffffffffffffffffffffffffffff16915083906002906105759089908990610f2b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556003906105da9088908890610f2b565b9081526040519081900360200181205f90556105f99087908790610f2b565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a2505050505050565b60308614610692576040517f9f10647200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b602084146106cc576040517fb39bca1600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60608214610706576040517f4be6321b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f73ffffffffffffffffffffffffffffffffffffffff166002888860405161072f929190610f2b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16036108765773ffffffffffffffffffffffffffffffffffffffff81166107a7576040517f51969a7a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80600288886040516107ba929190610f2b565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff00000000000000000000000000000000000000009093169290921790915561081c9088908890610f2b565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff841683525f6020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a26108c4565b73ffffffffffffffffffffffffffffffffffffffff8116156108c4576040517fc4142b4100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f6108cd610b5d565b9050633b9aca0067ffffffffffffffff82161015610917576040517f0e1eddda00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f80547f68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46918a918a918a918a9187918b918b9167ffffffffffffffff16908061095f83610f8b565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff160217905550604051610999989796959493929190610ffe565b60405180910390a15050505050505050565b5f600284846040516109be929190610f2b565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff169050338114610a1f576040517f7c214f0400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216610a6c576040517fd92e233d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f60038585604051610a7f929190610f2b565b908152604051908190036020018120426bffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff86166c01000000000000000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000161781559150610af79086908690610f2b565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff8681168452851660208401524283830152905190917f7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f919081900360600190a25050505050565b5f610b6c633b9aca0034611096565b15610ba3576040517f40567b3800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f610bb2633b9aca00346110a9565b905067ffffffffffffffff811115610bf6576040517f2aa6673400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610c005f34610c05565b919050565b5f385f3884865af1610c1e5763b12d13eb5f526004601cfd5b5050565b5f60208284031215610c32575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610c61575f80fd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215610ca5575f80fd5b813567ffffffffffffffff811115610cbb575f80fd5b8201601f81018413610ccb575f80fd5b803567ffffffffffffffff811115610ce557610ce5610c68565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715610d5157610d51610c68565b604052818152828201602001861015610d68575f80fd5b816020840160208301375f91810160200191909152949350505050565b5f8083601f840112610d95575f80fd5b50813567ffffffffffffffff811115610dac575f80fd5b602083019150836020828501011115610dc3575f80fd5b9250929050565b5f8060208385031215610ddb575f80fd5b823567ffffffffffffffff811115610df1575f80fd5b610dfd85828601610d85565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610c00575f80fd5b5f805f805f805f6080888a031215610e42575f80fd5b873567ffffffffffffffff811115610e58575f80fd5b610e648a828b01610d85565b909850965050602088013567ffffffffffffffff811115610e83575f80fd5b610e8f8a828b01610d85565b909650945050604088013567ffffffffffffffff811115610eae575f80fd5b610eba8a828b01610d85565b9094509250610ecd905060608901610e09565b905092959891949750929550565b5f805f60408486031215610eed575f80fd5b833567ffffffffffffffff811115610f03575f80fd5b610f0f86828701610d85565b9094509250610f22905060208501610e09565b90509250925092565b818382375f9101908152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6bffffffffffffffffffffffff818116838216019081111561031457610314610f3a565b5f67ffffffffffffffff821667ffffffffffffffff8103610fae57610fae610f3a565b60010192915050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60a081525f61101160a083018a8c610fb7565b828103602084015261102481898b610fb7565b905067ffffffffffffffff871660408401528281036060840152611049818688610fb7565b91505067ffffffffffffffff831660808301529998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f826110a4576110a4611069565b500690565b5f826110b7576110b7611069565b50049056fea264697066735822122069227307258cbe8f29985bb4f3e283b1b03d5c0cbab8add81bf3c22e3d13729664736f6c634300081a0033", } // DepositContractABI is the input ABI used to generate the binding from. // Deprecated: Use DepositContractMetaData.ABI instead. var DepositContractABI = DepositContractMetaData.ABI // DepositContractBin is the compiled bytecode used for deploying new contracts. // Deprecated: Use DepositContractMetaData.Bin instead. var DepositContractBin = DepositContractMetaData.Bin // DeployDepositContract deploys a new Ethereum contract, binding an instance of DepositContract to it. func DeployDepositContract(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *DepositContract, error) { parsed, err := DepositContractMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err } if parsed == nil { return common.Address{}, nil, nil, errors.New("GetABI returned nil") } address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(DepositContractBin), backend) if err != nil { return common.Address{}, nil, nil, err } return address, tx, &DepositContract{DepositContractCaller: DepositContractCaller{contract: contract}, DepositContractTransactor: DepositContractTransactor{contract: contract}, DepositContractFilterer: DepositContractFilterer{contract: contract}}, nil } // DepositContract is an auto generated Go binding around an Ethereum contract. type DepositContract struct { DepositContractCaller // Read-only binding to the contract DepositContractTransactor // Write-only binding to the contract DepositContractFilterer // Log filterer for contract events } // DepositContractCaller is an auto generated read-only Go binding around an Ethereum contract. type DepositContractCaller struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } // DepositContractTransactor is an auto generated write-only Go binding around an Ethereum contract. type DepositContractTransactor struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } // DepositContractFilterer is an auto generated log filtering Go binding around an Ethereum contract events. type DepositContractFilterer struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } // DepositContractSession is an auto generated Go binding around an Ethereum contract, // with pre-set call and transact options. type DepositContractSession struct { Contract *DepositContract // Generic contract binding to set the session for CallOpts bind.CallOpts // Call options to use throughout this session TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } // DepositContractCallerSession is an auto generated read-only Go binding around an Ethereum contract, // with pre-set call options. type DepositContractCallerSession struct { Contract *DepositContractCaller // Generic contract caller binding to set the session for CallOpts bind.CallOpts // Call options to use throughout this session } // DepositContractTransactorSession is an auto generated write-only Go binding around an Ethereum contract, // with pre-set transact options. type DepositContractTransactorSession struct { Contract *DepositContractTransactor // Generic contract transactor binding to set the session for TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } // DepositContractRaw is an auto generated low-level Go binding around an Ethereum contract. type DepositContractRaw struct { Contract *DepositContract // Generic contract binding to access the raw methods on } // DepositContractCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. type DepositContractCallerRaw struct { Contract *DepositContractCaller // Generic read-only contract binding to access the raw methods on } // DepositContractTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. type DepositContractTransactorRaw struct { Contract *DepositContractTransactor // Generic write-only contract binding to access the raw methods on } // NewDepositContract creates a new instance of DepositContract, bound to a specific deployed contract. func NewDepositContract(address common.Address, backend bind.ContractBackend) (*DepositContract, error) { contract, err := bindDepositContract(address, backend, backend, backend) if err != nil { return nil, err } return &DepositContract{DepositContractCaller: DepositContractCaller{contract: contract}, DepositContractTransactor: DepositContractTransactor{contract: contract}, DepositContractFilterer: DepositContractFilterer{contract: contract}}, nil } // NewDepositContractCaller creates a new read-only instance of DepositContract, bound to a specific deployed contract. func NewDepositContractCaller(address common.Address, caller bind.ContractCaller) (*DepositContractCaller, error) { contract, err := bindDepositContract(address, caller, nil, nil) if err != nil { return nil, err } return &DepositContractCaller{contract: contract}, nil } // NewDepositContractTransactor creates a new write-only instance of DepositContract, bound to a specific deployed contract. func NewDepositContractTransactor(address common.Address, transactor bind.ContractTransactor) (*DepositContractTransactor, error) { contract, err := bindDepositContract(address, nil, transactor, nil) if err != nil { return nil, err } return &DepositContractTransactor{contract: contract}, nil } // NewDepositContractFilterer creates a new log filterer instance of DepositContract, bound to a specific deployed contract. func NewDepositContractFilterer(address common.Address, filterer bind.ContractFilterer) (*DepositContractFilterer, error) { contract, err := bindDepositContract(address, nil, nil, filterer) if err != nil { return nil, err } return &DepositContractFilterer{contract: contract}, nil } // bindDepositContract binds a generic wrapper to an already deployed contract. func bindDepositContract(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { parsed, err := DepositContractMetaData.GetAbi() if err != nil { return nil, err } return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil } // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. func (_DepositContract *DepositContractRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { return _DepositContract.Contract.DepositContractCaller.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. func (_DepositContract *DepositContractRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { return _DepositContract.Contract.DepositContractTransactor.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. func (_DepositContract *DepositContractRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { return _DepositContract.Contract.DepositContractTransactor.contract.Transact(opts, method, params...) } // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. func (_DepositContract *DepositContractCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { return _DepositContract.Contract.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. func (_DepositContract *DepositContractTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { return _DepositContract.Contract.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. func (_DepositContract *DepositContractTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { return _DepositContract.Contract.contract.Transact(opts, method, params...) } // DepositCount is a free data retrieval call binding the contract method 0x2dfdf0b5. // // Solidity: function depositCount() view returns(uint64) func (_DepositContract *DepositContractCaller) DepositCount(opts *bind.CallOpts) (uint64, error) { var out []interface{} err := _DepositContract.contract.Call(opts, &out, "depositCount") if err != nil { return *new(uint64), err } out0 := *abi.ConvertType(out[0], new(uint64)).(*uint64) return out0, err } // DepositCount is a free data retrieval call binding the contract method 0x2dfdf0b5. // // Solidity: function depositCount() view returns(uint64) func (_DepositContract *DepositContractSession) DepositCount() (uint64, error) { return _DepositContract.Contract.DepositCount(&_DepositContract.CallOpts) } // DepositCount is a free data retrieval call binding the contract method 0x2dfdf0b5. // // Solidity: function depositCount() view returns(uint64) func (_DepositContract *DepositContractCallerSession) DepositCount() (uint64, error) { return _DepositContract.Contract.DepositCount(&_DepositContract.CallOpts) } // GenesisDepositsRoot is a free data retrieval call binding the contract method 0x3523f9bd. // // Solidity: function genesisDepositsRoot() view returns(bytes32) func (_DepositContract *DepositContractCaller) GenesisDepositsRoot(opts *bind.CallOpts) ([32]byte, error) { var out []interface{} err := _DepositContract.contract.Call(opts, &out, "genesisDepositsRoot") if err != nil { return *new([32]byte), err } out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) return out0, err } // GenesisDepositsRoot is a free data retrieval call binding the contract method 0x3523f9bd. // // Solidity: function genesisDepositsRoot() view returns(bytes32) func (_DepositContract *DepositContractSession) GenesisDepositsRoot() ([32]byte, error) { return _DepositContract.Contract.GenesisDepositsRoot(&_DepositContract.CallOpts) } // GenesisDepositsRoot is a free data retrieval call binding the contract method 0x3523f9bd. // // Solidity: function genesisDepositsRoot() view returns(bytes32) func (_DepositContract *DepositContractCallerSession) GenesisDepositsRoot() ([32]byte, error) { return _DepositContract.Contract.GenesisDepositsRoot(&_DepositContract.CallOpts) } // GetOperator is a free data retrieval call binding the contract method 0x9eaffa96. // // Solidity: function getOperator(bytes pubkey) view returns(address) func (_DepositContract *DepositContractCaller) GetOperator(opts *bind.CallOpts, pubkey []byte) (common.Address, error) { var out []interface{} err := _DepositContract.contract.Call(opts, &out, "getOperator", pubkey) if err != nil { return *new(common.Address), err } out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) return out0, err } // GetOperator is a free data retrieval call binding the contract method 0x9eaffa96. // // Solidity: function getOperator(bytes pubkey) view returns(address) func (_DepositContract *DepositContractSession) GetOperator(pubkey []byte) (common.Address, error) { return _DepositContract.Contract.GetOperator(&_DepositContract.CallOpts, pubkey) } // GetOperator is a free data retrieval call binding the contract method 0x9eaffa96. // // Solidity: function getOperator(bytes pubkey) view returns(address) func (_DepositContract *DepositContractCallerSession) GetOperator(pubkey []byte) (common.Address, error) { return _DepositContract.Contract.GetOperator(&_DepositContract.CallOpts, pubkey) } // QueuedOperator is a free data retrieval call binding the contract method 0x560036ec. // // Solidity: function queuedOperator(bytes ) view returns(uint96 queuedTimestamp, address newOperator) func (_DepositContract *DepositContractCaller) QueuedOperator(opts *bind.CallOpts, arg0 []byte) (struct { QueuedTimestamp *big.Int NewOperator common.Address }, error) { var out []interface{} err := _DepositContract.contract.Call(opts, &out, "queuedOperator", arg0) outstruct := new(struct { QueuedTimestamp *big.Int NewOperator common.Address }) if err != nil { return *outstruct, err } outstruct.QueuedTimestamp = *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) outstruct.NewOperator = *abi.ConvertType(out[1], new(common.Address)).(*common.Address) return *outstruct, err } // QueuedOperator is a free data retrieval call binding the contract method 0x560036ec. // // Solidity: function queuedOperator(bytes ) view returns(uint96 queuedTimestamp, address newOperator) func (_DepositContract *DepositContractSession) QueuedOperator(arg0 []byte) (struct { QueuedTimestamp *big.Int NewOperator common.Address }, error) { return _DepositContract.Contract.QueuedOperator(&_DepositContract.CallOpts, arg0) } // QueuedOperator is a free data retrieval call binding the contract method 0x560036ec. // // Solidity: function queuedOperator(bytes ) view returns(uint96 queuedTimestamp, address newOperator) func (_DepositContract *DepositContractCallerSession) QueuedOperator(arg0 []byte) (struct { QueuedTimestamp *big.Int NewOperator common.Address }, error) { return _DepositContract.Contract.QueuedOperator(&_DepositContract.CallOpts, arg0) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // // Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) func (_DepositContract *DepositContractCaller) SupportsInterface(opts *bind.CallOpts, interfaceId [4]byte) (bool, error) { var out []interface{} err := _DepositContract.contract.Call(opts, &out, "supportsInterface", interfaceId) if err != nil { return *new(bool), err } out0 := *abi.ConvertType(out[0], new(bool)).(*bool) return out0, err } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // // Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) func (_DepositContract *DepositContractSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _DepositContract.Contract.SupportsInterface(&_DepositContract.CallOpts, interfaceId) } // SupportsInterface is a free data retrieval call binding the contract method 0x01ffc9a7. // // Solidity: function supportsInterface(bytes4 interfaceId) pure returns(bool) func (_DepositContract *DepositContractCallerSession) SupportsInterface(interfaceId [4]byte) (bool, error) { return _DepositContract.Contract.SupportsInterface(&_DepositContract.CallOpts, interfaceId) } // AcceptOperatorChange is a paid mutator transaction binding the contract method 0xc53925d9. // // Solidity: function acceptOperatorChange(bytes pubkey) returns() func (_DepositContract *DepositContractTransactor) AcceptOperatorChange(opts *bind.TransactOpts, pubkey []byte) (*types.Transaction, error) { return _DepositContract.contract.Transact(opts, "acceptOperatorChange", pubkey) } // AcceptOperatorChange is a paid mutator transaction binding the contract method 0xc53925d9. // // Solidity: function acceptOperatorChange(bytes pubkey) returns() func (_DepositContract *DepositContractSession) AcceptOperatorChange(pubkey []byte) (*types.Transaction, error) { return _DepositContract.Contract.AcceptOperatorChange(&_DepositContract.TransactOpts, pubkey) } // AcceptOperatorChange is a paid mutator transaction binding the contract method 0xc53925d9. // // Solidity: function acceptOperatorChange(bytes pubkey) returns() func (_DepositContract *DepositContractTransactorSession) AcceptOperatorChange(pubkey []byte) (*types.Transaction, error) { return _DepositContract.Contract.AcceptOperatorChange(&_DepositContract.TransactOpts, pubkey) } // CancelOperatorChange is a paid mutator transaction binding the contract method 0x577212fe. // // Solidity: function cancelOperatorChange(bytes pubkey) returns() func (_DepositContract *DepositContractTransactor) CancelOperatorChange(opts *bind.TransactOpts, pubkey []byte) (*types.Transaction, error) { return _DepositContract.contract.Transact(opts, "cancelOperatorChange", pubkey) } // CancelOperatorChange is a paid mutator transaction binding the contract method 0x577212fe. // // Solidity: function cancelOperatorChange(bytes pubkey) returns() func (_DepositContract *DepositContractSession) CancelOperatorChange(pubkey []byte) (*types.Transaction, error) { return _DepositContract.Contract.CancelOperatorChange(&_DepositContract.TransactOpts, pubkey) } // CancelOperatorChange is a paid mutator transaction binding the contract method 0x577212fe. // // Solidity: function cancelOperatorChange(bytes pubkey) returns() func (_DepositContract *DepositContractTransactorSession) CancelOperatorChange(pubkey []byte) (*types.Transaction, error) { return _DepositContract.Contract.CancelOperatorChange(&_DepositContract.TransactOpts, pubkey) } // Deposit is a paid mutator transaction binding the contract method 0xe12cf4cb. // // Solidity: function deposit(bytes pubkey, bytes credentials, bytes signature, address operator) payable returns() func (_DepositContract *DepositContractTransactor) Deposit(opts *bind.TransactOpts, pubkey []byte, credentials []byte, signature []byte, operator common.Address) (*types.Transaction, error) { return _DepositContract.contract.Transact(opts, "deposit", pubkey, credentials, signature, operator) } // Deposit is a paid mutator transaction binding the contract method 0xe12cf4cb. // // Solidity: function deposit(bytes pubkey, bytes credentials, bytes signature, address operator) payable returns() func (_DepositContract *DepositContractSession) Deposit(pubkey []byte, credentials []byte, signature []byte, operator common.Address) (*types.Transaction, error) { return _DepositContract.Contract.Deposit(&_DepositContract.TransactOpts, pubkey, credentials, signature, operator) } // Deposit is a paid mutator transaction binding the contract method 0xe12cf4cb. // // Solidity: function deposit(bytes pubkey, bytes credentials, bytes signature, address operator) payable returns() func (_DepositContract *DepositContractTransactorSession) Deposit(pubkey []byte, credentials []byte, signature []byte, operator common.Address) (*types.Transaction, error) { return _DepositContract.Contract.Deposit(&_DepositContract.TransactOpts, pubkey, credentials, signature, operator) } // RequestOperatorChange is a paid mutator transaction binding the contract method 0xfea7ab77. // // Solidity: function requestOperatorChange(bytes pubkey, address newOperator) returns() func (_DepositContract *DepositContractTransactor) RequestOperatorChange(opts *bind.TransactOpts, pubkey []byte, newOperator common.Address) (*types.Transaction, error) { return _DepositContract.contract.Transact(opts, "requestOperatorChange", pubkey, newOperator) } // RequestOperatorChange is a paid mutator transaction binding the contract method 0xfea7ab77. // // Solidity: function requestOperatorChange(bytes pubkey, address newOperator) returns() func (_DepositContract *DepositContractSession) RequestOperatorChange(pubkey []byte, newOperator common.Address) (*types.Transaction, error) { return _DepositContract.Contract.RequestOperatorChange(&_DepositContract.TransactOpts, pubkey, newOperator) } // RequestOperatorChange is a paid mutator transaction binding the contract method 0xfea7ab77. // // Solidity: function requestOperatorChange(bytes pubkey, address newOperator) returns() func (_DepositContract *DepositContractTransactorSession) RequestOperatorChange(pubkey []byte, newOperator common.Address) (*types.Transaction, error) { return _DepositContract.Contract.RequestOperatorChange(&_DepositContract.TransactOpts, pubkey, newOperator) } // DepositContractDepositIterator is returned from FilterDeposit and is used to iterate over the raw logs and unpacked data for Deposit events raised by the DepositContract contract. type DepositContractDepositIterator struct { Event *DepositContractDeposit // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data logs chan types.Log // Log channel receiving the found contract events sub ethereum.Subscription // Subscription for errors, completion and termination done bool // Whether the subscription completed delivering logs fail error // Occurred error to stop iteration } // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. func (it *DepositContractDepositIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false } // If the iterator completed, deliver directly whatever's available if it.done { select { case log := <-it.logs: it.Event = new(DepositContractDeposit) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false } it.Event.Raw = log return true default: return false } } // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: it.Event = new(DepositContractDeposit) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false } it.Event.Raw = log return true case err := <-it.sub.Err(): it.done = true it.fail = err return it.Next() } } // Error returns any retrieval or parsing error occurred during filtering. func (it *DepositContractDepositIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. func (it *DepositContractDepositIterator) Close() error { it.sub.Unsubscribe() return nil } // DepositContractDeposit represents a Deposit event raised by the DepositContract contract. type DepositContractDeposit struct { Pubkey []byte Credentials []byte Amount uint64 Signature []byte Index uint64 Raw types.Log // Blockchain specific contextual infos } // FilterDeposit is a free log retrieval operation binding the contract event 0x68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46. // // Solidity: event Deposit(bytes pubkey, bytes credentials, uint64 amount, bytes signature, uint64 index) func (_DepositContract *DepositContractFilterer) FilterDeposit(opts *bind.FilterOpts) (*DepositContractDepositIterator, error) { logs, sub, err := _DepositContract.contract.FilterLogs(opts, "Deposit") if err != nil { return nil, err } return &DepositContractDepositIterator{contract: _DepositContract.contract, event: "Deposit", logs: logs, sub: sub}, nil } // WatchDeposit is a free log subscription operation binding the contract event 0x68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46. // // Solidity: event Deposit(bytes pubkey, bytes credentials, uint64 amount, bytes signature, uint64 index) func (_DepositContract *DepositContractFilterer) WatchDeposit(opts *bind.WatchOpts, sink chan<- *DepositContractDeposit) (event.Subscription, error) { logs, sub, err := _DepositContract.contract.WatchLogs(opts, "Deposit") if err != nil { return nil, err } return event.NewSubscription(func(quit <-chan struct{}) error { defer sub.Unsubscribe() for { select { case log := <-logs: // New log arrived, parse the event and forward to the user event := new(DepositContractDeposit) if err := _DepositContract.contract.UnpackLog(event, "Deposit", log); err != nil { return err } event.Raw = log select { case sink <- event: case err := <-sub.Err(): return err case <-quit: return nil } case err := <-sub.Err(): return err case <-quit: return nil } } }), nil } // ParseDeposit is a log parse operation binding the contract event 0x68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46. // // Solidity: event Deposit(bytes pubkey, bytes credentials, uint64 amount, bytes signature, uint64 index) func (_DepositContract *DepositContractFilterer) ParseDeposit(log types.Log) (*DepositContractDeposit, error) { event := new(DepositContractDeposit) if err := _DepositContract.contract.UnpackLog(event, "Deposit", log); err != nil { return nil, err } event.Raw = log return event, nil } // DepositContractOperatorChangeCancelledIterator is returned from FilterOperatorChangeCancelled and is used to iterate over the raw logs and unpacked data for OperatorChangeCancelled events raised by the DepositContract contract. type DepositContractOperatorChangeCancelledIterator struct { Event *DepositContractOperatorChangeCancelled // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data logs chan types.Log // Log channel receiving the found contract events sub ethereum.Subscription // Subscription for errors, completion and termination done bool // Whether the subscription completed delivering logs fail error // Occurred error to stop iteration } // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. func (it *DepositContractOperatorChangeCancelledIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false } // If the iterator completed, deliver directly whatever's available if it.done { select { case log := <-it.logs: it.Event = new(DepositContractOperatorChangeCancelled) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false } it.Event.Raw = log return true default: return false } } // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: it.Event = new(DepositContractOperatorChangeCancelled) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false } it.Event.Raw = log return true case err := <-it.sub.Err(): it.done = true it.fail = err return it.Next() } } // Error returns any retrieval or parsing error occurred during filtering. func (it *DepositContractOperatorChangeCancelledIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. func (it *DepositContractOperatorChangeCancelledIterator) Close() error { it.sub.Unsubscribe() return nil } // DepositContractOperatorChangeCancelled represents a OperatorChangeCancelled event raised by the DepositContract contract. type DepositContractOperatorChangeCancelled struct { Pubkey common.Hash Raw types.Log // Blockchain specific contextual infos } // FilterOperatorChangeCancelled is a free log retrieval operation binding the contract event 0x1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db. // // Solidity: event OperatorChangeCancelled(bytes indexed pubkey) func (_DepositContract *DepositContractFilterer) FilterOperatorChangeCancelled(opts *bind.FilterOpts, pubkey [][]byte) (*DepositContractOperatorChangeCancelledIterator, error) { var pubkeyRule []interface{} for _, pubkeyItem := range pubkey { pubkeyRule = append(pubkeyRule, pubkeyItem) } logs, sub, err := _DepositContract.contract.FilterLogs(opts, "OperatorChangeCancelled", pubkeyRule) if err != nil { return nil, err } return &DepositContractOperatorChangeCancelledIterator{contract: _DepositContract.contract, event: "OperatorChangeCancelled", logs: logs, sub: sub}, nil } // WatchOperatorChangeCancelled is a free log subscription operation binding the contract event 0x1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db. // // Solidity: event OperatorChangeCancelled(bytes indexed pubkey) func (_DepositContract *DepositContractFilterer) WatchOperatorChangeCancelled(opts *bind.WatchOpts, sink chan<- *DepositContractOperatorChangeCancelled, pubkey [][]byte) (event.Subscription, error) { var pubkeyRule []interface{} for _, pubkeyItem := range pubkey { pubkeyRule = append(pubkeyRule, pubkeyItem) } logs, sub, err := _DepositContract.contract.WatchLogs(opts, "OperatorChangeCancelled", pubkeyRule) if err != nil { return nil, err } return event.NewSubscription(func(quit <-chan struct{}) error { defer sub.Unsubscribe() for { select { case log := <-logs: // New log arrived, parse the event and forward to the user event := new(DepositContractOperatorChangeCancelled) if err := _DepositContract.contract.UnpackLog(event, "OperatorChangeCancelled", log); err != nil { return err } event.Raw = log select { case sink <- event: case err := <-sub.Err(): return err case <-quit: return nil } case err := <-sub.Err(): return err case <-quit: return nil } } }), nil } // ParseOperatorChangeCancelled is a log parse operation binding the contract event 0x1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db. // // Solidity: event OperatorChangeCancelled(bytes indexed pubkey) func (_DepositContract *DepositContractFilterer) ParseOperatorChangeCancelled(log types.Log) (*DepositContractOperatorChangeCancelled, error) { event := new(DepositContractOperatorChangeCancelled) if err := _DepositContract.contract.UnpackLog(event, "OperatorChangeCancelled", log); err != nil { return nil, err } event.Raw = log return event, nil } // DepositContractOperatorChangeQueuedIterator is returned from FilterOperatorChangeQueued and is used to iterate over the raw logs and unpacked data for OperatorChangeQueued events raised by the DepositContract contract. type DepositContractOperatorChangeQueuedIterator struct { Event *DepositContractOperatorChangeQueued // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data logs chan types.Log // Log channel receiving the found contract events sub ethereum.Subscription // Subscription for errors, completion and termination done bool // Whether the subscription completed delivering logs fail error // Occurred error to stop iteration } // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. func (it *DepositContractOperatorChangeQueuedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false } // If the iterator completed, deliver directly whatever's available if it.done { select { case log := <-it.logs: it.Event = new(DepositContractOperatorChangeQueued) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false } it.Event.Raw = log return true default: return false } } // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: it.Event = new(DepositContractOperatorChangeQueued) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false } it.Event.Raw = log return true case err := <-it.sub.Err(): it.done = true it.fail = err return it.Next() } } // Error returns any retrieval or parsing error occurred during filtering. func (it *DepositContractOperatorChangeQueuedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. func (it *DepositContractOperatorChangeQueuedIterator) Close() error { it.sub.Unsubscribe() return nil } // DepositContractOperatorChangeQueued represents a OperatorChangeQueued event raised by the DepositContract contract. type DepositContractOperatorChangeQueued struct { Pubkey common.Hash QueuedOperator common.Address CurrentOperator common.Address QueuedTimestamp *big.Int Raw types.Log // Blockchain specific contextual infos } // FilterOperatorChangeQueued is a free log retrieval operation binding the contract event 0x7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f. // // Solidity: event OperatorChangeQueued(bytes indexed pubkey, address queuedOperator, address currentOperator, uint256 queuedTimestamp) func (_DepositContract *DepositContractFilterer) FilterOperatorChangeQueued(opts *bind.FilterOpts, pubkey [][]byte) (*DepositContractOperatorChangeQueuedIterator, error) { var pubkeyRule []interface{} for _, pubkeyItem := range pubkey { pubkeyRule = append(pubkeyRule, pubkeyItem) } logs, sub, err := _DepositContract.contract.FilterLogs(opts, "OperatorChangeQueued", pubkeyRule) if err != nil { return nil, err } return &DepositContractOperatorChangeQueuedIterator{contract: _DepositContract.contract, event: "OperatorChangeQueued", logs: logs, sub: sub}, nil } // WatchOperatorChangeQueued is a free log subscription operation binding the contract event 0x7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f. // // Solidity: event OperatorChangeQueued(bytes indexed pubkey, address queuedOperator, address currentOperator, uint256 queuedTimestamp) func (_DepositContract *DepositContractFilterer) WatchOperatorChangeQueued(opts *bind.WatchOpts, sink chan<- *DepositContractOperatorChangeQueued, pubkey [][]byte) (event.Subscription, error) { var pubkeyRule []interface{} for _, pubkeyItem := range pubkey { pubkeyRule = append(pubkeyRule, pubkeyItem) } logs, sub, err := _DepositContract.contract.WatchLogs(opts, "OperatorChangeQueued", pubkeyRule) if err != nil { return nil, err } return event.NewSubscription(func(quit <-chan struct{}) error { defer sub.Unsubscribe() for { select { case log := <-logs: // New log arrived, parse the event and forward to the user event := new(DepositContractOperatorChangeQueued) if err := _DepositContract.contract.UnpackLog(event, "OperatorChangeQueued", log); err != nil { return err } event.Raw = log select { case sink <- event: case err := <-sub.Err(): return err case <-quit: return nil } case err := <-sub.Err(): return err case <-quit: return nil } } }), nil } // ParseOperatorChangeQueued is a log parse operation binding the contract event 0x7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f. // // Solidity: event OperatorChangeQueued(bytes indexed pubkey, address queuedOperator, address currentOperator, uint256 queuedTimestamp) func (_DepositContract *DepositContractFilterer) ParseOperatorChangeQueued(log types.Log) (*DepositContractOperatorChangeQueued, error) { event := new(DepositContractOperatorChangeQueued) if err := _DepositContract.contract.UnpackLog(event, "OperatorChangeQueued", log); err != nil { return nil, err } event.Raw = log return event, nil } // DepositContractOperatorUpdatedIterator is returned from FilterOperatorUpdated and is used to iterate over the raw logs and unpacked data for OperatorUpdated events raised by the DepositContract contract. type DepositContractOperatorUpdatedIterator struct { Event *DepositContractOperatorUpdated // Event containing the contract specifics and raw log contract *bind.BoundContract // Generic contract to use for unpacking event data event string // Event name to use for unpacking event data logs chan types.Log // Log channel receiving the found contract events sub ethereum.Subscription // Subscription for errors, completion and termination done bool // Whether the subscription completed delivering logs fail error // Occurred error to stop iteration } // Next advances the iterator to the subsequent event, returning whether there // are any more events found. In case of a retrieval or parsing error, false is // returned and Error() can be queried for the exact failure. func (it *DepositContractOperatorUpdatedIterator) Next() bool { // If the iterator failed, stop iterating if it.fail != nil { return false } // If the iterator completed, deliver directly whatever's available if it.done { select { case log := <-it.logs: it.Event = new(DepositContractOperatorUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false } it.Event.Raw = log return true default: return false } } // Iterator still in progress, wait for either a data or an error event select { case log := <-it.logs: it.Event = new(DepositContractOperatorUpdated) if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { it.fail = err return false } it.Event.Raw = log return true case err := <-it.sub.Err(): it.done = true it.fail = err return it.Next() } } // Error returns any retrieval or parsing error occurred during filtering. func (it *DepositContractOperatorUpdatedIterator) Error() error { return it.fail } // Close terminates the iteration process, releasing any pending underlying // resources. func (it *DepositContractOperatorUpdatedIterator) Close() error { it.sub.Unsubscribe() return nil } // DepositContractOperatorUpdated represents a OperatorUpdated event raised by the DepositContract contract. type DepositContractOperatorUpdated struct { Pubkey common.Hash NewOperator common.Address PreviousOperator common.Address Raw types.Log // Blockchain specific contextual infos } // FilterOperatorUpdated is a free log retrieval operation binding the contract event 0x0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403. // // Solidity: event OperatorUpdated(bytes indexed pubkey, address newOperator, address previousOperator) func (_DepositContract *DepositContractFilterer) FilterOperatorUpdated(opts *bind.FilterOpts, pubkey [][]byte) (*DepositContractOperatorUpdatedIterator, error) { var pubkeyRule []interface{} for _, pubkeyItem := range pubkey { pubkeyRule = append(pubkeyRule, pubkeyItem) } logs, sub, err := _DepositContract.contract.FilterLogs(opts, "OperatorUpdated", pubkeyRule) if err != nil { return nil, err } return &DepositContractOperatorUpdatedIterator{contract: _DepositContract.contract, event: "OperatorUpdated", logs: logs, sub: sub}, nil } // WatchOperatorUpdated is a free log subscription operation binding the contract event 0x0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403. // // Solidity: event OperatorUpdated(bytes indexed pubkey, address newOperator, address previousOperator) func (_DepositContract *DepositContractFilterer) WatchOperatorUpdated(opts *bind.WatchOpts, sink chan<- *DepositContractOperatorUpdated, pubkey [][]byte) (event.Subscription, error) { var pubkeyRule []interface{} for _, pubkeyItem := range pubkey { pubkeyRule = append(pubkeyRule, pubkeyItem) } logs, sub, err := _DepositContract.contract.WatchLogs(opts, "OperatorUpdated", pubkeyRule) if err != nil { return nil, err } return event.NewSubscription(func(quit <-chan struct{}) error { defer sub.Unsubscribe() for { select { case log := <-logs: // New log arrived, parse the event and forward to the user event := new(DepositContractOperatorUpdated) if err := _DepositContract.contract.UnpackLog(event, "OperatorUpdated", log); err != nil { return err } event.Raw = log select { case sink <- event: case err := <-sub.Err(): return err case <-quit: return nil } case err := <-sub.Err(): return err case <-quit: return nil } } }), nil } // ParseOperatorUpdated is a log parse operation binding the contract event 0x0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403. // // Solidity: event OperatorUpdated(bytes indexed pubkey, address newOperator, address previousOperator) func (_DepositContract *DepositContractFilterer) ParseOperatorUpdated(log types.Log) (*DepositContractOperatorUpdated, error) { event := new(DepositContractOperatorUpdated) if err := _DepositContract.contract.UnpackLog(event, "OperatorUpdated", log); err != nil { return nil, err } event.Raw = log return event, nil } ================================================ FILE: gethlib/deposit/contract.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit // TODO: Remove ldflags=-checklinkname=0 override once fix is applied. // //go:generate abigen --abi=../../contracts/out/DepositContract.sol/DepositContract.abi.json --bin=../../contracts/out/DepositContract.sol/DepositContract.bin --pkg=deposit --type=DepositContract --out=contract.abigen.go ================================================ FILE: gethlib/ethclient/ethclient.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ethclient import ( "context" "encoding/json" "errors" "fmt" "math/big" "github.com/berachain/beacon-kit/gethlib/types" "github.com/ethereum/go-ethereum" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" coretypes "github.com/ethereum/go-ethereum/core/types" gethclient "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" ) // Client is a wrapper around go-ethereum's ethclient which handles unmarhsalling // Berachain blocks and transactions. type Client struct { *gethclient.Client } // Wrap wraps a go-ethereum's ethclient and returns a Berachain-specific ethclient. func Wrap(c *gethclient.Client) *Client { return &Client{c} } // BlockByNumber overrides the original method to unmarshal the block. func (c *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { return c.getBlock(ctx, "eth_getBlockByNumber", toBlockNumArg(number), true) } // BlockByHash overrides the original method to unmarshal the block. func (c *Client) BlockByHash(ctx context.Context, hash gethcommon.Hash) (*types.Block, error) { return c.getBlock(ctx, "eth_getBlockByHash", hash, true) } // TransactionByHash overrides the original method to unmarshal the transaction. func (c *Client) TransactionByHash( ctx context.Context, hash gethcommon.Hash, ) (*types.Transaction, bool, error) { var jsonTx *rpcTransaction err := c.Client.Client().CallContext(ctx, &jsonTx, "eth_getTransactionByHash", hash) if err != nil { return nil, false, err } if jsonTx == nil { return nil, false, ethereum.NotFound } sigErr := ensureTransactionHasRequiredSignature(jsonTx.tx) if sigErr != nil { return nil, false, sigErr } return jsonTx.tx, jsonTx.BlockNumber == nil, nil } // TransactionInBlock overrides the original method to unmarshal the transaction. func (c *Client) TransactionInBlock(ctx context.Context, blockHash gethcommon.Hash, index uint) (*types.Transaction, error) { var jsonTx *rpcTransaction err := c.Client.Client().CallContext(ctx, &jsonTx, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index)) if err != nil { return nil, err } if jsonTx == nil { return nil, ethereum.NotFound } sigErr := ensureTransactionHasRequiredSignature(jsonTx.tx) if sigErr != nil { return nil, sigErr } return jsonTx.tx, nil } type rpcBlock struct { Hash *gethcommon.Hash `json:"hash"` Transactions []rpcTransaction `json:"transactions"` UncleHashes []gethcommon.Hash `json:"uncles"` Withdrawals []*coretypes.Withdrawal `json:"withdrawals,omitempty"` } type rpcTransaction struct { tx *types.Transaction txExtraInfo } type txExtraInfo struct { BlockNumber *string `json:"blockNumber,omitempty"` BlockHash *gethcommon.Hash `json:"blockHash,omitempty"` From *gethcommon.Address `json:"from,omitempty"` } func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error { if err := json.Unmarshal(msg, &tx.tx); err != nil { return err } return json.Unmarshal(msg, &tx.txExtraInfo) } type rpcHeader struct { ParentHash *gethcommon.Hash `json:"parentHash"` UncleHash *gethcommon.Hash `json:"sha3Uncles"` Coinbase *gethcommon.Address `json:"miner"` Root *gethcommon.Hash `json:"stateRoot"` TxHash *gethcommon.Hash `json:"transactionsRoot"` ReceiptHash *gethcommon.Hash `json:"receiptsRoot"` Bloom *coretypes.Bloom `json:"logsBloom"` Difficulty *hexutil.Big `json:"difficulty"` Number *hexutil.Big `json:"number"` GasLimit *hexutil.Uint64 `json:"gasLimit"` GasUsed *hexutil.Uint64 `json:"gasUsed"` Time *hexutil.Uint64 `json:"timestamp"` Extra *hexutil.Bytes `json:"extraData"` MixDigest *gethcommon.Hash `json:"mixHash"` Nonce *coretypes.BlockNonce `json:"nonce"` BaseFee *hexutil.Big `json:"baseFeePerGas,omitempty"` WithdrawalsHash *gethcommon.Hash `json:"withdrawalsRoot,omitempty"` BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed,omitempty"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas,omitempty"` ParentBeaconRoot *gethcommon.Hash `json:"parentBeaconBlockRoot,omitempty"` RequestsHash *gethcommon.Hash `json:"requestsHash,omitempty"` ParentProposerPubkey *types.ExecutionPubkey `json:"parentProposerPubkey,omitempty"` } //nolint:gocognit,funlen // Validation mirrors strict geth header decoding requirements. func (h *rpcHeader) toHeader() (*types.Header, error) { if h == nil { return nil, errors.New("missing header payload") } if h.ParentHash == nil { return nil, errors.New("missing required field 'parentHash' for Header") } if h.UncleHash == nil { return nil, errors.New("missing required field 'sha3Uncles' for Header") } if h.Root == nil { return nil, errors.New("missing required field 'stateRoot' for Header") } if h.TxHash == nil { return nil, errors.New("missing required field 'transactionsRoot' for Header") } if h.ReceiptHash == nil { return nil, errors.New("missing required field 'receiptsRoot' for Header") } if h.Bloom == nil { return nil, errors.New("missing required field 'logsBloom' for Header") } if h.Difficulty == nil { return nil, errors.New("missing required field 'difficulty' for Header") } if h.Number == nil { return nil, errors.New("missing required field 'number' for Header") } if h.GasLimit == nil { return nil, errors.New("missing required field 'gasLimit' for Header") } if h.GasUsed == nil { return nil, errors.New("missing required field 'gasUsed' for Header") } if h.Time == nil { return nil, errors.New("missing required field 'timestamp' for Header") } if h.Extra == nil { return nil, errors.New("missing required field 'extraData' for Header") } head := &types.Header{ ParentHash: *h.ParentHash, UncleHash: *h.UncleHash, Root: *h.Root, TxHash: *h.TxHash, ReceiptHash: *h.ReceiptHash, Bloom: *h.Bloom, Difficulty: (*big.Int)(h.Difficulty), Number: (*big.Int)(h.Number), GasLimit: uint64(*h.GasLimit), GasUsed: uint64(*h.GasUsed), Time: uint64(*h.Time), Extra: *h.Extra, } if h.Coinbase != nil { head.Coinbase = *h.Coinbase } if h.MixDigest != nil { head.MixDigest = *h.MixDigest } if h.Nonce != nil { head.Nonce = *h.Nonce } if h.BaseFee != nil { head.BaseFee = (*big.Int)(h.BaseFee) } if h.WithdrawalsHash != nil { hash := *h.WithdrawalsHash head.WithdrawalsHash = &hash } if h.BlobGasUsed != nil { blobGasUsed := uint64(*h.BlobGasUsed) head.BlobGasUsed = &blobGasUsed } if h.ExcessBlobGas != nil { excessBlobGas := uint64(*h.ExcessBlobGas) head.ExcessBlobGas = &excessBlobGas } if h.ParentBeaconRoot != nil { root := *h.ParentBeaconRoot head.ParentBeaconRoot = &root } if h.RequestsHash != nil { hash := *h.RequestsHash head.RequestsHash = &hash } if h.ParentProposerPubkey != nil { pubkey := *h.ParentProposerPubkey head.ParentProposerPubkey = &pubkey } return head, nil } func (c *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { var raw json.RawMessage if err := c.Client.Client().CallContext(ctx, &raw, method, args...); err != nil { return nil, err } // Decode header and transactions. var rawHead *rpcHeader if err := json.Unmarshal(raw, &rawHead); err != nil { return nil, err } // When the block is not found, the API returns JSON null. if rawHead == nil { return nil, ethereum.NotFound } head, err := rawHead.toHeader() if err != nil { return nil, err } var body rpcBlock err = json.Unmarshal(raw, &body) if err != nil { return nil, err } // Pending blocks don't return a block hash. Compute it for consistency. if body.Hash == nil { tmp := head.Hash() body.Hash = &tmp } // Quick-verify transaction and uncle lists. if head.UncleHash != coretypes.EmptyUncleHash || len(body.UncleHashes) > 0 { return nil, errors.New("server returned non-empty uncle list, unsupported by Berachain") } if head.TxHash == coretypes.EmptyTxsHash && len(body.Transactions) > 0 { return nil, errors.New("server returned non-empty transaction list but block header indicates no transactions") } if head.TxHash != coretypes.EmptyTxsHash && len(body.Transactions) == 0 { return nil, errors.New("server returned empty transaction list but block header indicates transactions") } // Fill transaction list. txs := make([]*types.Transaction, len(body.Transactions)) for i, tx := range body.Transactions { sigErr := ensureTransactionHasRequiredSignature(tx.tx) if sigErr != nil { return nil, sigErr } txs[i] = tx.tx } return types.NewBlockWithHeader(head).WithBody( types.Body{ Transactions: txs, Uncles: nil, // Berachain doesn't support uncles. Withdrawals: body.Withdrawals, }), nil } func ensureTransactionHasRequiredSignature(tx *types.Transaction) error { if tx == nil { return errors.New("server returned null transaction") } if tx.Type() == types.PoLTxType { return nil } _, r, _ := tx.RawSignatureValues() if r == nil { return errors.New("server returned transaction without signature") } return nil } func toBlockNumArg(number *big.Int) string { if number == nil { return "latest" } if number.Sign() >= 0 { return hexutil.EncodeBig(number) } // It's negative. if number.IsInt64() { return rpc.BlockNumber(number.Int64()).String() } // It's negative and large, which is invalid. return fmt.Sprintf("", number) } ================================================ FILE: gethlib/ethclient/ethclient_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ethclient_test import ( "context" "encoding/json" "math/big" "strings" "testing" beraclient "github.com/berachain/beacon-kit/gethlib/ethclient" "github.com/berachain/beacon-kit/gethlib/types" gethcommon "github.com/ethereum/go-ethereum/common" coretypes "github.com/ethereum/go-ethereum/core/types" gethclient "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" ) var ( testBlockHash = gethcommon.HexToHash("0x1111111111111111111111111111111111111111111111111111111111111111") testParentHash = gethcommon.HexToHash("0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") testStateRoot = gethcommon.HexToHash("0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") testReceiptsRoot = gethcommon.HexToHash("0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc") testTxRoot = gethcommon.HexToHash("0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd") testTxHash = gethcommon.HexToHash("0x2222222222222222222222222222222222222222222222222222222222222222") testFrom = gethcommon.HexToAddress("0x1000000000000000000000000000000000000001") testTo = gethcommon.HexToAddress("0x2000000000000000000000000000000000000002") ) func TestBlockByNumberWithPoLTransaction(t *testing.T) { t.Parallel() client := newMockClient(t) block, err := client.BlockByNumber(t.Context(), big.NewInt(2)) if err != nil { t.Fatalf("BlockByNumber returned error: %v", err) } if block == nil { t.Fatal("BlockByNumber returned nil block") } if got := len(block.Transactions()); got != 1 { t.Fatalf("unexpected tx count: got %d want %d", got, 1) } if txType := block.Transactions()[0].Type(); txType != types.PoLTxType { t.Fatalf("unexpected tx type: got 0x%x want 0x%x", txType, types.PoLTxType) } } func TestBlockByHashWithPoLTransaction(t *testing.T) { t.Parallel() client := newMockClient(t) block, err := client.BlockByHash(t.Context(), testBlockHash) if err != nil { t.Fatalf("BlockByHash returned error: %v", err) } if block == nil { t.Fatal("BlockByHash returned nil block") } if got := len(block.Transactions()); got != 1 { t.Fatalf("unexpected tx count: got %d want %d", got, 1) } if txType := block.Transactions()[0].Type(); txType != types.PoLTxType { t.Fatalf("unexpected tx type: got 0x%x want 0x%x", txType, types.PoLTxType) } } func TestTransactionByHashWithPoLTransaction(t *testing.T) { t.Parallel() client := newMockClient(t) tx, isPending, err := client.TransactionByHash(t.Context(), testTxHash) if err != nil { t.Fatalf("TransactionByHash returned error: %v", err) } if tx == nil { t.Fatal("TransactionByHash returned nil transaction") } if isPending { t.Fatal("TransactionByHash unexpectedly marked tx as pending") } if txType := tx.Type(); txType != types.PoLTxType { t.Fatalf("unexpected tx type: got 0x%x want 0x%x", txType, types.PoLTxType) } } func TestTransactionInBlockWithPoLTransaction(t *testing.T) { t.Parallel() client := newMockClient(t) tx, err := client.TransactionInBlock(t.Context(), testBlockHash, 0) if err != nil { t.Fatalf("TransactionInBlock returned error: %v", err) } if tx == nil { t.Fatal("TransactionInBlock returned nil transaction") } if txType := tx.Type(); txType != types.PoLTxType { t.Fatalf("unexpected tx type: got 0x%x want 0x%x", txType, types.PoLTxType) } } type mockEthService struct{} func (s *mockEthService) GetBlockByNumber(ctx context.Context, number string, fullTx bool) (json.RawMessage, error) { _ = ctx _ = number _ = fullTx return mockBlockJSON(), nil } func (s *mockEthService) GetBlockByHash(ctx context.Context, hash gethcommon.Hash, fullTx bool) (json.RawMessage, error) { _ = ctx _ = hash _ = fullTx return mockBlockJSON(), nil } func (s *mockEthService) GetTransactionByHash(ctx context.Context, hash gethcommon.Hash) (json.RawMessage, error) { _ = ctx _ = hash return mockTransactionJSON(), nil } func (s *mockEthService) GetTransactionByBlockHashAndIndex( ctx context.Context, blockHash gethcommon.Hash, index string, ) (json.RawMessage, error) { _ = ctx _ = blockHash _ = index return mockTransactionJSON(), nil } func newMockClient(t *testing.T) *beraclient.Client { t.Helper() srv := rpc.NewServer() if err := srv.RegisterName("eth", &mockEthService{}); err != nil { t.Fatalf("failed to register mock service: %v", err) } rpcClient := rpc.DialInProc(srv) client := beraclient.Wrap(gethclient.NewClient(rpcClient)) t.Cleanup(func() { client.Close() srv.Stop() }) return client } func mockTransactionJSON() json.RawMessage { tx := mockTransactionObject() raw, err := json.Marshal(tx) if err != nil { panic(err) } return raw } func mockTransactionObject() map[string]any { return map[string]any{ "type": "0x7e", "chainId": "0x1", "from": testFrom.Hex(), "to": testTo.Hex(), "nonce": "0x2", "gas": "0x5208", "gasPrice": "0x1", "input": "0x1234", "hash": testTxHash.Hex(), "blockHash": testBlockHash.Hex(), "blockNumber": "0x2", "transactionIndex": "0x0", } } func mockBlockJSON() json.RawMessage { block := map[string]any{ "hash": testBlockHash.Hex(), "parentHash": testParentHash.Hex(), "sha3Uncles": coretypes.EmptyUncleHash.Hex(), "miner": gethcommon.Address{}.Hex(), "stateRoot": testStateRoot.Hex(), "transactionsRoot": testTxRoot.Hex(), "receiptsRoot": testReceiptsRoot.Hex(), "logsBloom": "0x" + strings.Repeat("0", 512), "difficulty": "0x1", "number": "0x2", "gasLimit": "0x1c9c380", "gasUsed": "0x5208", "timestamp": "0x1", "extraData": "0x", "mixHash": gethcommon.Hash{}.Hex(), "nonce": "0x0000000000000000", "transactions": []any{mockTransactionObject()}, "uncles": []any{}, } raw, err := json.Marshal(block) if err != nil { panic(err) } return raw } ================================================ FILE: gethlib/ssztest/contract.abigen.go ================================================ // Code generated - DO NOT EDIT. // This file is a generated binding and any manual changes will be lost. package ssztest import ( "errors" "math/big" "strings" ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" ) // Reference imports to suppress errors if they are not otherwise used. var ( _ = errors.New _ = big.NewInt _ = strings.NewReader _ = ethereum.NotFound _ = bind.Bind _ = common.Big1 _ = types.BloomLookup _ = event.NewSubscription _ = abi.ConvertType ) // SSZTestMetaData contains all meta data concerning the SSZTest contract. var SSZTestMetaData = &bind.MetaData{ ABI: "[{\"type\":\"function\",\"name\":\"BEACON_ROOTS\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getParentBlockRootAt\",\"inputs\":[{\"name\":\"ts\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"outputs\":[{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"mustVerifyProof\",\"inputs\":[{\"name\":\"proof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"leaf\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifyProof\",\"inputs\":[{\"name\":\"proof\",\"type\":\"bytes32[]\",\"internalType\":\"bytes32[]\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"leaf\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"index\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"isValid\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"error\",\"name\":\"RootNotFound\",\"inputs\":[]}]", Bin: "0x6080604052348015600e575f80fd5b5061033f8061001c5f395ff3fe608060405234801561000f575f80fd5b506004361061004a575f3560e01c806341b703ff1461004e5780634fc36be61461006357806356d7e8fd1461008b578063e2c37a98146100ca575b5f80fd5b61006161005c366004610256565b6100eb565b005b610076610071366004610256565b610169565b60405190151581526020015b60405180910390f35b6100a5720f3df6d732807ef1319fb7b8bb8522d0beac0281565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610082565b6100dd6100d83660046102db565b610181565b604051908152602001610082565b6100f885858585856101bc565b610162576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601060248201527f50726f6f6620697320696e76616c696400000000000000000000000000000000604482015260640160405180910390fd5b5050505050565b5f61017786868686866101bc565b9695505050505050565b5f815f5260205f60205f720f3df6d732807ef1319fb7b8bb8522d0beac025afa806101b357633033b0ff5f526004601cfd5b50505f51919050565b5f8415610218578460051b8601865b6001841660051b8460011c9450846101ea57635849603f5f526004601cfd5b85815281356020918218525f60408160025afa80610206575f80fd5b505f5194506020018181106101cb5750505b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82011561024d57631b6661c35f526004601cfd5b50501492915050565b5f805f805f6080868803121561026a575f80fd5b853567ffffffffffffffff811115610280575f80fd5b8601601f81018813610290575f80fd5b803567ffffffffffffffff8111156102a6575f80fd5b8860208260051b84010111156102ba575f80fd5b60209182019990985090870135966040810135965060600135945092505050565b5f602082840312156102eb575f80fd5b813567ffffffffffffffff81168114610302575f80fd5b939250505056fea26469706673582212204cc5111caf3fc9426b1119c431d63b522cbd3e75039cf6c038d28577712aac6464736f6c634300081a0033", } // SSZTestABI is the input ABI used to generate the binding from. // Deprecated: Use SSZTestMetaData.ABI instead. var SSZTestABI = SSZTestMetaData.ABI // SSZTestBin is the compiled bytecode used for deploying new contracts. // Deprecated: Use SSZTestMetaData.Bin instead. var SSZTestBin = SSZTestMetaData.Bin // DeploySSZTest deploys a new Ethereum contract, binding an instance of SSZTest to it. func DeploySSZTest(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *SSZTest, error) { parsed, err := SSZTestMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err } if parsed == nil { return common.Address{}, nil, nil, errors.New("GetABI returned nil") } address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(SSZTestBin), backend) if err != nil { return common.Address{}, nil, nil, err } return address, tx, &SSZTest{SSZTestCaller: SSZTestCaller{contract: contract}, SSZTestTransactor: SSZTestTransactor{contract: contract}, SSZTestFilterer: SSZTestFilterer{contract: contract}}, nil } // SSZTest is an auto generated Go binding around an Ethereum contract. type SSZTest struct { SSZTestCaller // Read-only binding to the contract SSZTestTransactor // Write-only binding to the contract SSZTestFilterer // Log filterer for contract events } // SSZTestCaller is an auto generated read-only Go binding around an Ethereum contract. type SSZTestCaller struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } // SSZTestTransactor is an auto generated write-only Go binding around an Ethereum contract. type SSZTestTransactor struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } // SSZTestFilterer is an auto generated log filtering Go binding around an Ethereum contract events. type SSZTestFilterer struct { contract *bind.BoundContract // Generic contract wrapper for the low level calls } // SSZTestSession is an auto generated Go binding around an Ethereum contract, // with pre-set call and transact options. type SSZTestSession struct { Contract *SSZTest // Generic contract binding to set the session for CallOpts bind.CallOpts // Call options to use throughout this session TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } // SSZTestCallerSession is an auto generated read-only Go binding around an Ethereum contract, // with pre-set call options. type SSZTestCallerSession struct { Contract *SSZTestCaller // Generic contract caller binding to set the session for CallOpts bind.CallOpts // Call options to use throughout this session } // SSZTestTransactorSession is an auto generated write-only Go binding around an Ethereum contract, // with pre-set transact options. type SSZTestTransactorSession struct { Contract *SSZTestTransactor // Generic contract transactor binding to set the session for TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session } // SSZTestRaw is an auto generated low-level Go binding around an Ethereum contract. type SSZTestRaw struct { Contract *SSZTest // Generic contract binding to access the raw methods on } // SSZTestCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. type SSZTestCallerRaw struct { Contract *SSZTestCaller // Generic read-only contract binding to access the raw methods on } // SSZTestTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. type SSZTestTransactorRaw struct { Contract *SSZTestTransactor // Generic write-only contract binding to access the raw methods on } // NewSSZTest creates a new instance of SSZTest, bound to a specific deployed contract. func NewSSZTest(address common.Address, backend bind.ContractBackend) (*SSZTest, error) { contract, err := bindSSZTest(address, backend, backend, backend) if err != nil { return nil, err } return &SSZTest{SSZTestCaller: SSZTestCaller{contract: contract}, SSZTestTransactor: SSZTestTransactor{contract: contract}, SSZTestFilterer: SSZTestFilterer{contract: contract}}, nil } // NewSSZTestCaller creates a new read-only instance of SSZTest, bound to a specific deployed contract. func NewSSZTestCaller(address common.Address, caller bind.ContractCaller) (*SSZTestCaller, error) { contract, err := bindSSZTest(address, caller, nil, nil) if err != nil { return nil, err } return &SSZTestCaller{contract: contract}, nil } // NewSSZTestTransactor creates a new write-only instance of SSZTest, bound to a specific deployed contract. func NewSSZTestTransactor(address common.Address, transactor bind.ContractTransactor) (*SSZTestTransactor, error) { contract, err := bindSSZTest(address, nil, transactor, nil) if err != nil { return nil, err } return &SSZTestTransactor{contract: contract}, nil } // NewSSZTestFilterer creates a new log filterer instance of SSZTest, bound to a specific deployed contract. func NewSSZTestFilterer(address common.Address, filterer bind.ContractFilterer) (*SSZTestFilterer, error) { contract, err := bindSSZTest(address, nil, nil, filterer) if err != nil { return nil, err } return &SSZTestFilterer{contract: contract}, nil } // bindSSZTest binds a generic wrapper to an already deployed contract. func bindSSZTest(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { parsed, err := SSZTestMetaData.GetAbi() if err != nil { return nil, err } return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil } // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. func (_SSZTest *SSZTestRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { return _SSZTest.Contract.SSZTestCaller.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. func (_SSZTest *SSZTestRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { return _SSZTest.Contract.SSZTestTransactor.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. func (_SSZTest *SSZTestRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { return _SSZTest.Contract.SSZTestTransactor.contract.Transact(opts, method, params...) } // Call invokes the (constant) contract method with params as input values and // sets the output to result. The result type might be a single field for simple // returns, a slice of interfaces for anonymous returns and a struct for named // returns. func (_SSZTest *SSZTestCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { return _SSZTest.Contract.contract.Call(opts, result, method, params...) } // Transfer initiates a plain transaction to move funds to the contract, calling // its default method if one is available. func (_SSZTest *SSZTestTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { return _SSZTest.Contract.contract.Transfer(opts) } // Transact invokes the (paid) contract method with params as input values. func (_SSZTest *SSZTestTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { return _SSZTest.Contract.contract.Transact(opts, method, params...) } // BEACONROOTS is a free data retrieval call binding the contract method 0x56d7e8fd. // // Solidity: function BEACON_ROOTS() view returns(address) func (_SSZTest *SSZTestCaller) BEACONROOTS(opts *bind.CallOpts) (common.Address, error) { var out []interface{} err := _SSZTest.contract.Call(opts, &out, "BEACON_ROOTS") if err != nil { return *new(common.Address), err } out0 := *abi.ConvertType(out[0], new(common.Address)).(*common.Address) return out0, err } // BEACONROOTS is a free data retrieval call binding the contract method 0x56d7e8fd. // // Solidity: function BEACON_ROOTS() view returns(address) func (_SSZTest *SSZTestSession) BEACONROOTS() (common.Address, error) { return _SSZTest.Contract.BEACONROOTS(&_SSZTest.CallOpts) } // BEACONROOTS is a free data retrieval call binding the contract method 0x56d7e8fd. // // Solidity: function BEACON_ROOTS() view returns(address) func (_SSZTest *SSZTestCallerSession) BEACONROOTS() (common.Address, error) { return _SSZTest.Contract.BEACONROOTS(&_SSZTest.CallOpts) } // GetParentBlockRootAt is a free data retrieval call binding the contract method 0xe2c37a98. // // Solidity: function getParentBlockRootAt(uint64 ts) view returns(bytes32 root) func (_SSZTest *SSZTestCaller) GetParentBlockRootAt(opts *bind.CallOpts, ts uint64) ([32]byte, error) { var out []interface{} err := _SSZTest.contract.Call(opts, &out, "getParentBlockRootAt", ts) if err != nil { return *new([32]byte), err } out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) return out0, err } // GetParentBlockRootAt is a free data retrieval call binding the contract method 0xe2c37a98. // // Solidity: function getParentBlockRootAt(uint64 ts) view returns(bytes32 root) func (_SSZTest *SSZTestSession) GetParentBlockRootAt(ts uint64) ([32]byte, error) { return _SSZTest.Contract.GetParentBlockRootAt(&_SSZTest.CallOpts, ts) } // GetParentBlockRootAt is a free data retrieval call binding the contract method 0xe2c37a98. // // Solidity: function getParentBlockRootAt(uint64 ts) view returns(bytes32 root) func (_SSZTest *SSZTestCallerSession) GetParentBlockRootAt(ts uint64) ([32]byte, error) { return _SSZTest.Contract.GetParentBlockRootAt(&_SSZTest.CallOpts, ts) } // MustVerifyProof is a free data retrieval call binding the contract method 0x41b703ff. // // Solidity: function mustVerifyProof(bytes32[] proof, bytes32 root, bytes32 leaf, uint256 index) view returns() func (_SSZTest *SSZTestCaller) MustVerifyProof(opts *bind.CallOpts, proof [][32]byte, root [32]byte, leaf [32]byte, index *big.Int) error { var out []interface{} err := _SSZTest.contract.Call(opts, &out, "mustVerifyProof", proof, root, leaf, index) if err != nil { return err } return err } // MustVerifyProof is a free data retrieval call binding the contract method 0x41b703ff. // // Solidity: function mustVerifyProof(bytes32[] proof, bytes32 root, bytes32 leaf, uint256 index) view returns() func (_SSZTest *SSZTestSession) MustVerifyProof(proof [][32]byte, root [32]byte, leaf [32]byte, index *big.Int) error { return _SSZTest.Contract.MustVerifyProof(&_SSZTest.CallOpts, proof, root, leaf, index) } // MustVerifyProof is a free data retrieval call binding the contract method 0x41b703ff. // // Solidity: function mustVerifyProof(bytes32[] proof, bytes32 root, bytes32 leaf, uint256 index) view returns() func (_SSZTest *SSZTestCallerSession) MustVerifyProof(proof [][32]byte, root [32]byte, leaf [32]byte, index *big.Int) error { return _SSZTest.Contract.MustVerifyProof(&_SSZTest.CallOpts, proof, root, leaf, index) } // VerifyProof is a free data retrieval call binding the contract method 0x4fc36be6. // // Solidity: function verifyProof(bytes32[] proof, bytes32 root, bytes32 leaf, uint256 index) view returns(bool isValid) func (_SSZTest *SSZTestCaller) VerifyProof(opts *bind.CallOpts, proof [][32]byte, root [32]byte, leaf [32]byte, index *big.Int) (bool, error) { var out []interface{} err := _SSZTest.contract.Call(opts, &out, "verifyProof", proof, root, leaf, index) if err != nil { return *new(bool), err } out0 := *abi.ConvertType(out[0], new(bool)).(*bool) return out0, err } // VerifyProof is a free data retrieval call binding the contract method 0x4fc36be6. // // Solidity: function verifyProof(bytes32[] proof, bytes32 root, bytes32 leaf, uint256 index) view returns(bool isValid) func (_SSZTest *SSZTestSession) VerifyProof(proof [][32]byte, root [32]byte, leaf [32]byte, index *big.Int) (bool, error) { return _SSZTest.Contract.VerifyProof(&_SSZTest.CallOpts, proof, root, leaf, index) } // VerifyProof is a free data retrieval call binding the contract method 0x4fc36be6. // // Solidity: function verifyProof(bytes32[] proof, bytes32 root, bytes32 leaf, uint256 index) view returns(bool isValid) func (_SSZTest *SSZTestCallerSession) VerifyProof(proof [][32]byte, root [32]byte, leaf [32]byte, index *big.Int) (bool, error) { return _SSZTest.Contract.VerifyProof(&_SSZTest.CallOpts, proof, root, leaf, index) } ================================================ FILE: gethlib/ssztest/contract.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ssztest // TODO: Remove ldflags=-checklinkname=0 override once fix is applied. // //go:generate abigen --abi=../../contracts/out/SSZ.sol/SSZTest.abi.json --bin=../../contracts/out/SSZ.sol/SSZTest.bin --pkg=ssztest --type=SSZTest --out=contract.abigen.go ================================================ FILE: gethlib/types/block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "math/big" "slices" "sync/atomic" "time" "github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" coretypes "github.com/ethereum/go-ethereum/core/types" ) // Block represents a Berachain block. // // Note the Block type tries to be 'immutable', and contains certain caches that rely // on that. The rules around block immutability are as follows: // // - We copy all data when the block is constructed. This makes references held inside // the block independent of whatever value was passed in. // // - We copy all header data on access. This is because any change to the header would mess // up the cached hash and size values in the block. Calling code is expected to take // advantage of this to avoid over-allocating! // // - When new body data is attached to the block, a shallow copy of the block is returned. // This ensures block modifications are race-free. // // - We do not copy body data on access because it does not affect the caches, and also // because it would be too expensive. type Block struct { header *Header uncles []*Header transactions Transactions withdrawals coretypes.Withdrawals // caches hash atomic.Pointer[common.Hash] // These fields are used by package eth to track // inter-peer block relay. ReceivedAt time.Time ReceivedFrom interface{} } // Body is a simple (mutable, non-safe) data container for storing and moving // a block's data contents (transactions and uncles) together. type Body struct { Transactions []*Transaction Uncles []*Header Withdrawals []*coretypes.Withdrawal `rlp:"optional"` } // NewBlock creates a new block. The input data is copied, changes to header and to the // field values will not affect the block. // // The body elements and the receipts are used to recompute and overwrite the // relevant portions of the header. // // The receipt's bloom must already calculated for the block's bloom to be // correctly calculated. func NewBlock(header *Header, body *Body, receipts []*coretypes.Receipt, hasher coretypes.ListHasher) *Block { if body == nil { body = &Body{} } var ( b = NewBlockWithHeader(header) txs = body.Transactions uncles = body.Uncles withdrawals = body.Withdrawals ) if len(txs) == 0 { b.header.TxHash = coretypes.EmptyTxsHash } else { b.header.TxHash = coretypes.DeriveSha(Transactions(txs), hasher) b.transactions = make(Transactions, len(txs)) copy(b.transactions, txs) } if len(receipts) == 0 { b.header.ReceiptHash = coretypes.EmptyReceiptsHash } else { b.header.ReceiptHash = coretypes.DeriveSha(coretypes.Receipts(receipts), hasher) // Receipts must go through MakeReceipt to calculate the receipt's bloom // already. Merge the receipt's bloom together instead of recalculating // everything. b.header.Bloom = coretypes.MergeBloom(receipts) } if len(uncles) == 0 { b.header.UncleHash = coretypes.EmptyUncleHash } else { b.header.UncleHash = CalcUncleHash(uncles) b.uncles = make([]*Header, len(uncles)) for i := range uncles { b.uncles[i] = CopyHeader(uncles[i]) } } switch { case withdrawals == nil: b.header.WithdrawalsHash = nil case len(withdrawals) == 0: b.header.WithdrawalsHash = &coretypes.EmptyWithdrawalsHash b.withdrawals = coretypes.Withdrawals{} default: hash := coretypes.DeriveSha(coretypes.Withdrawals(withdrawals), hasher) b.header.WithdrawalsHash = &hash b.withdrawals = slices.Clone(withdrawals) } return b } // NewBlockWithHeader creates a block with the given header data. The // header data is copied, changes to header and to the field values // will not affect the block. func NewBlockWithHeader(header *Header) *Block { return &Block{header: CopyHeader(header)} } // WithBody returns a new block with the original header and a deep copy of the // provided body. func (b *Block) WithBody(body Body) *Block { block := &Block{ header: b.header, transactions: slices.Clone(body.Transactions), uncles: make([]*Header, len(body.Uncles)), withdrawals: slices.Clone(body.Withdrawals), } for i := range body.Uncles { block.uncles[i] = CopyHeader(body.Uncles[i]) } return block } // Hash returns the keccak256 hash of b's header. // The hash is computed on the first call and cached thereafter. func (b *Block) Hash() common.Hash { if hash := b.hash.Load(); hash != nil { return *hash } h := b.header.Hash() b.hash.Store(&h) return h } // Accessors for body data. These do not return a copy because the content // of the body slices does not affect the cached hash/size in block. func (b *Block) Transactions() Transactions { return b.transactions } func (b *Block) Withdrawals() coretypes.Withdrawals { return b.withdrawals } // Header value accessors. These do copy! func (b *Block) GasLimit() uint64 { return b.header.GasLimit } func (b *Block) GasUsed() uint64 { return b.header.GasUsed } func (b *Block) Time() uint64 { return b.header.Time } func (b *Block) NumberU64() uint64 { return b.header.Number.Uint64() } func (b *Block) MixDigest() common.Hash { return b.header.MixDigest } func (b *Block) Bloom() coretypes.Bloom { return b.header.Bloom } func (b *Block) Coinbase() common.Address { return b.header.Coinbase } func (b *Block) Root() common.Hash { return b.header.Root } func (b *Block) ParentHash() common.Hash { return b.header.ParentHash } func (b *Block) ReceiptHash() common.Hash { return b.header.ReceiptHash } func (b *Block) Extra() []byte { return common.CopyBytes(b.header.Extra) } func (b *Block) BaseFee() *big.Int { if b.header.BaseFee == nil { return nil } return new(big.Int).Set(b.header.BaseFee) } func (b *Block) ExcessBlobGas() *uint64 { var excessBlobGas *uint64 if b.header.ExcessBlobGas != nil { excessBlobGas = new(uint64) *excessBlobGas = *b.header.ExcessBlobGas } return excessBlobGas } func (b *Block) BlobGasUsed() *uint64 { var blobGasUsed *uint64 if b.header.BlobGasUsed != nil { blobGasUsed = new(uint64) *blobGasUsed = *b.header.BlobGasUsed } return blobGasUsed } // BlockToExecutableData constructs the ExecutableData structure by filling the // fields from the given block. It assumes the given block is post-merge block. func BlockToExecutableData( block *Block, fees *big.Int, sidecars []*coretypes.BlobTxSidecar, requests [][]byte, ) *engine.ExecutionPayloadEnvelope { data := &engine.ExecutableData{ BlockHash: block.Hash(), ParentHash: block.ParentHash(), FeeRecipient: block.Coinbase(), StateRoot: block.Root(), Number: block.NumberU64(), GasLimit: block.GasLimit(), GasUsed: block.GasUsed(), BaseFeePerGas: block.BaseFee(), Timestamp: block.Time(), ReceiptsRoot: block.ReceiptHash(), LogsBloom: block.Bloom().Bytes(), Transactions: encodeTransactions(block.Transactions()), Random: block.MixDigest(), ExtraData: block.Extra(), Withdrawals: block.Withdrawals(), BlobGasUsed: block.BlobGasUsed(), ExcessBlobGas: block.ExcessBlobGas(), } // Add blobs. bundle := engine.BlobsBundle{ Commitments: make([]hexutil.Bytes, 0), Blobs: make([]hexutil.Bytes, 0), Proofs: make([]hexutil.Bytes, 0), } for _, sidecar := range sidecars { for j := range sidecar.Blobs { bundle.Blobs = append(bundle.Blobs, sidecar.Blobs[j][:]) bundle.Commitments = append(bundle.Commitments, sidecar.Commitments[j][:]) } // - Before the Osaka fork, only version-0 blob transactions should be packed, // with the proof length equal to len(blobs). // // - After the Osaka fork, only version-1 blob transactions should be packed, // with the proof length equal to CELLS_PER_EXT_BLOB * len(blobs). // // Ideally, length validation should be performed based on the bundle version. // In practice, this is unnecessary because blob transaction filtering is // already done during payload construction. for _, proof := range sidecar.Proofs { bundle.Proofs = append(bundle.Proofs, proof[:]) } } return &engine.ExecutionPayloadEnvelope{ ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Requests: requests, Override: false, } } func encodeTransactions(txs []*Transaction) [][]byte { var enc = make([][]byte, len(txs)) for i, tx := range txs { enc[i], _ = tx.MarshalBinary() } return enc } ================================================ FILE: gethlib/types/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" ) // ChainConfig is the core config which determines the blockchain settings. // // ChainConfig is stored in the database on a per block basis. This means // that any network, identified by its genesis block, can have its own // set of configuration options. type ChainConfig struct { ChainID *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead) DAOForkBlock *big.Int `json:"daoForkBlock,omitempty"` // TheDAO hard-fork switch block (nil = no fork) DAOForkSupport bool `json:"daoForkSupport,omitempty"` // Whether the nodes supports or opposes the DAO hard-fork // EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150) EIP150Block *big.Int `json:"eip150Block,omitempty"` // EIP150 HF block (nil = no fork) EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium) ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated) PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople) IstanbulBlock *big.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul) // MuirGlacierBlock is EIP-2384 (difficulty bomb delay) switch block. MuirGlacierBlock *big.Int `json:"muirGlacierBlock,omitempty"` // nil = no fork, 0 = already activated BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin) LondonBlock *big.Int `json:"londonBlock,omitempty"` // London switch block (nil = no fork, 0 = already on london) // ArrowGlacierBlock is EIP-4345 (difficulty bomb delay) switch block. ArrowGlacierBlock *big.Int `json:"arrowGlacierBlock,omitempty"` // nil = no fork, 0 = already activated // GrayGlacierBlock is EIP-5133 (difficulty bomb delay) switch block. GrayGlacierBlock *big.Int `json:"grayGlacierBlock,omitempty"` // nil = no fork, 0 = already activated MergeNetsplitBlock *big.Int `json:"mergeNetsplitBlock,omitempty"` // Virtual fork after The Merge to use as a network splitter // Fork scheduling was switched from blocks to timestamps here ShanghaiTime *uint64 `json:"shanghaiTime,omitempty"` // Shanghai switch time (nil = no fork, 0 = already on shanghai) CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka) BPO1Time *uint64 `json:"bpo1Time,omitempty"` // BPO1 switch time (nil = no fork, 0 = already on bpo1) BPO2Time *uint64 `json:"bpo2Time,omitempty"` // BPO2 switch time (nil = no fork, 0 = already on bpo2) BPO3Time *uint64 `json:"bpo3Time,omitempty"` // BPO3 switch time (nil = no fork, 0 = already on bpo3) BPO4Time *uint64 `json:"bpo4Time,omitempty"` // BPO4 switch time (nil = no fork, 0 = already on bpo4) BPO5Time *uint64 `json:"bpo5Time,omitempty"` // BPO5 switch time (nil = no fork, 0 = already on bpo5) AmsterdamTime *uint64 `json:"amsterdamTime,omitempty"` // Amsterdam switch time (nil = no fork, 0 = already on amsterdam) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"` DepositContractAddress common.Address `json:"depositContractAddress,omitempty"` // EnableVerkleAtGenesis is a flag that specifies whether the network uses // the Verkle tree starting from the genesis block. If set to true, the // genesis state will be committed using the Verkle tree, eliminating the // need for any Verkle transition later. // // This is a temporary flag only for verkle devnet testing, where verkle is // activated at genesis, and the configured activation date has already passed. // // In production networks (mainnet and public testnets), verkle activation // always occurs after the genesis block, making this flag irrelevant in // those cases. EnableVerkleAtGenesis bool `json:"enableVerkleAtGenesis,omitempty"` // Various consensus engines Ethash *params.EthashConfig `json:"ethash,omitempty"` Clique *params.CliqueConfig `json:"clique,omitempty"` BlobScheduleConfig *params.BlobScheduleConfig `json:"blobSchedule,omitempty"` // Berachain config Berachain BerachainConfig `json:"berachain,omitempty"` } // BerachainConfig is the berachain config. type BerachainConfig struct { // Prague1 fork values. Prague1 Prague1Config `json:"prague1,omitempty"` // Prague2 fork values. Prague2 Prague2Config `json:"prague2,omitempty"` // Prague3 fork values. Prague3 Prague3Config `json:"prague3,omitempty"` // Prague4 fork values. Prague4 Prague4Config `json:"prague4,omitempty"` } // Prague1Config is the config values for the Prague1 fork on Berachain. type Prague1Config struct { // Time is the time of the Prague1 fork. Time *uint64 `json:"time,omitempty"` // Prague1 switch time (0 = already on prague1, nil = no fork) // BaseFeeChangeDenominator is the base fee change denominator. BaseFeeChangeDenominator uint64 `json:"baseFeeChangeDenominator,omitempty"` // MinimumBaseFeeWei is the minimum base fee in wei. MinimumBaseFeeWei *big.Int `json:"minimumBaseFeeWei,omitempty"` // PoLDistributorAddress is the address of the PoL distributor. PoLDistributorAddress common.Address `json:"polDistributorAddress,omitempty"` } // Prague2Config is the config values for the Prague2 fork on Berachain. type Prague2Config struct { // Time is the time of the Prague2 fork. Time *uint64 `json:"time,omitempty"` // Prague2 switch time (0 = already on prague2, nil = no fork) // MinimumBaseFeeWei is the minimum base fee in wei. MinimumBaseFeeWei *big.Int `json:"minimumBaseFeeWei,omitempty"` } // Prague3Config is the config values for the Prague3 fork on Berachain. type Prague3Config struct { // Time is the time of the Prague3 fork. Time *uint64 `json:"time,omitempty"` // Prague3 switch time (0 = already on prague3, nil = no fork) // BexVaultAddress is the address of the BEX vault. BexVaultAddress common.Address `json:"bexVaultAddress,omitempty"` // BlockedAddresses is the list of addresses blocked from sending or receiving ERC20 transfers. BlockedAddresses []common.Address `json:"blockedAddresses,omitempty"` // RescueAddress is the only address that blocked addresses can send to. RescueAddress common.Address `json:"rescueAddress,omitempty"` } // Prague4Config is the config values for the Prague4 fork on Berachain. type Prague4Config struct { // Time is the time of the Prague4 fork. Time *uint64 `json:"time,omitempty"` // Prague4 switch time (0 = already on prague4, nil = no fork) } // IsLondon returns whether num is either equal to the London fork block or greater. func (c *ChainConfig) IsLondon(num *big.Int) bool { return isBlockForked(c.LondonBlock, num) } // IsShanghai returns whether time is either equal to the Shanghai fork time or greater. func (c *ChainConfig) IsShanghai(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.ShanghaiTime, time) } // IsCancun returns whether time is either equal to the Cancun fork time or greater. func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.CancunTime, time) } // IsPrague returns whether time is either equal to the Prague fork time or greater. func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool { return c.IsLondon(num) && isTimestampForked(c.PragueTime, time) } // IsPrague1 returns whether time is either equal to the Prague1 fork time or greater. // NOTE: Prague1 is a Berachain fork and must be on Ethereum's Prague fork. func (c *ChainConfig) IsPrague1(num *big.Int, time uint64) bool { return c.IsPrague(num, time) && isTimestampForked(c.Berachain.Prague1.Time, time) } // IsVerkleGenesis checks whether the verkle fork is activated at the genesis block. // // Verkle mode is considered enabled if the verkle fork time is configured, // regardless of whether the local time has surpassed the fork activation time. // This is a temporary workaround for verkle devnet testing, where verkle is // activated at genesis, and the configured activation date has already passed. // // In production networks (mainnet and public testnets), verkle activation // always occurs after the genesis block, making this function irrelevant in // those cases. func (c *ChainConfig) IsVerkleGenesis() bool { return c.EnableVerkleAtGenesis } // isBlockForked returns whether a fork scheduled at block s is active at the // given head block. Whilst this method is the same as isTimestampForked, they // are explicitly separate for clearer reading. func isBlockForked(s, head *big.Int) bool { if s == nil || head == nil { return false } return s.Cmp(head) <= 0 } // isTimestampForked returns whether a fork scheduled at timestamp s is active // at the given head timestamp. Whilst this method is the same as isBlockForked, // they are explicitly separate for clearer reading. func isTimestampForked(s *uint64, head uint64) bool { if s == nil { return false } return *s <= head } ================================================ FILE: gethlib/types/genesis.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "encoding/json" "errors" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb/pathdb" "github.com/holiman/uint256" ) // Genesis specifies the header fields, state of a genesis block. It also defines hard // fork switch-over blocks through the chain configuration. type Genesis struct { Config *ChainConfig `json:"config"` Nonce uint64 `json:"nonce"` Timestamp uint64 `json:"timestamp"` ExtraData []byte `json:"extraData"` GasLimit uint64 `json:"gasLimit" gencodec:"required"` Difficulty *big.Int `json:"difficulty" gencodec:"required"` Mixhash common.Hash `json:"mixHash"` Coinbase common.Address `json:"coinbase"` Alloc types.GenesisAlloc `json:"alloc" gencodec:"required"` // These fields are used for consensus tests. Please don't use them // in actual genesis blocks. Number uint64 `json:"number"` GasUsed uint64 `json:"gasUsed"` ParentHash common.Hash `json:"parentHash"` BaseFee *big.Int `json:"baseFeePerGas"` // EIP-1559 ExcessBlobGas *uint64 `json:"excessBlobGas"` // EIP-4844 BlobGasUsed *uint64 `json:"blobGasUsed"` // EIP-4844 } // IsVerkle indicates whether the state is already stored in a verkle // tree at genesis time. func (g *Genesis) IsVerkle() bool { return g.Config.IsVerkleGenesis() } // ToBlock returns the genesis block according to genesis specification. func (g *Genesis) ToBlock() *Block { root, err := hashAlloc(&g.Alloc, g.IsVerkle()) if err != nil { panic(err) } return g.toBlockWithRoot(root) } // UnmarshalJSON unmarshals from JSON. func (g *Genesis) UnmarshalJSON(input []byte) error { type Genesis struct { Config *ChainConfig `json:"config"` Nonce *math.HexOrDecimal64 `json:"nonce"` Timestamp *math.HexOrDecimal64 `json:"timestamp"` ExtraData *hexutil.Bytes `json:"extraData"` GasLimit *math.HexOrDecimal64 `json:"gasLimit" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"difficulty" gencodec:"required"` Mixhash *common.Hash `json:"mixHash"` Coinbase *common.Address `json:"coinbase"` Alloc map[common.UnprefixedAddress]types.Account `json:"alloc" gencodec:"required"` Number *math.HexOrDecimal64 `json:"number"` GasUsed *math.HexOrDecimal64 `json:"gasUsed"` ParentHash *common.Hash `json:"parentHash"` BaseFee *math.HexOrDecimal256 `json:"baseFeePerGas"` ExcessBlobGas *math.HexOrDecimal64 `json:"excessBlobGas"` BlobGasUsed *math.HexOrDecimal64 `json:"blobGasUsed"` } var dec Genesis if err := json.Unmarshal(input, &dec); err != nil { return err } if dec.Config != nil { g.Config = dec.Config } if dec.Nonce != nil { g.Nonce = uint64(*dec.Nonce) } if dec.Timestamp != nil { g.Timestamp = uint64(*dec.Timestamp) } if dec.ExtraData != nil { g.ExtraData = *dec.ExtraData } if dec.GasLimit == nil { return errors.New("missing required field 'gasLimit' for Genesis") } g.GasLimit = uint64(*dec.GasLimit) if dec.Difficulty == nil { return errors.New("missing required field 'difficulty' for Genesis") } g.Difficulty = (*big.Int)(dec.Difficulty) if dec.Mixhash != nil { g.Mixhash = *dec.Mixhash } if dec.Coinbase != nil { g.Coinbase = *dec.Coinbase } if dec.Alloc == nil { return errors.New("missing required field 'alloc' for Genesis") } g.Alloc = make(types.GenesisAlloc, len(dec.Alloc)) for k, v := range dec.Alloc { g.Alloc[common.Address(k)] = v } if dec.Number != nil { g.Number = uint64(*dec.Number) } if dec.GasUsed != nil { g.GasUsed = uint64(*dec.GasUsed) } if dec.ParentHash != nil { g.ParentHash = *dec.ParentHash } if dec.BaseFee != nil { g.BaseFee = (*big.Int)(dec.BaseFee) } if dec.ExcessBlobGas != nil { g.ExcessBlobGas = (*uint64)(dec.ExcessBlobGas) } if dec.BlobGasUsed != nil { g.BlobGasUsed = (*uint64)(dec.BlobGasUsed) } return nil } // toBlockWithRoot constructs the genesis block with the given genesis state root. // //nolint:gocognit,nestif // Mirrors geth's fork-specific genesis initialization flow. func (g *Genesis) toBlockWithRoot(root common.Hash) *Block { head := &Header{ Number: new(big.Int).SetUint64(g.Number), Nonce: types.EncodeNonce(g.Nonce), Time: g.Timestamp, ParentHash: g.ParentHash, Extra: g.ExtraData, GasLimit: g.GasLimit, GasUsed: g.GasUsed, BaseFee: g.BaseFee, Difficulty: g.Difficulty, MixDigest: g.Mixhash, Coinbase: g.Coinbase, Root: root, } if g.GasLimit == 0 { head.GasLimit = params.GenesisGasLimit } if g.Difficulty == nil { if g.Config != nil && g.Config.Ethash == nil { head.Difficulty = big.NewInt(0) } else if g.Mixhash == (common.Hash{}) { head.Difficulty = params.GenesisDifficulty } } if g.Config != nil && g.Config.IsLondon(common.Big0) { if g.BaseFee != nil { head.BaseFee = g.BaseFee } else { head.BaseFee = new(big.Int).SetUint64(params.InitialBaseFee) } } var ( withdrawals []*types.Withdrawal ) if conf := g.Config; conf != nil { num := new(big.Int).SetUint64(g.Number) if conf.IsShanghai(num, g.Timestamp) { head.WithdrawalsHash = &types.EmptyWithdrawalsHash withdrawals = make([]*types.Withdrawal, 0) } if conf.IsCancun(num, g.Timestamp) { // EIP-4788: The parentBeaconBlockRoot of the genesis block is always // the zero hash. This is because the genesis block does not have a parent // by definition. head.ParentBeaconRoot = new(common.Hash) // EIP-4844 fields head.ExcessBlobGas = g.ExcessBlobGas head.BlobGasUsed = g.BlobGasUsed if head.ExcessBlobGas == nil { head.ExcessBlobGas = new(uint64) } if head.BlobGasUsed == nil { head.BlobGasUsed = new(uint64) } } else if g.ExcessBlobGas != nil { log.Warn("Invalid genesis, unexpected ExcessBlobGas set before Cancun, allowing it for testing purposes") head.ExcessBlobGas = g.ExcessBlobGas } if conf.IsPrague(num, g.Timestamp) { head.RequestsHash = &types.EmptyRequestsHash } if conf.IsPrague1(num, g.Timestamp) { // BRIP-0004: The parentProposerPubkey of the genesis block is always // the zero pubkey. This is because the genesis block does not have a parent // by definition. head.ParentProposerPubkey = new(ExecutionPubkey) } } return NewBlock(head, &Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil)) } // hashAlloc computes the state root according to the genesis specification. func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) { // If a genesis-time verkle trie is requested, create a trie config // with the verkle trie enabled so that the tree can be initialized // as such. var config *triedb.Config if isVerkle { config = &triedb.Config{ PathDB: pathdb.Defaults, IsVerkle: true, } } // Create an ephemeral in-memory database for computing hash, // all the derived states will be discarded to not pollute disk. emptyRoot := types.EmptyRootHash if isVerkle { emptyRoot = types.EmptyVerkleHash } db := rawdb.NewMemoryDatabase() statedb, err := state.New(emptyRoot, state.NewDatabase(triedb.NewDatabase(db, config), nil)) if err != nil { return common.Hash{}, err } for addr, account := range *ga { if account.Balance != nil { statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), tracing.BalanceIncreaseGenesisBalance) } statedb.SetCode(addr, account.Code, tracing.CodeChangeGenesis) statedb.SetNonce(addr, account.Nonce, tracing.NonceChangeGenesis) for key, value := range account.Storage { statedb.SetState(addr, key, value) } } return statedb.Commit(0, false, false) } ================================================ FILE: gethlib/types/header.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "math/big" "sync" "github.com/ethereum/go-ethereum/common" coretypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" ) // hasherPool holds LegacyKeccak256 buffer for rlpHash. // //nolint:gochecknoglobals // Shared pool is required to avoid allocations in hash hot paths. var hasherPool = sync.Pool{ New: func() interface{} { return crypto.NewKeccakState() }, } // Header represents a block header in the Ethereum blockchain. type Header struct { ParentHash common.Hash `json:"parentHash" gencodec:"required"` UncleHash common.Hash `json:"sha3Uncles" gencodec:"required"` Coinbase common.Address `json:"miner"` Root common.Hash `json:"stateRoot" gencodec:"required"` TxHash common.Hash `json:"transactionsRoot" gencodec:"required"` ReceiptHash common.Hash `json:"receiptsRoot" gencodec:"required"` Bloom coretypes.Bloom `json:"logsBloom" gencodec:"required"` Difficulty *big.Int `json:"difficulty" gencodec:"required"` Number *big.Int `json:"number" gencodec:"required"` GasLimit uint64 `json:"gasLimit" gencodec:"required"` GasUsed uint64 `json:"gasUsed" gencodec:"required"` Time uint64 `json:"timestamp" gencodec:"required"` Extra []byte `json:"extraData" gencodec:"required"` MixDigest common.Hash `json:"mixHash"` Nonce coretypes.BlockNonce `json:"nonce"` // BaseFee was added by EIP-1559 and is ignored in legacy headers. BaseFee *big.Int `json:"baseFeePerGas" rlp:"optional"` // WithdrawalsHash was added by EIP-4895 and is ignored in legacy headers. WithdrawalsHash *common.Hash `json:"withdrawalsRoot" rlp:"optional"` // BlobGasUsed was added by EIP-4844 and is ignored in legacy headers. BlobGasUsed *uint64 `json:"blobGasUsed" rlp:"optional"` // ExcessBlobGas was added by EIP-4844 and is ignored in legacy headers. ExcessBlobGas *uint64 `json:"excessBlobGas" rlp:"optional"` // ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers. ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"` // RequestsHash was added by EIP-7685 and is ignored in legacy headers. RequestsHash *common.Hash `json:"requestsHash" rlp:"optional"` // ParentProposerPubkey was added by BRIP-0004 and is ignored in legacy headers. ParentProposerPubkey *ExecutionPubkey `json:"parentProposerPubkey" rlp:"optional"` } // CopyHeader creates a deep copy of a block header. func CopyHeader(h *Header) *Header { cpy := *h if cpy.Difficulty = new(big.Int); h.Difficulty != nil { cpy.Difficulty.Set(h.Difficulty) } if cpy.Number = new(big.Int); h.Number != nil { cpy.Number.Set(h.Number) } if h.BaseFee != nil { cpy.BaseFee = new(big.Int).Set(h.BaseFee) } if len(h.Extra) > 0 { cpy.Extra = make([]byte, len(h.Extra)) copy(cpy.Extra, h.Extra) } if h.WithdrawalsHash != nil { cpy.WithdrawalsHash = new(common.Hash) *cpy.WithdrawalsHash = *h.WithdrawalsHash } if h.ExcessBlobGas != nil { cpy.ExcessBlobGas = new(uint64) *cpy.ExcessBlobGas = *h.ExcessBlobGas } if h.BlobGasUsed != nil { cpy.BlobGasUsed = new(uint64) *cpy.BlobGasUsed = *h.BlobGasUsed } if h.ParentBeaconRoot != nil { cpy.ParentBeaconRoot = new(common.Hash) *cpy.ParentBeaconRoot = *h.ParentBeaconRoot } if h.RequestsHash != nil { cpy.RequestsHash = new(common.Hash) *cpy.RequestsHash = *h.RequestsHash } if h.ParentProposerPubkey != nil { cpy.ParentProposerPubkey = new(ExecutionPubkey) *cpy.ParentProposerPubkey = *h.ParentProposerPubkey } return &cpy } // Hash returns the block hash of the header, which is simply the keccak256 hash of its // RLP encoding. func (h *Header) Hash() common.Hash { return rlpHash(h) } ================================================ FILE: gethlib/types/pubkey.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "bytes" "encoding/hex" "fmt" "reflect" "github.com/berachain/beacon-kit/primitives/constants" "github.com/ethereum/go-ethereum/common/hexutil" ) // ExecutionPubkey represents a 48-byte BLS12-381 public key on the execution layer. // JSON and text serialization use 0x-prefixed hex strings. type ExecutionPubkey [constants.BLSPubkeyLength]byte const ( hexPrefixBytes = 2 hexCharsPerByte = 2 ) // Bytes returns a copy of the underlying byte slice. func (p ExecutionPubkey) Bytes() []byte { return p[:] } // String returns the hex-encoded string representation of the pubkey. func (p ExecutionPubkey) String() string { return hexutil.Encode(p[:]) } // Format implements fmt.Formatter. // Pubkey supports the %v, %s, %q, %x, %X and %d format verbs. // // #nosec:G104 // copied from geth and fmt.State.Write errors are conventionally ignored func (p ExecutionPubkey) Format(s fmt.State, c rune) { hexb := make([]byte, hexPrefixBytes+len(p)*hexCharsPerByte) copy(hexb, "0x") hex.Encode(hexb[hexPrefixBytes:], p[:]) switch c { case 'x', 'X': if !s.Flag('#') { hexb = hexb[hexPrefixBytes:] } if c == 'X' { hexb = bytes.ToUpper(hexb) } fallthrough case 'v', 's': _, _ = s.Write(hexb) case 'q': q := []byte{'"'} _, _ = s.Write(q) _, _ = s.Write(hexb) _, _ = s.Write(q) case 'd': fmt.Fprint(s, ([len(p)]byte)(p)) default: fmt.Fprintf(s, "%%!%c(pubkey=%x)", c, p) } } // MarshalText encodes the pubkey as a 0x-prefixed hex string. func (p ExecutionPubkey) MarshalText() ([]byte, error) { return hexutil.Bytes(p[:]).MarshalText() } // UnmarshalText decodes a 0x-prefixed hex string into the pubkey. func (p *ExecutionPubkey) UnmarshalText(input []byte) error { return hexutil.UnmarshalFixedText("Pubkey", input, p[:]) } // UnmarshalJSON decodes a JSON string containing the 0x-prefixed hex pubkey. func (p *ExecutionPubkey) UnmarshalJSON(input []byte) error { return hexutil.UnmarshalFixedJSON(reflect.TypeOf(ExecutionPubkey{}), input, p[:]) } ================================================ FILE: gethlib/types/transaction.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "bytes" "errors" "math/big" "sync/atomic" "github.com/ethereum/go-ethereum/common" coretypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" ) // TxData is the underlying data of a transaction. type TxData interface { txType() byte // returns the type ID encode(*bytes.Buffer) error decode([]byte) error } // Transaction is similar to coretypes.Transaction, with added support // for the BRIP-0004 PoL transaction type. type Transaction struct { inner TxData // Consensus contents of a transaction // cache hash atomic.Pointer[common.Hash] } // BlobHashes returns the hashes of the blob commitments for blob transactions, nil otherwise. func (tx *Transaction) BlobHashes() []common.Hash { if blobtx, ok := tx.inner.(*BlobTx); ok { return blobtx.BlobHashes } return nil } // Hash returns the transaction hash. func (tx *Transaction) Hash() common.Hash { if hash := tx.hash.Load(); hash != nil { return *hash } var h common.Hash if tx.Type() == coretypes.LegacyTxType { h = rlpHash(tx.inner) } else { h = prefixedRlpHash(tx.Type(), tx.inner) } tx.hash.Store(&h) return h } // Type returns the transaction type. func (tx *Transaction) Type() uint8 { return tx.inner.txType() } // RawSignatureValues returns the transaction signature values. // PoL transactions intentionally return nil values because they are unsigned. func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) { switch itx := tx.inner.(type) { case *LegacyTx: return itx.V, itx.R, itx.S case *AccessListTx: return itx.V, itx.R, itx.S case *DynamicFeeTx: return itx.V, itx.R, itx.S case *BlobTx: if itx.V == nil || itx.R == nil || itx.S == nil { return nil, nil, nil } return itx.V.ToBig(), itx.R.ToBig(), itx.S.ToBig() case *SetCodeTx: if itx.V == nil || itx.R == nil || itx.S == nil { return nil, nil, nil } return itx.V.ToBig(), itx.R.ToBig(), itx.S.ToBig() default: return nil, nil, nil } } // MarshalBinary returns the canonical encoding of the transaction. // For legacy transactions, it returns the RLP encoding. For EIP-2718 typed // transactions, it returns the type and payload. func (tx *Transaction) MarshalBinary() ([]byte, error) { if tx.Type() == coretypes.LegacyTxType { return rlp.EncodeToBytes(tx.inner) } var buf bytes.Buffer err := tx.encodeTyped(&buf) return buf.Bytes(), err } // UnmarshalBinary decodes the canonical encoding of transactions. // It supports legacy RLP transactions and EIP-2718 typed transactions. func (tx *Transaction) UnmarshalBinary(b []byte) error { if len(b) > 0 && b[0] > 0x7f { // It's a legacy transaction. var data LegacyTx err := rlp.DecodeBytes(b, &data) if err != nil { return err } tx.setDecoded(&data) return nil } // It's an EIP-2718 typed transaction envelope. inner, err := tx.decodeTyped(b) if err != nil { return err } tx.setDecoded(inner) return nil } // encodeTyped writes the canonical encoding of a typed transaction to w. func (tx *Transaction) encodeTyped(w *bytes.Buffer) error { w.WriteByte(tx.Type()) return tx.inner.encode(w) } // decodeTyped decodes a typed transaction from the canonical format. func (tx *Transaction) decodeTyped(b []byte) (TxData, error) { if len(b) <= 1 { return nil, errors.New("typed transaction too short") } var inner TxData switch b[0] { case coretypes.AccessListTxType: inner = new(AccessListTx) case coretypes.DynamicFeeTxType: inner = new(DynamicFeeTx) case coretypes.BlobTxType: inner = new(BlobTx) case coretypes.SetCodeTxType: inner = new(SetCodeTx) case PoLTxType: inner = new(PoLTx) default: return nil, coretypes.ErrTxTypeNotSupported } err := inner.decode(b[1:]) return inner, err } // setDecoded sets the inner transaction and clears hash cache. func (tx *Transaction) setDecoded(inner TxData) { tx.inner = inner tx.hash.Store(nil) } // Transactions implements DerivableList for transactions. type Transactions []*Transaction // Len returns the length of s. func (s Transactions) Len() int { return len(s) } // EncodeIndex encodes the i'th transaction to w. Note that this does not check for errors // because we assume that *Transaction will only ever contain valid txs that were either // constructed by decoding or via public API in this package. func (s Transactions) EncodeIndex(i int, w *bytes.Buffer) { tx := s[i] if tx.Type() == coretypes.LegacyTxType { _ = rlp.Encode(w, tx.inner) } else { _ = tx.encodeTyped(w) } } ================================================ FILE: gethlib/types/transaction_marshalling.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "encoding/json" "errors" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" coretypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/holiman/uint256" ) var ( errInvalidYParity = errors.New("'yParity' field must be 0 or 1") errVYParityMismatch = errors.New("'v' and 'yParity' fields do not match") errVYParityMissing = errors.New("missing 'yParity' or 'v' field in transaction") ) const ( recoveryIDByteLen = 8 replayProtectionBitLen = 64 legacyVValue27 = 27 legacyVValue28 = 28 replayProtectionBase = 35 chainIDDivisor = 2 ) // txJSON is the JSON representation of transactions. type txJSON struct { Type hexutil.Uint64 `json:"type"` ChainID *hexutil.Big `json:"chainId,omitempty"` From *common.Address `json:"from,omitempty"` Nonce *hexutil.Uint64 `json:"nonce"` To *common.Address `json:"to"` Gas *hexutil.Uint64 `json:"gas"` GasPrice *hexutil.Big `json:"gasPrice"` MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` Value *hexutil.Big `json:"value"` Input *hexutil.Bytes `json:"input"` AccessList *coretypes.AccessList `json:"accessList,omitempty"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` AuthorizationList []coretypes.SetCodeAuthorization `json:"authorizationList,omitempty"` V *hexutil.Big `json:"v"` R *hexutil.Big `json:"r"` S *hexutil.Big `json:"s"` YParity *hexutil.Uint64 `json:"yParity,omitempty"` // Blob transaction sidecar encoding: Blobs []kzg4844.Blob `json:"blobs,omitempty"` Commitments []kzg4844.Commitment `json:"commitments,omitempty"` Proofs []kzg4844.Proof `json:"proofs,omitempty"` // Only used for encoding: Hash common.Hash `json:"hash"` } // yParityValue returns the YParity value from JSON. For backwards-compatibility reasons, // this can be given in the 'v' field or the 'yParity' field. If both exist, they must match. func (tx *txJSON) yParityValue() (*big.Int, error) { if tx.YParity != nil { val := uint64(*tx.YParity) if val != 0 && val != 1 { return nil, errInvalidYParity } bigval := new(big.Int).SetUint64(val) if tx.V != nil && tx.V.ToInt().Cmp(bigval) != 0 { return nil, errVYParityMismatch } return bigval, nil } if tx.V != nil { return tx.V.ToInt(), nil } return nil, errVYParityMissing } // MarshalJSON marshals as JSON with a hash. // //nolint:funlen // Mirrors geth transaction JSON shape for wire compatibility. func (tx *Transaction) MarshalJSON() ([]byte, error) { var enc txJSON hash := tx.Hash() // These are set for all tx types. enc.Hash = hash enc.Type = hexutil.Uint64(tx.Type()) // Other fields are set conditionally depending on tx type. switch itx := tx.inner.(type) { case *LegacyTx: enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.To = itx.To enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.GasPrice = (*hexutil.Big)(itx.GasPrice) enc.Value = (*hexutil.Big)(itx.Value) enc.Input = (*hexutil.Bytes)(&itx.Data) enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) if itx.V != nil && isProtectedV(itx.V) { enc.ChainID = (*hexutil.Big)(deriveChainID(itx.V)) } case *AccessListTx: enc.ChainID = (*hexutil.Big)(itx.ChainID) enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.To = itx.To enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.GasPrice = (*hexutil.Big)(itx.GasPrice) enc.Value = (*hexutil.Big)(itx.Value) enc.Input = (*hexutil.Bytes)(&itx.Data) enc.AccessList = &itx.AccessList enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) if itx.V != nil { yparity := itx.V.Uint64() enc.YParity = (*hexutil.Uint64)(&yparity) } case *DynamicFeeTx: enc.ChainID = (*hexutil.Big)(itx.ChainID) enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.To = itx.To enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap) enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap) enc.Value = (*hexutil.Big)(itx.Value) enc.Input = (*hexutil.Bytes)(&itx.Data) enc.AccessList = &itx.AccessList enc.V = (*hexutil.Big)(itx.V) enc.R = (*hexutil.Big)(itx.R) enc.S = (*hexutil.Big)(itx.S) if itx.V != nil { yparity := itx.V.Uint64() enc.YParity = (*hexutil.Uint64)(&yparity) } case *BlobTx: enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig()) enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap.ToBig()) enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap.ToBig()) enc.MaxFeePerBlobGas = (*hexutil.Big)(itx.BlobFeeCap.ToBig()) enc.Value = (*hexutil.Big)(itx.Value.ToBig()) enc.Input = (*hexutil.Bytes)(&itx.Data) enc.AccessList = &itx.AccessList enc.BlobVersionedHashes = itx.BlobHashes enc.To = &itx.To enc.V = (*hexutil.Big)(itx.V.ToBig()) enc.R = (*hexutil.Big)(itx.R.ToBig()) enc.S = (*hexutil.Big)(itx.S.ToBig()) yparity := itx.V.Uint64() enc.YParity = (*hexutil.Uint64)(&yparity) if sidecar := itx.Sidecar; sidecar != nil { enc.Blobs = itx.Sidecar.Blobs enc.Commitments = itx.Sidecar.Commitments enc.Proofs = itx.Sidecar.Proofs } case *SetCodeTx: enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig()) enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.To = &itx.To enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.MaxFeePerGas = (*hexutil.Big)(itx.GasFeeCap.ToBig()) enc.MaxPriorityFeePerGas = (*hexutil.Big)(itx.GasTipCap.ToBig()) enc.Value = (*hexutil.Big)(itx.Value.ToBig()) enc.Input = (*hexutil.Bytes)(&itx.Data) enc.AccessList = &itx.AccessList enc.AuthorizationList = itx.AuthList enc.V = (*hexutil.Big)(itx.V.ToBig()) enc.R = (*hexutil.Big)(itx.R.ToBig()) enc.S = (*hexutil.Big)(itx.S.ToBig()) yparity := itx.V.Uint64() enc.YParity = (*hexutil.Uint64)(&yparity) case *PoLTx: enc.ChainID = (*hexutil.Big)(itx.ChainID) enc.From = &itx.From enc.To = &itx.To enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) gas := hexutil.Uint64(itx.GasLimit) enc.Gas = &gas enc.GasPrice = (*hexutil.Big)(itx.GasPrice) enc.Input = (*hexutil.Bytes)(&itx.Data) } return json.Marshal(&enc) } // UnmarshalJSON unmarshals from JSON. // //nolint:gocognit,funlen,gocyclo,cyclop,maintidx // Mirrors geth transaction JSON shape for wire compatibility. func (tx *Transaction) UnmarshalJSON(input []byte) error { var dec txJSON if err := json.Unmarshal(input, &dec); err != nil { return err } // Decode / verify fields according to transaction type. var inner TxData txType := uint64(dec.Type) switch txType { case uint64(coretypes.LegacyTxType): var itx LegacyTx inner = &itx if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) if dec.To != nil { itx.To = dec.To } if dec.Gas == nil { return errors.New("missing required field 'gas' in transaction") } itx.Gas = uint64(*dec.Gas) if dec.GasPrice == nil { return errors.New("missing required field 'gasPrice' in transaction") } itx.GasPrice = (*big.Int)(dec.GasPrice) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } itx.Value = (*big.Int)(dec.Value) if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } itx.Data = *dec.Input // signature R if dec.R == nil { return errors.New("missing required field 'r' in transaction") } itx.R = (*big.Int)(dec.R) // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } itx.S = (*big.Int)(dec.S) // signature V if dec.V == nil { return errors.New("missing required field 'v' in transaction") } itx.V = (*big.Int)(dec.V) if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { sigErr := sanityCheckSignature(itx.V, itx.R, itx.S, true) if sigErr != nil { return sigErr } } case uint64(coretypes.AccessListTxType): var itx AccessListTx inner = &itx if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } itx.ChainID = (*big.Int)(dec.ChainID) if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) if dec.To != nil { itx.To = dec.To } if dec.Gas == nil { return errors.New("missing required field 'gas' in transaction") } itx.Gas = uint64(*dec.Gas) if dec.GasPrice == nil { return errors.New("missing required field 'gasPrice' in transaction") } itx.GasPrice = (*big.Int)(dec.GasPrice) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } itx.Value = (*big.Int)(dec.Value) if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } itx.Data = *dec.Input if dec.AccessList != nil { itx.AccessList = *dec.AccessList } // signature R if dec.R == nil { return errors.New("missing required field 'r' in transaction") } itx.R = (*big.Int)(dec.R) // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } itx.S = (*big.Int)(dec.S) // signature V vParity, parityErr := dec.yParityValue() if parityErr != nil { return parityErr } itx.V = vParity if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { sigErr := sanityCheckSignature(itx.V, itx.R, itx.S, false) if sigErr != nil { return sigErr } } case uint64(coretypes.DynamicFeeTxType): var itx DynamicFeeTx inner = &itx if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } itx.ChainID = (*big.Int)(dec.ChainID) if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) if dec.To != nil { itx.To = dec.To } if dec.Gas == nil { return errors.New("missing required field 'gas' for txdata") } itx.Gas = uint64(*dec.Gas) if dec.MaxPriorityFeePerGas == nil { return errors.New("missing required field 'maxPriorityFeePerGas' for txdata") } itx.GasTipCap = (*big.Int)(dec.MaxPriorityFeePerGas) if dec.MaxFeePerGas == nil { return errors.New("missing required field 'maxFeePerGas' for txdata") } itx.GasFeeCap = (*big.Int)(dec.MaxFeePerGas) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } itx.Value = (*big.Int)(dec.Value) if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } itx.Data = *dec.Input if dec.AccessList != nil { itx.AccessList = *dec.AccessList } // signature R if dec.R == nil { return errors.New("missing required field 'r' in transaction") } itx.R = (*big.Int)(dec.R) // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } itx.S = (*big.Int)(dec.S) // signature V vParity, parityErr := dec.yParityValue() if parityErr != nil { return parityErr } itx.V = vParity if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { sigErr := sanityCheckSignature(itx.V, itx.R, itx.S, false) if sigErr != nil { return sigErr } } case uint64(coretypes.BlobTxType): var itx BlobTx inner = &itx if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } var overflow bool itx.ChainID, overflow = uint256.FromBig(dec.ChainID.ToInt()) if overflow { return errors.New("'chainId' value overflows uint256") } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) if dec.To == nil { return errors.New("missing required field 'to' in transaction") } itx.To = *dec.To if dec.Gas == nil { return errors.New("missing required field 'gas' for txdata") } itx.Gas = uint64(*dec.Gas) if dec.MaxPriorityFeePerGas == nil { return errors.New("missing required field 'maxPriorityFeePerGas' for txdata") } itx.GasTipCap = uint256.MustFromBig((*big.Int)(dec.MaxPriorityFeePerGas)) if dec.MaxFeePerGas == nil { return errors.New("missing required field 'maxFeePerGas' for txdata") } itx.GasFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerGas)) if dec.MaxFeePerBlobGas == nil { return errors.New("missing required field 'maxFeePerBlobGas' for txdata") } itx.BlobFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerBlobGas)) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } itx.Value = uint256.MustFromBig((*big.Int)(dec.Value)) if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } itx.Data = *dec.Input if dec.AccessList != nil { itx.AccessList = *dec.AccessList } if dec.BlobVersionedHashes == nil { return errors.New("missing required field 'blobVersionedHashes' in transaction") } itx.BlobHashes = dec.BlobVersionedHashes // signature R if dec.R == nil { return errors.New("missing required field 'r' in transaction") } itx.R, overflow = uint256.FromBig((*big.Int)(dec.R)) if overflow { return errors.New("'r' value overflows uint256") } // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } itx.S, overflow = uint256.FromBig((*big.Int)(dec.S)) if overflow { return errors.New("'s' value overflows uint256") } // signature V vParity, parityErr := dec.yParityValue() if parityErr != nil { return parityErr } itx.V, overflow = uint256.FromBig(vParity) if overflow { return errors.New("'v' value overflows uint256") } if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { sigErr := sanityCheckSignature(vParity, itx.R.ToBig(), itx.S.ToBig(), false) if sigErr != nil { return sigErr } } case uint64(coretypes.SetCodeTxType): var itx SetCodeTx inner = &itx if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } var overflow bool itx.ChainID, overflow = uint256.FromBig(dec.ChainID.ToInt()) if overflow { return errors.New("'chainId' value overflows uint256") } if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) if dec.To == nil { return errors.New("missing required field 'to' in transaction") } itx.To = *dec.To if dec.Gas == nil { return errors.New("missing required field 'gas' for txdata") } itx.Gas = uint64(*dec.Gas) if dec.MaxPriorityFeePerGas == nil { return errors.New("missing required field 'maxPriorityFeePerGas' for txdata") } itx.GasTipCap = uint256.MustFromBig((*big.Int)(dec.MaxPriorityFeePerGas)) if dec.MaxFeePerGas == nil { return errors.New("missing required field 'maxFeePerGas' for txdata") } itx.GasFeeCap = uint256.MustFromBig((*big.Int)(dec.MaxFeePerGas)) if dec.Value == nil { return errors.New("missing required field 'value' in transaction") } itx.Value = uint256.MustFromBig((*big.Int)(dec.Value)) if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } itx.Data = *dec.Input if dec.AccessList != nil { itx.AccessList = *dec.AccessList } if dec.AuthorizationList == nil { return errors.New("missing required field 'authorizationList' in transaction") } itx.AuthList = dec.AuthorizationList // signature R if dec.R == nil { return errors.New("missing required field 'r' in transaction") } itx.R, overflow = uint256.FromBig((*big.Int)(dec.R)) if overflow { return errors.New("'r' value overflows uint256") } // signature S if dec.S == nil { return errors.New("missing required field 's' in transaction") } itx.S, overflow = uint256.FromBig((*big.Int)(dec.S)) if overflow { return errors.New("'s' value overflows uint256") } // signature V vParity, parityErr := dec.yParityValue() if parityErr != nil { return parityErr } itx.V, overflow = uint256.FromBig(vParity) if overflow { return errors.New("'v' value overflows uint256") } if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 { sigErr := sanityCheckSignature(vParity, itx.R.ToBig(), itx.S.ToBig(), false) if sigErr != nil { return sigErr } } case uint64(PoLTxType): var itx PoLTx inner = &itx if dec.ChainID == nil { return errors.New("missing required field 'chainId' in transaction") } itx.ChainID = (*big.Int)(dec.ChainID) if dec.From == nil { return errors.New("missing required field 'from' in transaction") } itx.From = *dec.From if dec.To == nil { return errors.New("missing required field 'to' in transaction") } itx.To = *dec.To if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } itx.Nonce = uint64(*dec.Nonce) if dec.Gas == nil { return errors.New("missing required field 'gas' in transaction") } itx.GasLimit = uint64(*dec.Gas) if dec.GasPrice == nil { return errors.New("missing required field 'gasPrice' in transaction") } itx.GasPrice = (*big.Int)(dec.GasPrice) if dec.Input == nil { return errors.New("missing required field 'input' in transaction") } itx.Data = *dec.Input default: return coretypes.ErrTxTypeNotSupported } // Set the inner transaction. tx.setDecoded(inner) return nil } func sanityCheckSignature(v *big.Int, r *big.Int, s *big.Int, maybeProtected bool) error { if isProtectedV(v) && !maybeProtected { return coretypes.ErrUnexpectedProtection } var plainV uint64 switch { case isProtectedV(v): chainID := deriveChainID(v).Uint64() plainV = v.Uint64() - replayProtectionBase - chainIDDivisor*chainID case maybeProtected: // Only EIP-155 signatures can be optionally protected. Since // we determined this v value is not protected, it must be a // raw 27 or 28. plainV = v.Uint64() - legacyVValue27 default: // If the signature is not optionally protected, we assume it // must already be equal to the recovery id. plainV = v.Uint64() } var recoveryID byte switch plainV { case 0: recoveryID = 0 case 1: recoveryID = 1 default: return coretypes.ErrInvalidSig } if !crypto.ValidateSignatureValues(recoveryID, r, s, false) { return coretypes.ErrInvalidSig } return nil } func isProtectedV(v *big.Int) bool { if v.BitLen() <= recoveryIDByteLen { val := v.Uint64() return val != legacyVValue27 && val != legacyVValue28 && val != 1 && val != 0 } // Anything not 27 or 28 is considered protected. return true } // deriveChainID derives the chain ID from a signature v value. func deriveChainID(v *big.Int) *big.Int { if v.BitLen() <= replayProtectionBitLen { val := v.Uint64() if val == legacyVValue27 || val == legacyVValue28 { return new(big.Int) } return new(big.Int).SetUint64((val - replayProtectionBase) / chainIDDivisor) } vCopy := new(big.Int).Sub(v, big.NewInt(replayProtectionBase)) return vCopy.Rsh(vCopy, 1) } ================================================ FILE: gethlib/types/tx_types.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "bytes" "errors" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" coretypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/rlp" "github.com/holiman/uint256" ) // BRIP-0004 PoL transaction type. const PoLTxType = 0x7E // AccessListTx is the data of EIP-2930 access list transactions. type AccessListTx struct { ChainID *big.Int // destination chain ID Nonce uint64 // nonce of sender account GasPrice *big.Int // wei per gas Gas uint64 // gas limit To *common.Address `rlp:"nil"` // nil means contract creation Value *big.Int // wei amount Data []byte // contract invocation input data AccessList coretypes.AccessList // EIP-2930 access list V, R, S *big.Int // signature values } func (tx *AccessListTx) txType() byte { return coretypes.AccessListTxType } func (tx *AccessListTx) encode(b *bytes.Buffer) error { return rlp.Encode(b, tx) } func (tx *AccessListTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } // BlobTx represents an EIP-4844 transaction. type BlobTx struct { ChainID *uint256.Int Nonce uint64 GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas GasFeeCap *uint256.Int // a.k.a. maxFeePerGas Gas uint64 To common.Address Value *uint256.Int Data []byte AccessList coretypes.AccessList BlobFeeCap *uint256.Int // a.k.a. maxFeePerBlobGas BlobHashes []common.Hash // A blob transaction can optionally contain blobs. This field must be set when BlobTx // is used to create a transaction for signing. Sidecar *coretypes.BlobTxSidecar `rlp:"-"` // Signature values V *uint256.Int R *uint256.Int S *uint256.Int } func (tx *BlobTx) txType() byte { return coretypes.BlobTxType } func (tx *BlobTx) encode(b *bytes.Buffer) error { switch { case tx.Sidecar == nil: return rlp.Encode(b, tx) case tx.Sidecar.Version == coretypes.BlobSidecarVersion0: return rlp.Encode(b, &blobTxWithBlobsV0{ BlobTx: tx, Blobs: tx.Sidecar.Blobs, Commitments: tx.Sidecar.Commitments, Proofs: tx.Sidecar.Proofs, }) case tx.Sidecar.Version == coretypes.BlobSidecarVersion1: return rlp.Encode(b, &blobTxWithBlobsV1{ BlobTx: tx, Version: tx.Sidecar.Version, Blobs: tx.Sidecar.Blobs, Commitments: tx.Sidecar.Commitments, Proofs: tx.Sidecar.Proofs, }) default: return errors.New("unsupported sidecar version") } } func (tx *BlobTx) decode(input []byte) error { // Here we need to support two outer formats: the network protocol encoding of the tx // (with blobs) or the canonical encoding without blobs. // // The canonical encoding is just a list of fields: // // [chainID, nonce, ...] // // The network encoding is a list where the first element is the tx in the canonical encoding, // and the remaining elements are the 'sidecar': // // [[chainID, nonce, ...], ...] // // The two outer encodings can be distinguished by checking whether the first element // of the input list is itself a list. If it's the canonical encoding, the first // element is the chainID, which is a number. firstElem, _, err := rlp.SplitList(input) if err != nil { return err } firstElemKind, _, secondElem, err := rlp.Split(firstElem) if err != nil { return err } if firstElemKind != rlp.List { // Blob tx without blobs. return rlp.DecodeBytes(input, tx) } // Now we know it's the network encoding with the blob sidecar. Here we again need to // support multiple encodings: legacy sidecars (v0) with a blob proof, and versioned // sidecars. // // The legacy encoding is: // // [tx, blobs, commitments, proofs] // // The versioned encoding is: // // [tx, version, blobs, ...] // // We can tell the two apart by checking whether the second element is the version byte. // For legacy sidecar the second element is a list of blobs. secondElemKind, _, _, err := rlp.Split(secondElem) if err != nil { return err } var payload blobTxWithBlobs if secondElemKind == rlp.List { // No version byte: blob sidecar v0. payload = new(blobTxWithBlobsV0) } else { // It has a version byte. Decode as v1, version is checked by assign() payload = new(blobTxWithBlobsV1) } err = rlp.DecodeBytes(input, payload) if err != nil { return err } sc := new(coretypes.BlobTxSidecar) err = payload.assign(sc) if err != nil { return err } *tx = *payload.tx() tx.Sidecar = sc return nil } // blobTxWithBlobs represents blob tx with its corresponding sidecar. // This is an interface because sidecars are versioned. type blobTxWithBlobs interface { tx() *BlobTx assign(*coretypes.BlobTxSidecar) error } type blobTxWithBlobsV0 struct { BlobTx *BlobTx Blobs []kzg4844.Blob Commitments []kzg4844.Commitment Proofs []kzg4844.Proof } type blobTxWithBlobsV1 struct { BlobTx *BlobTx Version byte Blobs []kzg4844.Blob Commitments []kzg4844.Commitment Proofs []kzg4844.Proof } func (btx *blobTxWithBlobsV0) tx() *BlobTx { return btx.BlobTx } func (btx *blobTxWithBlobsV0) assign(sc *coretypes.BlobTxSidecar) error { sc.Version = coretypes.BlobSidecarVersion0 sc.Blobs = btx.Blobs sc.Commitments = btx.Commitments sc.Proofs = btx.Proofs return nil } func (btx *blobTxWithBlobsV1) tx() *BlobTx { return btx.BlobTx } func (btx *blobTxWithBlobsV1) assign(sc *coretypes.BlobTxSidecar) error { if btx.Version != coretypes.BlobSidecarVersion1 { return fmt.Errorf("unsupported blob tx version %d", btx.Version) } sc.Version = coretypes.BlobSidecarVersion1 sc.Blobs = btx.Blobs sc.Commitments = btx.Commitments sc.Proofs = btx.Proofs return nil } // DynamicFeeTx represents an EIP-1559 transaction. type DynamicFeeTx struct { ChainID *big.Int Nonce uint64 GasTipCap *big.Int // a.k.a. maxPriorityFeePerGas GasFeeCap *big.Int // a.k.a. maxFeePerGas Gas uint64 To *common.Address `rlp:"nil"` // nil means contract creation Value *big.Int Data []byte AccessList coretypes.AccessList // Signature values V *big.Int R *big.Int S *big.Int } func (tx *DynamicFeeTx) txType() byte { return coretypes.DynamicFeeTxType } func (tx *DynamicFeeTx) encode(b *bytes.Buffer) error { return rlp.Encode(b, tx) } func (tx *DynamicFeeTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } // LegacyTx is the transaction data of the original Ethereum transactions. type LegacyTx struct { Nonce uint64 // nonce of sender account GasPrice *big.Int // wei per gas Gas uint64 // gas limit To *common.Address `rlp:"nil"` // nil means contract creation Value *big.Int // wei amount Data []byte // contract invocation input data V, R, S *big.Int // signature values } func (tx *LegacyTx) txType() byte { return coretypes.LegacyTxType } func (tx *LegacyTx) encode(*bytes.Buffer) error { panic("encode called on LegacyTx") } func (tx *LegacyTx) decode([]byte) error { panic("decode called on LegacyTx)") } // PoLTx represents an BRIP-0004 transaction. No gas is consumed for execution. type PoLTx struct { ChainID *big.Int From common.Address // system address To common.Address // address of the PoL Distributor contract Nonce uint64 // block number distributing for GasLimit uint64 // artificial gas limit for the PoL tx, not consumed against the block gas limit GasPrice *big.Int // gas price is set to the baseFee to make the tx valid for EIP-1559 rules Data []byte // encodes the pubkey distributing for } func (*PoLTx) txType() byte { return PoLTxType } func (tx *PoLTx) encode(b *bytes.Buffer) error { return rlp.Encode(b, tx) } func (tx *PoLTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } // SetCodeTx implements the EIP-7702 transaction type which temporarily installs // the code at the signer's address. type SetCodeTx struct { ChainID *uint256.Int Nonce uint64 GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas GasFeeCap *uint256.Int // a.k.a. maxFeePerGas Gas uint64 To common.Address Value *uint256.Int Data []byte AccessList coretypes.AccessList AuthList []coretypes.SetCodeAuthorization // Signature values V *uint256.Int R *uint256.Int S *uint256.Int } func (tx *SetCodeTx) txType() byte { return coretypes.SetCodeTxType } func (tx *SetCodeTx) encode(b *bytes.Buffer) error { return rlp.Encode(b, tx) } func (tx *SetCodeTx) decode(input []byte) error { return rlp.DecodeBytes(input, tx) } ================================================ FILE: gethlib/types/utils.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/ethereum/go-ethereum/common" coretypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" ) func CalcUncleHash(uncles []*Header) common.Hash { if len(uncles) == 0 { return coretypes.EmptyUncleHash } return rlpHash(uncles) } // rlpHash encodes x and hashes the encoded bytes. func rlpHash(x interface{}) common.Hash { var h common.Hash sha, ok := hasherPool.Get().(crypto.KeccakState) if !ok { sha = crypto.NewKeccakState() } defer hasherPool.Put(sha) sha.Reset() _ = rlp.Encode(sha, x) _, _ = sha.Read(h[:]) return h } // prefixedRlpHash writes the prefix into the hasher before rlp-encoding x. // It's used for typed transactions. func prefixedRlpHash(prefix byte, x interface{}) common.Hash { var h common.Hash sha, ok := hasherPool.Get().(crypto.KeccakState) if !ok { sha = crypto.NewKeccakState() } defer hasherPool.Put(sha) sha.Reset() _, _ = sha.Write([]byte{prefix}) _ = rlp.Encode(sha, x) _, _ = sha.Read(h[:]) return h } ================================================ FILE: go.mod ================================================ module github.com/berachain/beacon-kit go 1.26.2 replace ( github.com/cometbft/cometbft => github.com/berachain/cometbft v1.0.1-0.20260417142533-880521c815b6 github.com/cometbft/cometbft/api => github.com/berachain/cometbft/api v1.0.1-0.20260417142533-880521c815b6 github.com/cosmos/cosmos-sdk => github.com/cosmos/cosmos-sdk v0.52.0-rc.1 github.com/karalabe/ssz => github.com/berachain/karalabe-ssz v0.3.0-alpha.0 ) require ( cosmossdk.io/collections v1.3.1 cosmossdk.io/core v1.0.0 cosmossdk.io/depinject v1.2.1 cosmossdk.io/errors v1.0.2 cosmossdk.io/log v1.6.1 cosmossdk.io/math v1.5.3 cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43 github.com/cenkalti/backoff/v5 v5.0.3 github.com/cometbft/cometbft v1.0.1-0.20241220100824-07c737de00ff github.com/cometbft/cometbft/api v1.0.1-0.20241220100824-07c737de00ff github.com/cosmos/cosmos-db v1.1.3 github.com/cosmos/cosmos-sdk v0.53.0 github.com/cosmos/go-bip39 v1.0.0 github.com/crate-crypto/go-kzg-4844 v1.1.0 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/go-faster/xor v1.0.0 github.com/go-playground/validator/v10 v10.28.0 github.com/golang-jwt/jwt/v5 v5.3.0 github.com/hashicorp/go-metrics v0.5.4 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/holiman/uint256 v1.3.2 github.com/karalabe/ssz v0.2.1-0.20240724074312-3d1ff7a6f7c4 github.com/labstack/echo/v4 v4.13.4 github.com/minio/sha256-simd v1.0.1 github.com/mitchellh/mapstructure v1.5.0 github.com/ory/dockertest v3.3.5+incompatible github.com/phuslu/log v1.0.120 github.com/pkg/errors v0.9.1 github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b github.com/prysmaticlabs/prysm/v5 v5.3.0 github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 github.com/spf13/afero v1.15.0 github.com/spf13/cast v1.10.0 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.21.0 github.com/umbracle/fastrlp v0.1.0 go.uber.org/automaxprocs v1.6.0 golang.org/x/crypto v0.49.0 golang.org/x/sync v0.20.0 sigs.k8s.io/yaml v1.6.0 ) // build/test dependencies require ( github.com/attestantio/go-eth2-client v0.27.2 github.com/cosmos/ics23/go v0.11.0 github.com/ethereum/go-ethereum v1.17.0 github.com/ferranbt/fastssz v0.1.5-0.20240903094032-455b54c08c81 github.com/kurtosis-tech/kurtosis/api/golang v1.16.6 github.com/protolambda/zrnt v0.34.1 github.com/protolambda/ztyp v0.2.2 github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.11.1 ) require ( buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.0-20241120201313-68e42a58b301.1 // indirect buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.0-20240130113600-88ef6483f90f.1 // indirect cosmossdk.io/api v0.8.0-rc.3 // indirect cosmossdk.io/core/testing v0.0.1 // indirect cosmossdk.io/schema v1.1.0 // indirect cosmossdk.io/x/bank v0.0.0-20241218110910-47409028a73d // indirect cosmossdk.io/x/staking v0.0.0-20241218110910-47409028a73d // indirect cosmossdk.io/x/tx v1.0.0-alpha.3 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/DataDog/datadog-go v4.8.3+incompatible // indirect github.com/DataDog/zstd v1.5.7 // indirect github.com/Masterminds/semver/v3 v3.3.1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect github.com/VictoriaMetrics/fastcache v1.13.0 // indirect github.com/adrg/xdg v0.4.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.2.0 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/bufbuild/protocompile v0.14.1 // indirect github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/sonic v1.15.0 // indirect github.com/bytedance/sonic/loader v0.5.0 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect github.com/cockroachdb/errors v1.12.0 // indirect github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 // indirect github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 // indirect github.com/cockroachdb/pebble v1.1.5 // indirect github.com/cockroachdb/redact v1.1.6 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cometbft/cometbft-db v1.0.4 // indirect github.com/consensys/gnark-crypto v0.18.1 // indirect github.com/containerd/continuity v0.4.4 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/gogoproto v1.7.0 // indirect github.com/cosmos/iavl v1.3.4 // indirect github.com/cosmos/ledger-cosmos-go v0.13.3 // indirect github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect github.com/danieljoos/wincred v1.2.1 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/dgraph-io/badger/v4 v4.5.1 // indirect github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.7.0 // indirect github.com/emicklei/dot v1.6.4 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.10 // indirect github.com/getsentry/sentry-go v0.33.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/go-yaml/yaml v2.1.0+incompatible // indirect github.com/goccy/go-yaml v1.9.2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/flatbuffers v25.1.24+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-plugin v1.6.2 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/yamux v0.1.2 // indirect github.com/hdevalence/ed25519consensus v0.2.0 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/huandu/go-clone v1.6.0 // indirect github.com/huandu/skiplist v1.2.1 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/kilic/bls12-381 v0.1.0 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/kurtosis-tech/kurtosis-portal/api/golang v0.0.0-20230818182330-1a86869414d2 // indirect github.com/kurtosis-tech/kurtosis/contexts-config-store v0.0.0-20230818184218-f4e3e773463b // indirect github.com/kurtosis-tech/kurtosis/grpc-file-transfer/golang v0.0.0-20230803130419-099ee7a4e3dc // indirect github.com/kurtosis-tech/kurtosis/path-compression v0.0.0-20240307154559-64d2929cd265 // indirect github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/linxGnu/grocksdb v1.9.8 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/mholt/archiver v3.1.1+incompatible // indirect github.com/minio/highwayhash v1.0.3 // indirect github.com/moby/sys/user v0.3.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mtibben/percent v0.2.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nwaples/rardecode v1.1.3 // indirect github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect github.com/oklog/run v1.1.0 // indirect github.com/onsi/gomega v1.34.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/opencontainers/runc v1.2.8 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pk910/dynamic-ssz v0.0.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.62.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/protolambda/bls12-381-util v0.1.0 // indirect github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 // indirect github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 // indirect github.com/r3labs/sse/v2 v2.10.0 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/cors v1.11.1 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sasha-s/go-deadlock v0.3.5 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect github.com/tidwall/btree v1.7.0 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.8.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ulikunitz/xz v0.5.14 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect github.com/zondax/hid v0.9.2 // indirect github.com/zondax/ledger-go v0.14.3 // indirect gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b // indirect gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 // indirect go.etcd.io/bbolt v1.4.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/otel v1.39.0 // indirect go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/trace v1.39.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.17.0 // indirect golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect golang.org/x/net v0.52.0 // indirect golang.org/x/sys v0.42.0 // indirect golang.org/x/term v0.41.0 // indirect golang.org/x/text v0.35.0 // indirect golang.org/x/time v0.11.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect google.golang.org/grpc v1.79.3 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/Knetic/govaluate.v3 v3.0.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.2 // indirect pgregory.net/rapid v1.2.0 // indirect ) ================================================ FILE: go.sum ================================================ buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.0-20241120201313-68e42a58b301.1 h1:LBP+N3ehp1hseHYlIIHlU0gMM3aGYDcgx/H//Pk12ko= buf.build/gen/go/cometbft/cometbft/protocolbuffers/go v1.36.0-20241120201313-68e42a58b301.1/go.mod h1:pab5p7+q6IAI+R+Z2MQ+hP7ZV+FP2mcbucv6xs5WFPk= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.0-20240130113600-88ef6483f90f.1 h1:5wJBiYyPUS2xpqLJKm7ZEKx1VhesPOXXx5y+JxgVSX4= buf.build/gen/go/cosmos/gogo-proto/protocolbuffers/go v1.36.0-20240130113600-88ef6483f90f.1/go.mod h1:VItWFs9dzQsqOin45pYbA4O/SRdqMPDs4XPZBHL+u2w= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cosmossdk.io/api v0.8.0-rc.3 h1:BNVMqBO7jO20fQCLKzAYLI9RPTq9bVn30ncq9vF8SBk= cosmossdk.io/api v0.8.0-rc.3/go.mod h1:1hADc5N9rDJ4RTH7z3sp6+PXI+shznzk0Frf0/k3ilE= cosmossdk.io/collections v1.3.1 h1:09e+DUId2brWsNOQ4nrk+bprVmMUaDH9xvtZkeqIjVw= cosmossdk.io/collections v1.3.1/go.mod h1:ynvkP0r5ruAjbmedE+vQ07MT6OtJ0ZIDKrtJHK7Q/4c= cosmossdk.io/core v1.0.0 h1:e7XBbISOytLBOXMVwpRPixThXqEkeLGlg8no/qpgS8U= cosmossdk.io/core v1.0.0/go.mod h1:mKIp3RkoEmtqdEdFHxHwWAULRe+79gfdOvmArrLDbDc= cosmossdk.io/core/testing v0.0.1 h1:gYCTaftcRrz+HoNXmK7r9KgbG1jgBJ8pNzm/Pa/erFQ= cosmossdk.io/core/testing v0.0.1/go.mod h1:2VDNz/25qtxgPa0+j8LW5e8Ev/xObqoJA7QuJS9/wIQ= cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= cosmossdk.io/schema v1.1.0/go.mod h1:Gb7pqO+tpR+jLW5qDcNOSv0KtppYs7881kfzakguhhI= cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43 h1:glZ6MpmD+5AhwJYV4jzx+rn7cgUB2owHgk9o+93luz0= cosmossdk.io/store v1.10.0-rc.1.0.20241218084712-ca559989da43/go.mod h1:XCWpgfueHSBY+B7Cf2Aq/CcsU+6XoFH+EmseCKglFrU= cosmossdk.io/x/bank v0.0.0-20241218110910-47409028a73d h1:8Sw9mmz+P/H0iURZkRHKmpkmr9Lm3eGM2yRZveU2GWs= cosmossdk.io/x/bank v0.0.0-20241218110910-47409028a73d/go.mod h1:C5yLe3vDDDHcWMSfa1lfgglczjjMGfOc4nYDmk69U2w= cosmossdk.io/x/staking v0.0.0-20241218110910-47409028a73d h1:Ey5BddfuPEQACiDgeb9SqvHr533RH7rd2GDNIgV45hk= cosmossdk.io/x/staking v0.0.0-20241218110910-47409028a73d/go.mod h1:ZvgV4cHXyDsKYdDDz5srMizpi9ylVI1wuvgmj53ug18= cosmossdk.io/x/tx v1.0.0-alpha.3 h1:+55/JFH5QRqnFhOI2heH3DKsaNL0RpXcJOQNzUvHiaQ= cosmossdk.io/x/tx v1.0.0-alpha.3/go.mod h1:h4pQ/j6Gfu8goB1R3Jbl4qY4RjYVNAsoylcleTXdSRg= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMbk2FiG/kXiLl8BRyzTWDw7gX/Hz7Dd5eDMs= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs= github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v4.8.3+incompatible h1:fNGaYSuObuQb5nzeTQqowRAd9bpDIRRV4/gUtIBjh8Q= github.com/DataDog/datadog-go v4.8.3+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.5.7 h1:ybO8RBeh29qrxIhCA9E8gKY6xfONU9T6G6aP9DTKfLE= github.com/DataDog/zstd v1.5.7/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4= github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= github.com/adlio/schema v1.3.6 h1:k1/zc2jNfeiZBA5aFTRy37jlBIuCkXCm0XmvpzCKI9I= github.com/adlio/schema v1.3.6/go.mod h1:qkxwLgPBd1FgLRHYVCmQT/rrBr3JH38J9LjmVzWNudg= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-metrics v0.4.1/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/attestantio/go-eth2-client v0.27.2 h1:VjA9R39ovy8ryb7IpFfD5eLYBg/20biztxh6fKZ7/K0= github.com/attestantio/go-eth2-client v0.27.2/go.mod h1:i56XBegxVt7wXupnLBOj9IyGwy5cqaoTsCSKlwTubEU= github.com/bazelbuild/rules_go v0.23.2 h1:Wxu7JjqnF78cKZbsBsARLSXx/jlGaSLCnUV3mTlyHvM= github.com/bazelbuild/rules_go v0.23.2/go.mod h1:MC23Dc/wkXEyk3Wpq6lCqz0ZAYOZDw2DR5y3N1q2i7M= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/berachain/cometbft v1.0.1-0.20260417142533-880521c815b6 h1:pCfZDheMbkXRE+VbERz/bPFibp96Yd5V3RVDJLLib2A= github.com/berachain/cometbft v1.0.1-0.20260417142533-880521c815b6/go.mod h1:AB3j5W0TQmQSuwRdzWvIBQPAKquFo7VnckwETlAsuwk= github.com/berachain/cometbft/api v1.0.1-0.20260417142533-880521c815b6 h1:HS1NYR8xeqNR9ABrfvS84clBgujpXOUunGKEaKP1l+k= github.com/berachain/cometbft/api v1.0.1-0.20260417142533-880521c815b6/go.mod h1:QaK8NCB4rHDs0MdS+L+QOQsL4UM3YJ9OMCNrH+CGdA0= github.com/berachain/karalabe-ssz v0.3.0-alpha.0 h1:SVMU5PSuMB2fgmFTf1rSBY9rEHpQv24DJcqxSrD7jf8= github.com/berachain/karalabe-ssz v0.3.0-alpha.0/go.mod h1:7BZG/jckt43eKw7sl/AF6gTcL0oxgFPme39m54v8rDI= github.com/bgentry/speakeasy v0.2.0 h1:tgObeVOf8WAvtuAX6DhJ4xks4CFNwPDZiqzGqIHE51E= github.com/bgentry/speakeasy v0.2.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/btcsuite/btcd/btcec/v2 v2.3.4 h1:3EJjcN70HCu/mwqlUsGK8GcNVyLVxFDlWurTXGPFfiQ= github.com/btcsuite/btcd/btcec/v2 v2.3.4/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04= github.com/btcsuite/btcd/btcutil v1.1.6 h1:zFL2+c3Lb9gEgqKNzowKUPQNb8jV7v5Oaodi/AYFd6c= github.com/btcsuite/btcd/btcutil v1.1.6/go.mod h1:9dFymx8HpuLqBnsPELrImQeTQfKBQqzqGbbV3jK55aE= github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE= github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k= github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE= github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/cp v1.1.1 h1:nCb6ZLdB7NRaqsm91JtQTAme2SKJzXVsdPIPkyJr1MU= github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f h1:otljaYPt5hWxV3MUfO5dFPFiOXg9CyG5/kCfayTqsJ4= github.com/cockroachdb/datadriven v1.0.3-0.20230413201302-be42291fc80f/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU= github.com/cockroachdb/errors v1.12.0 h1:d7oCs6vuIMUQRVbi6jWWWEJZahLCfJpnJSVobd1/sUo= github.com/cockroachdb/errors v1.12.0/go.mod h1:SvzfYNNBshAVbZ8wzNc/UPK3w1vf0dKDUP41ucAIf7g= github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0 h1:pU88SPhIFid6/k0egdR5V6eALQYq2qbSmukrkgIh/0A= github.com/cockroachdb/fifo v0.0.0-20240816210425-c5d0cb0b6fc0/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506 h1:ASDL+UJcILMqgNeV5jiqR4j+sTuvQNHdf2chuKj1M5k= github.com/cockroachdb/logtags v0.0.0-20241215232642-bb51bb14a506/go.mod h1:Mw7HqKr2kdtu6aYGn3tPmAftiP3QPX63LdK/zcariIo= github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= github.com/cockroachdb/redact v1.1.6 h1:zXJBwDZ84xJNlHl1rMyCojqyIxv+7YUpQiJLQ7n4314= github.com/cockroachdb/redact v1.1.6/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/cometbft/cometbft-db v1.0.4 h1:cezb8yx/ZWcF124wqUtAFjAuDksS1y1yXedvtprUFxs= github.com/cometbft/cometbft-db v1.0.4/go.mod h1:M+BtHAGU2XLrpUxo3Nn1nOCcnVCiLM9yx5OuT0u5SCA= github.com/consensys/gnark-crypto v0.18.1 h1:RyLV6UhPRoYYzaFnPQA4qK3DyuDgkTgskDdoGqFt3fI= github.com/consensys/gnark-crypto v0.18.1/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII= github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= github.com/cosmos/cosmos-db v1.1.3 h1:7QNT77+vkefostcKkhrzDK9uoIEryzFrU9eoMeaQOPY= github.com/cosmos/cosmos-db v1.1.3/go.mod h1:kN+wGsnwUJZYn8Sy5Q2O0vCYA99MJllkKASbs6Unb9U= github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= github.com/cosmos/cosmos-sdk v0.52.0-rc.1 h1:HgHOUYbxvjvyiX5CQF4eLT0u1wvjxajwgClOGzAmNoQ= github.com/cosmos/cosmos-sdk v0.52.0-rc.1/go.mod h1:2Z6V16EhPG1NI6Q+b9Xue7dgabx76JQpUtlcCnYbI90= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ4GUkT+tbFI= github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.7.0 h1:79USr0oyXAbxg3rspGh/m4SWNyoz/GLaAh0QlCe2fro= github.com/cosmos/gogoproto v1.7.0/go.mod h1:yWChEv5IUEYURQasfyBW5ffkMHR/90hiHgbNgrtp4j0= github.com/cosmos/iavl v1.3.4 h1:A0RUAms7TZ0L6EFrrBIPg4Dy7qD9vvD5lJKUxEXURLM= github.com/cosmos/iavl v1.3.4/go.mod h1:T6SfBcyhulVIY2G/ZtAtQm/QiJvsuhIos52V4dWYk88= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= github.com/cosmos/ledger-cosmos-go v0.13.3/go.mod h1:HENcEP+VtahZFw38HZ3+LS3Iv5XV6svsnkk9vdJtLr8= github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4= github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U= github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/deepmap/oapi-codegen v1.8.2 h1:SegyeYGcdi0jLLrpbCMoJxnUUn8GBXHsvr4rbzjuhfU= github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw= github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56HLps= github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA= github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/emicklei/dot v1.6.4 h1:cG9ycT67d9Yw22G+mAb4XiuUz6E6H1S0zePp/5Cwe/c= github.com/emicklei/dot v1.6.4/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= github.com/ethereum/go-ethereum v1.17.0 h1:2D+1Fe23CwZ5tQoAS5DfwKFNI1HGcTwi65/kRlAVxes= github.com/ethereum/go-ethereum v1.17.0/go.mod h1:2W3msvdosS/MCWytpqTcqgFiRYbTH59FxDJzqah120o= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/ferranbt/fastssz v0.1.5-0.20240903094032-455b54c08c81 h1:SNHNj7UyVnQV3AAi1LweOKnU6+OJ2CmxgaHpRmU7+mc= github.com/ferranbt/fastssz v0.1.5-0.20240903094032-455b54c08c81/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 h1:f6D9Hr8xV8uYKlyuj8XIruxlh9WjVjdh1gIicAS7ays= github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= github.com/getsentry/sentry-go v0.33.0 h1:YWyDii0KGVov3xOaamOnF0mjOrqSjBqwv48UEzn7QFg= github.com/getsentry/sentry-go v0.33.0/go.mod h1:C55omcY9ChRQIUcVcGcs+Zdy4ZpQGvNJ7JYHIoSWOtE= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-faster/xor v1.0.0 h1:2o8vTOgErSGHP3/7XwA5ib1FTtUsNtwCoLLBjl31X38= github.com/go-faster/xor v1.0.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o= github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/goccy/go-yaml v1.9.2 h1:2Njwzw+0+pjU2gb805ZC1B/uBuAs2VcZ3K+ZgHwDs7w= github.com/goccy/go-yaml v1.9.2/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/googleapis v1.4.1-0.20201022092350-68b0159b7869/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c= github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0= github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v25.1.24+incompatible h1:4wPqL3K7GzBd1CwyhSd3usxLKOaJN/AC6puCca6Jm7o= github.com/google/flatbuffers v25.1.24+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/orderedcode v0.0.1 h1:UzfcAexk9Vhv8+9pNOgRu41f16lHq725vPwnSeiG/Us= github.com/google/orderedcode v0.0.1/go.mod h1:iVyU4/qPKHY5h/wSd6rZZCDcLJNxiWO6dvsYES2Sb20= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gotestyourself/gotestyourself v2.2.0+incompatible h1:AQwinXlbQR2HvPjQZOmDhRqsv5mZf+Jb1RnSLxcqZcI= github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac= github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc= github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og= github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU= github.com/graph-gophers/graphql-go v1.3.0 h1:Eb9x/q6MFpCLz7jBCiP/WTxjSDrYLR1QY41SORZyNJ0= github.com/graph-gophers/graphql-go v1.3.0/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-metrics v0.5.4 h1:8mmPiIJkTPPEbAiV97IxdAGNdRdaWwVap1BU6elejKY= github.com/hashicorp/go-metrics v0.5.4/go.mod h1:CG5yz4NZ/AI/aQt9Ucm/vdBnbh7fvmv4lxZ350i+QQI= github.com/hashicorp/go-plugin v1.6.2 h1:zdGAEd0V1lCaU0u+MxWQhtSDQmahpkwOun8U8EiRVog= github.com/hashicorp/go-plugin v1.6.2/go.mod h1:CkgLQ5CZqNmdL9U9JzM532t8ZiYQ35+pj3b1FD37R0Q= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/hdevalence/ed25519consensus v0.2.0 h1:37ICyZqdyj0lAZ8P4D1d1id3HqbbG1N3iBb1Tb4rdcU= github.com/hdevalence/ed25519consensus v0.2.0/go.mod h1:w3BHWjwJbFU29IRHL1Iqkw3sus+7FctEyM4RqDxYNzo= github.com/herumi/bls-eth-go-binary v1.31.0 h1:9eeW3EA4epCb7FIHt2luENpAW69MvKGL5jieHlBiP+w= github.com/herumi/bls-eth-go-binary v1.31.0/go.mod h1:luAnRm3OsMQeokhGzpYmc0ZKwawY7o87PUEP11Z7r7U= github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c= github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U= github.com/huandu/go-clone v1.6.0 h1:HMo5uvg4wgfiy5FoGOqlFLQED/VGRm2D9Pi8g1FXPGc= github.com/huandu/go-clone v1.6.0/go.mod h1:ReGivhG6op3GYr+UY3lS6mxjKp7MIGTknuU5TbTVaXE= github.com/huandu/go-clone/generic v1.6.0 h1:Wgmt/fUZ28r16F2Y3APotFD59sHk1p78K0XLdbUYN5U= github.com/huandu/go-clone/generic v1.6.0/go.mod h1:xgd9ZebcMsBWWcBx5mVMCoqMX24gLWr5lQicr+nVXNs= github.com/huandu/skiplist v1.2.1 h1:dTi93MgjwErA/8idWTzIw4Y1kZsMWx35fmI2c8Rij7w= github.com/huandu/skiplist v1.2.1/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w= github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb-client-go/v2 v2.4.0 h1:HGBfZYStlx3Kqvsv1h2pJixbCl/jhnFtxpKFAv9Tu5k= github.com/influxdata/influxdb-client-go/v2 v2.4.0/go.mod h1:vLNHdxTJkIf2mSLvGrpj8TCcISApPoXkaxP8g9uRlW8= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c h1:qSHzRbhzK8RdXOsAdfDgO49TtqC1oZ+acxPrkfTxcCs= github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 h1:vilfsDSy7TDxedi9gyBkMvAirat/oRcL0lFdJBf6tdM= github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097/go.mod h1:xaLFMmpvUxqXtVkUJfg9QmT88cDaCJ3ZKgdZ78oO8Qo= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kilic/bls12-381 v0.1.0 h1:encrdjqKMEvabVQ7qYOKu1OvhqpK4s47wDYtNiPtlp4= github.com/kilic/bls12-381 v0.1.0/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kurtosis-tech/kurtosis-portal/api/golang v0.0.0-20230818182330-1a86869414d2 h1:izciXrFyFR+ihJ7nLTOkoIX5GzBPIp8gVKlw94gIc98= github.com/kurtosis-tech/kurtosis-portal/api/golang v0.0.0-20230818182330-1a86869414d2/go.mod h1:bWSMQK3WHVTGHX9CjxPAb/LtzcmfOxID2wdzakSWQxo= github.com/kurtosis-tech/kurtosis/api/golang v1.16.6 h1:uy03mqQ5eCFtOtBKDsOpUk8fw5SJ2v+VBstBiVQ55D8= github.com/kurtosis-tech/kurtosis/api/golang v1.16.6/go.mod h1:7jsreUn/zOtlJbNJcGPfjXsh7GWMgDd08Vn4ypUN78o= github.com/kurtosis-tech/kurtosis/contexts-config-store v0.0.0-20230818184218-f4e3e773463b h1:hMoIM99QKcYQqsnK4AF7Lovi9ZD9ac6lZLZ5D/jx2x8= github.com/kurtosis-tech/kurtosis/contexts-config-store v0.0.0-20230818184218-f4e3e773463b/go.mod h1:4pFdrRwDz5R+Fov2ZuTaPhAVgjA2jhGh1Izf832sX7A= github.com/kurtosis-tech/kurtosis/grpc-file-transfer/golang v0.0.0-20230803130419-099ee7a4e3dc h1:7IlEpSehmWcNXOFpNP24Cu5HQI3af7GCBQw//m+LnvQ= github.com/kurtosis-tech/kurtosis/grpc-file-transfer/golang v0.0.0-20230803130419-099ee7a4e3dc/go.mod h1:TOWMQgvAJH/NiWWERGXg/plT9lS7aFcXFxCa0M5sfHo= github.com/kurtosis-tech/kurtosis/path-compression v0.0.0-20240307154559-64d2929cd265 h1:uSDftcGStwuAjHv8fV2TleNCKSWPvUKe7EaplFG3yBI= github.com/kurtosis-tech/kurtosis/path-compression v0.0.0-20240307154559-64d2929cd265/go.mod h1:aDMrPeS7Gii8W6SDKSKyrBNgEQAUYidriyeKGf+Ml3I= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409 h1:YQTATifMUwZEtZYb0LVA7DK2pj8s71iY8rzweuUQ5+g= github.com/kurtosis-tech/stacktrace v0.0.0-20211028211901-1c67a77b5409/go.mod h1:y5weVs5d9wXXHcDA1awRxkIhhHC1xxYJN8a7aXnE6S8= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA= github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/linxGnu/grocksdb v1.9.8 h1:vOIKv9/+HKiqJAElJIEYv3ZLcihRxyP7Suu/Mu8Dxjs= github.com/linxGnu/grocksdb v1.9.8/go.mod h1:C3CNe9UYc9hlEM2pC82AqiGS3LRW537u9LFV4wIZuHk= github.com/magiconair/properties v1.8.9 h1:nWcCbLq1N2v/cpNsy5WvQ37Fb+YElfq20WJ/a8RkpQM= github.com/magiconair/properties v1.8.9/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU= github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU= github.com/minio/highwayhash v1.0.3 h1:kbnuUMoHYyVl7szWjSxJnxw11k2U709jqFPPmIUyD6Q= github.com/minio/highwayhash v1.0.3/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a h1:dlRvE5fWabOchtH7znfiFCcOvmIYgOeAS5ifBXBlh9Q= github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a/go.mod h1:hVoHR2EVESiICEMbg137etN/Lx+lSrHPTD39Z/uE+2s= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8= github.com/onsi/gomega v1.34.2/go.mod h1:v1xfxRgk0KIsG+QOdm7p8UosrOzPYRo60fd3B/1Dukc= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opencontainers/runc v1.2.8 h1:RnEICeDReapbZ5lZEgHvj7E9Q3Eex9toYmaGBsbvU5Q= github.com/opencontainers/runc v1.2.8/go.mod h1:cC0YkmZcuvr+rtBZ6T7NBoVbMGNAdLa/21vIElJDOzI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/ory/dockertest v3.3.5+incompatible h1:iLLK6SQwIhcbrG783Dghaaa3WPzGc+4Emza6EbVUUGA= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/peterh/liner v1.2.0 h1:w/UPXyl5GfahFxcTOz2j9wCIHNI+pUPr2laqpojKNCg= github.com/peterh/liner v1.2.0/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7 h1:Dx7Ovyv/SFnMFw3fD4oEoeorXc6saIiQ23LrGLth0Gw= github.com/petermattis/goid v0.0.0-20240813172612-4fcff4a6cae7/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/phuslu/log v1.0.120 h1:ok+KEfGEz4RM9iyiJ5NhMa0KspywxT55EkpIL2YOzzo= github.com/phuslu/log v1.0.120/go.mod h1:F8osGJADo5qLK/0F88djWwdyoZZ9xDJQL1HYRHFEkS0= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= github.com/pk910/dynamic-ssz v0.0.4 h1:DT29+1055tCEPCaR4V/ez+MOKW7BzBsmjyFvBRqx0ME= github.com/pk910/dynamic-ssz v0.0.4/go.mod h1:b6CrLaB2X7pYA+OSEEbkgXDEcRnjLOZIxZTsMuO/Y9c= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/protolambda/bls12-381-util v0.1.0 h1:05DU2wJN7DTU7z28+Q+zejXkIsA/MF8JZQGhtBZZiWk= github.com/protolambda/bls12-381-util v0.1.0/go.mod h1:cdkysJTRpeFeuUVx/TXGDQNMTiRAalk1vQw3TYTHcE4= github.com/protolambda/zrnt v0.34.1 h1:qW55rnhZJDnOb3TwFiFRJZi3yTXFrJdGOFQM7vCwYGg= github.com/protolambda/zrnt v0.34.1/go.mod h1:A0fezkp9Tt3GBLATSPIbuY4ywYESyAuc/FFmPKg8Lqs= github.com/protolambda/ztyp v0.2.2 h1:rVcL3vBu9W/aV646zF6caLS/dyn9BN8NYiuJzicLNyY= github.com/protolambda/ztyp v0.2.2/go.mod h1:9bYgKGqg3wJqT9ac1gI2hnVb0STQq7p/1lapqrqY1dU= github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516 h1:xuVAdtz5ShYblG2sPyb4gw01DF8InbOI/kBCQjk7NiM= github.com/prysmaticlabs/fastssz v0.0.0-20241008181541-518c4ce73516/go.mod h1:h2OlIZD/M6wFvV3YMZbW16lFgh3Rsye00G44J2cwLyU= github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15 h1:lC8kiphgdOBTcbTvo8MwkvpKjO0SlAgjv4xIK5FGJ94= github.com/prysmaticlabs/go-bitfield v0.0.0-20240618144021-706c95b2dd15/go.mod h1:8svFBIKKu31YriBG/pNizo9N0Jr9i5PQ+dFkxWg3x5k= github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b h1:VK7thFOnhxAZ/5aolr5Os4beiubuD08WiuiHyRqgwks= github.com/prysmaticlabs/gohashtree v0.0.4-beta.0.20240624100937-73632381301b/go.mod h1:HRuvtXLZ4WkaB1MItToVH2e8ZwKwZPY5/Rcby+CvvLY= github.com/prysmaticlabs/prysm/v5 v5.3.0 h1:7Lr8ndapBTZg00YE+MgujN6+yvJR6Bdfn28ZDSJ00II= github.com/prysmaticlabs/prysm/v5 v5.3.0/go.mod h1:r1KhlduqDMIGZ1GhR5pjZ2Ko8Q89noTDYTRoPKwf1+c= github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0= github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sasha-s/go-deadlock v0.3.5 h1:tNCOEEDG6tBqrNDOX35j/7hL5FcFViG6awUGROb2NsU= github.com/sasha-s/go-deadlock v0.3.5/go.mod h1:bugP6EGbdGYObIlx7pUZtWqlvo8k9H6vCBBsiChJQ5U= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2lyGa2E= github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e h1:cR8/SYRgyQCt5cNCMniB/ZScMkhI9nk8U5C7SbISXjo= github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e/go.mod h1:Tu4lItkATkonrYuvtVjG0/rhy15qrNGNTjPdaphtZ/8= github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY= github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg= github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/umbracle/fastrlp v0.1.0 h1:V0W3f6ZKWqbu1KggdhnRWOi+t7+PfL3VyAffJqayI5s= github.com/umbracle/fastrlp v0.1.0/go.mod h1:5RHgqiFjd4vLJESMWagP/E7su+5Gzk0iqqmrotR8WdA= github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zondax/hid v0.9.2 h1:WCJFnEDMiqGF64nlZz28E9qLVZ0KSJ7xpc5DLEyma2U= github.com/zondax/hid v0.9.2/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWpEM= github.com/zondax/ledger-go v0.14.3 h1:wEpJt2CEcBJ428md/5MgSLsXLBos98sBOyxNmCjfUCw= github.com/zondax/ledger-go v0.14.3/go.mod h1:IKKaoxupuB43g4NxeQmbLXv7T9AlQyie1UpHb342ycI= gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b h1:CzigHMRySiX3drau9C6Q5CAbNIApmLdat5jPMqChvDA= gitlab.com/yawning/secp256k1-voi v0.0.0-20230925100816-f2616030848b/go.mod h1:/y/V339mxv2sZmYYR64O07VuCpdNZqCTwO8ZcouTMI8= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02 h1:qwDnMxjkyLmAFgcfgTnfJrmYKWhHnci3GjDqcZp1M3Q= gitlab.com/yawning/tuplehash v0.0.0-20230713102510-df83abbf9a02/go.mod h1:JTnUj0mpYiAsuZLmKjTx/ex3AtMowcCgnE7YNyCEP0I= go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.17.0 h1:4O3dfLzd+lQewptAHqjewQZQDyEdejz3VwgeYwkZneU= golang.org/x/arch v0.17.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d h1:PksQg4dV6Sem3/HkBX+Ltq8T0ke0PKIRBNBatoDTVls= google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d/go.mod h1:s7iA721uChleev562UJO2OYB0PPT9CMFjV+Ce7VJH5M= google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b h1:uA40e2M6fYRBf0+8uN5mLlqUtV192iiksiICIBkYJ1E= google.golang.org/genproto/googleapis/api v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:Xa7le7qx2vmqB/SzWUBa7KdMjpdpAHlh5QCSnjessQk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b h1:Mv8VFug0MP9e5vUxfBcE3vUkV6CImK3cMNMIDFjmzxU= google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/Knetic/govaluate.v3 v3.0.0 h1:18mUyIt4ZlRlFZAAfVetz4/rzlJs9yhN+U02F4u1AOc= gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/apimachinery v0.30.4 h1:5QHQI2tInzr8LsT4kU/2+fSeibH1eIHswNx480cqIoY= k8s.io/apimachinery v0.30.4/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= k8s.io/client-go v0.30.4 h1:eculUe+HPQoPbixfwmaSZGsKcOf7D288tH6hDAdd+wY= k8s.io/client-go v0.30.4/go.mod h1:IBS0R/Mt0LHkNHF4E6n+SUDPG7+m2po6RZU7YHeOpzc= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= ================================================ FILE: kurtosis/Makefile ================================================ #!/usr/bin/make -f ############################################################################### ### Kurtosis ### ############################################################################### # This Makefile uses bash specific syntax. Makefile usually runs commands in # /bin/sh. This is fine on Macos since /bin/sh is bash. However, on Ubuntu, # /bin/sh is dash, so many of the commands here will fail without this (env # variables like PATH not set, STDERR redirect does not work, etc). SHELL := /bin/bash BLOCKSCOUT_VERIF_GHCR = ghcr.io/blockscout/smart-contract-verifier:v1.10.0 BLOCKSCOUT_VERIF_LOCAL = blockscout-sc-verifier:v1.10.0 # Installs Kurtosis if not already installed install-kurtosis: @echo "Checking for Kurtosis installation..." @if ! command -v kurtosis &> /dev/null; then \ echo "Kurtosis could not be found, installing..."; \ OS=$$(uname -s | tr A-Z a-z); \ if [ "$$OS" = "darwin" ]; then \ brew install kurtosis-tech/tap/kurtosis-cli; \ elif [ "$$OS" = "linux" ]; then \ ARCH=$$(uname -m); \ if [ "$$ARCH" = "x86_64" ]; then ARCH="amd64"; \ elif [ "$$ARCH" = "arm64" ]; then ARCH="arm64"; \ else echo "Unsupported architecture $$ARCH for Kurtosis installation" && exit 1; fi; \ TAG=`curl -s "https://api.github.com/repos/kurtosis-tech/kurtosis-cli-release-artifacts/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/'`; \ curl -Lo kurtosis.tar.gz "https://github.com/kurtosis-tech/kurtosis-cli-release-artifacts/releases/download/$TAG/kurtosis-cli_${TAG}_${OS}_${ARCH}.tar.gz"; \ tar -xzf kurtosis.tar.gz; \ rm kurtosis.tar.gz; \ chmod +x kurtosis; \ sudo mv kurtosis /usr/local/bin/; \ else \ echo "Unsupported OS $$OS for Kurtosis installation" && exit 1; \ fi; \ else \ echo "Kurtosis is already installed"; \ fi # Starts a Kurtosis enclave containing a local devnet. start-devnet: install-kurtosis $(MAKE) build-docker VERSION=kurtosis-local start-devnet-no-build # Removes and restarts a Kurtosis enclave containing a local devnet. restart-devnet: -$(MAKE) rm-devnet kurtosis engine restart $(MAKE) start-devnet # Pre-pulls GHCR images that require credential-helper auth and re-tags them # to local-only names so the Kurtosis engine can resolve them without GHCR access. pull-blockscout-images: @echo "Pre-pulling blockscout images for local devnet..." @docker pull $(BLOCKSCOUT_VERIF_GHCR) @docker tag $(BLOCKSCOUT_VERIF_GHCR) $(BLOCKSCOUT_VERIF_LOCAL) # Starts a Kurtosis enclave containing a local devnet without building the image start-devnet-no-build: pull-blockscout-images kurtosis run ./kurtosis --args-file ./kurtosis/beaconkit-local.yaml \ --enclave my-local-devnet --parallelism 200 # Starts a Kurtosis enclave in the cloud using the latest image tag start-devnet-cloud: install-kurtosis kurtosis run ./kurtosis --args-file ./kurtosis/beaconkit-cloud.yaml \ --enclave my-cloud-devnet-$(shell whoami) --parallelism 200 --production --image-download always # Remove the running Kurtosis enclave on GCP rm-devnet-cloud: kurtosis enclave rm my-cloud-devnet-$(shell whoami) --force # Stops the running Kurtosis enclave stop-devnet: kurtosis enclave stop my-local-devnet # Removes the specified Kurtosis enclave rm-devnet: kurtosis enclave rm my-local-devnet --force # Installs buildifier, a tool for linting and formatting starlark files. buildifier-install: @echo "--> Installing buildifier" @go install github.com/bazelbuild/buildtools/buildifier@latest # Lints Starlark (.star) files in the Kurtosis directory using buildifier star-lint: buildifier-install @echo "--> Running buildifier to format starlark files..." find ./kurtosis -name "*.star" -exec buildifier -mode=check {} + # Automatically fixes formatting issues in Starlark (.star) files using buildifier star-fix: buildifier-install @echo "--> Running buildifier to format starlark files..." find ./kurtosis -name "*.star" -exec buildifier --mode=fix {} + # Marks targets as not being associated with files .PHONY: start-devnet stop-devnet start-devnet-cloud rm-devnet-cloud reset-devnet rm-devnet buildifier-install \ star-lint star-fix install-kurtosis pull-blockscout-images ================================================ FILE: kurtosis/README.md ================================================ # Running BeaconKit with Kurtosis ## What is Kurtosis [Kurtosis](https://www.kurtosis.com/) is a platform for running distributed systems on Docker / Kubernetes. It provides a simple, powerful framework for spinning up and tearing down distributed systems programmatically. ## How to Use To use BeaconKit with Kurtosis, you'll first need to install the Kurtosis CLI and its dependencies. You can find instructions for doing so [here](https://docs.kurtosis.com/install). ### Docker/local environment Once you've installed the Kurtosis CLI, you can use it to spin up a Beacon network with the following command from within the root directory of the `beacon-kit` repository: ```sh make start-devnet ``` This will automatically build your `beacond` Docker image from the local source code and spin up a Kurtosis network based on the config file in `kurtosis/beaconkit-local.yaml`. Once complete, this will output all the network information for your nodes, like so: ![Example Network](./img/example-network.png) When you want to tear down your network, you can do so with the following commands: ```sh make stop-devnet make rm-devnet ``` And that's it! ## Deploy Devnet to Kubernetes Networks ### Deploy to a Google Cloud Network This will allow you to deploy a network orchestrated in the same way as `make start-devnet`, but on a cloud environment. A similar approach can be taken for a local Kubernetes environment (alternative commands will be commented with [Docker Desktop K8s]). - First, open your Kurtosis config: ```sh kurtosis config path # The command will output a path which you need to open in an editor /Users/.../kurtosis-config.yml ``` - Update the Kurtosis config with the following, replacing the entire file: ```yaml config-version: 2 should-send-metrics: true kurtosis-clusters: docker: type: "docker" docker-desktop: type: "kubernetes" config: kubernetes-cluster-name: "docker-desktop" storage-class: "hostpath" cloud: type: "kubernetes" config: kubernetes-cluster-name: "cloud" storage-class: "premium-rwo" ``` - Next, ensure Kurtosis is using the correct config so it deploys to the cloud instead of local Docker Desktop: ```sh kurtosis cluster set cloud # [Docker Desktop K8s]: kurtosis config use-context docker-desktop ``` - Now ensure your Kubernetes config is using the correct context, i.e., the one context you wish to deploy to: ```sh kubectl config use-context gke_prj-..... # [Docker Desktop K8s]: kubectl config use-context docker-desktop ``` - Run Kurtosis Gateway. This command will start a local "gateway" to connect your local machine to your remote Kubernetes cluster. Run this in a separate shell: ```sh kurtosis gateway ``` - Cloud-based deployments require a Docker image, as local Docker images cannot be pulled from the remote instance. If you want to update the image, edit: ```yaml # Found in beacon-kit/kurtosis/beaconkit-cloud.yaml images: beaconkit: ghcr.io/berachain/beacon-kit:main ``` - Deploy. Note that re-executing the same command twice will start the network from zero again unless you change the enclave name in the `Makefile`: ```sh make start-devnet-cloud ``` - View your deployment in K9s, navigating to the relevant namespace. It should be named `kt-my-cloud-devnet-${whoami}`. ## Helper Commands If you want to start from a clean state and remove all existing pods: ```sh # Everything is wrecked kurtosis clean -a kurtosis engine restart ``` If you manually kill a pod and want to restart it: ```sh # Note that for the namespace, you should remove the "kt-" prefix kurtosis service start {namespace} {podname} ``` ================================================ FILE: kurtosis/beaconkit-cloud.yaml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # This is the configuration is identical to beaconkit-local.yaml with the exception that the image is pulled from a public registry # As remote environments cannot access the image created locally. It also sets explicit min_cpu and min_memory values for the nodes # as in Kubernetes, the 0 value is interpreted as the max value. This is not the case for the local Docker environment. network_configuration: chain_id: 80087 chain_spec: "devnet" validators: type: "validator" nodes: - el_type: reth kzg_impl: crate-crypto/go-kzg-4844 replicas: 5 full_nodes: type: "full" nodes: - el_type: reth kzg_impl: crate-crypto/go-kzg-4844 replicas: 5 seed_nodes: type: "seed" nodes: - el_type: reth replicas: 1 node_settings: consensus_settings: specs: min_cpu: 1000 max_cpu: 2000 min_memory: 1024 max_memory: 2048 images: beaconkit: ghcr.io/berachain/beacon-kit:main config: timeout_propose: 2s timeout_prevote: 2s timeout_precommit: 2s max_num_inbound_peers: 40 max_num_outbound_peers: 10 app: payload_timeout: 850ms execution_settings: specs: min_cpu: 1000 max_cpu: 2000 min_memory: 1024 max_memory: 2048 images: reth: ghcr.io/berachain/bera-reth:nightly additional_services: - name: "spamoor" - name: "tx-fuzz" replicas: 16 - name: "prometheus" - name: "grafana" - name: "pyroscope" - name: "blockscout" client: "el-full-reth-0" ================================================ FILE: kurtosis/beaconkit-local.yaml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. network_configuration: chain_id: 80087 chain_spec: "devnet" validators: type: "validator" nodes: - el_type: reth kzg_impl: crate-crypto/go-kzg-4844 replicas: 5 full_nodes: type: "full" nodes: - el_type: reth kzg_impl: crate-crypto/go-kzg-4844 replicas: 5 seed_nodes: type: "seed" nodes: - el_type: reth replicas: 1 node_settings: consensus_settings: specs: min_cpu: 0 max_cpu: 2000 min_memory: 0 max_memory: 2048 images: beaconkit: beacond:kurtosis-local config: timeout_propose: 2s timeout_prevote: 2s timeout_precommit: 2s max_num_inbound_peers: 40 max_num_outbound_peers: 10 app: payload_timeout: 850ms execution_settings: specs: min_cpu: 0 max_cpu: 2000 min_memory: 0 max_memory: 2048 images: reth: ghcr.io/berachain/bera-reth:nightly additional_services: - name: "spamoor" - name: "tx-fuzz" replicas: 16 - name: "prometheus" - name: "grafana" - name: "pyroscope" - name: "blockscout" client: "el-full-reth-0" verifier_image: "blockscout-sc-verifier:v1.10.0" ================================================ FILE: kurtosis/kurtosis-params.yaml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. network_params: network_name: "kurtosis" network_id: "80087" ================================================ FILE: kurtosis/kurtosis.yml ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. name: github.com/berachain/beacon-kit/kurtosis description: | A package for running a basic beacon-kit devnet with kurtosis replace: # Fix to a specific version of kurtosis ethereum package to avoid breaking changes github.com/ethpandaops/ethereum-package: github.com/ethpandaops/ethereum-package@cda5ddac51e4ce2228f2a4da1d242b2fcb7eeccd ================================================ FILE: kurtosis/main.star ================================================ el_cl_genesis_data_generator = import_module( "github.com/ethpandaops/ethereum-package/src/prelaunch_data_generator/el_cl_genesis/el_cl_genesis_generator.star", ) execution = import_module("./src/nodes/execution/execution.star") service_module = import_module("./src/services/service.star") beacond = import_module("./src/nodes/consensus/beacond/launcher.star") networks = import_module("./src/networks/networks.star") port_spec_lib = import_module("./src/lib/port_spec.star") nodes = import_module("./src/nodes/nodes.star") constants = import_module("./src/constants.star") spamoor = import_module("./src/services/spamoor/launcher.star") prometheus = import_module("./src/observability/prometheus/prometheus.star") grafana = import_module("./src/observability/grafana/grafana.star") pyroscope = import_module("./src/observability/pyroscope/pyroscope.star") tx_fuzz = import_module("./src/services/tx_fuzz/launcher.star") blockscout = import_module("./src/services/blockscout/launcher.star") def run(plan, network_configuration = {}, node_settings = {}, additional_services = [], metrics_enabled_services = []): """ Initiates the execution plan with the specified number of validators and arguments. Args: plan: The execution plan to be run. network_configuration: Network configuration including validators, full nodes, seed nodes. node_settings: Node-specific settings. additional_services: Additional services to launch. metrics_enabled_services: Services with metrics enabled. """ # all_node_types = [validators["type"], full_nodes["type"], seed_nodes["type"]] # all_node_settings = nodes.parse_node_settings(node_settings, all_node_types) # Get chain configuration from network_configuration, if not provided, use default values chain_id = network_configuration.get("chain_id", 80087) chain_spec = network_configuration.get("chain_spec", "devnet") plan.print("CHAIN_ID: {}".format(chain_id), "CHAIN_SPEC: {}".format(chain_spec)) next_free_prefunded_account = 0 validators = nodes.parse_nodes_from_dict(network_configuration["validators"], node_settings) full_nodes = nodes.parse_nodes_from_dict(network_configuration["full_nodes"], node_settings) seed_nodes = nodes.parse_nodes_from_dict(network_configuration["seed_nodes"], node_settings) num_validators = len(validators) # 1. Initialize EVM genesis data evm_genesis_data = networks.get_genesis_data(plan) all_nodes = [] all_nodes.extend(validators) all_nodes.extend(seed_nodes) all_nodes.extend(full_nodes) node_modules = {} for node in all_nodes: if node.el_type not in node_modules.keys(): node_path = "./src/nodes/execution/{}/config.star".format(node.el_type) node_module = import_module(node_path) node_modules[node.el_type] = node_module # 2. Upload files jwt_file, kzg_trusted_setup = execution.upload_global_files(plan, node_modules, chain_id) # 3. Perform genesis ceremony for the CL genesis deposits. genesis_result = beacond.perform_genesis_deposits_ceremony(plan, validators, jwt_file, chain_id, chain_spec) stored_configs = genesis_result.configs # 4 a. Create genesis files only once and pass it to the node configs genesis_files = nodes.create_genesis_files_part1(plan, chain_id) # 4b. Modify the eth genesis file with the premined deposits && finalize CL genesis file. # Get the deposit storage values stored in env variables env_vars = beacond.modify_genesis_files_deposits(plan, validators, genesis_files, chain_id, chain_spec, stored_configs) # Extract values from env_vars genesis_deposits_root = env_vars.get("GENESIS_DEPOSITS_ROOT") genesis_deposit_count_hex = env_vars.get("GENESIS_DEPOSIT_COUNT_HEX") # 4c. Modify the eth genesis files with the ENV VARS genesis_files = nodes.create_genesis_files_part2(plan, chain_id, genesis_deposits_root, genesis_deposit_count_hex) el_enode_addrs = [] metrics_enabled_services = metrics_enabled_services[:] consensus_node_peering_info = [] all_consensus_peering_info = {} # Start seed nodes seed_node_el_client_configs = [] for n, seed in enumerate(seed_nodes): el_client_config = execution.generate_node_config(plan, node_modules, seed, chain_id, chain_spec, genesis_files) seed_node_el_client_configs.append(el_client_config) if seed_node_el_client_configs != []: seed_node_el_clients = execution.deploy_nodes(plan, seed_node_el_client_configs) for n, seed in enumerate(seed_nodes): enode_addr = execution.get_enode_addr(plan, seed.el_service_name) el_enode_addrs.append(enode_addr) metrics_enabled_services = execution.add_metrics(metrics_enabled_services, seed, seed.el_service_name, seed_node_el_clients[seed.el_service_name], node_modules) seed_node_configs = {} for n, seed in enumerate(seed_nodes): seed_node_config = beacond.create_node_config(plan, seed, consensus_node_peering_info, seed.el_service_name, chain_id, chain_spec, genesis_deposits_root, genesis_deposit_count_hex, jwt_file, kzg_trusted_setup) seed_node_configs[seed.cl_service_name] = seed_node_config seed_nodes_clients = {} if seed_node_configs != {}: seed_nodes_clients = plan.add_services( configs = seed_node_configs, ) for n, seed_client in enumerate(seed_nodes): peer_info = beacond.get_peer_info(plan, seed_client.cl_service_name) consensus_node_peering_info.append(peer_info) metrics_enabled_services.append({ "name": seed_client.cl_service_name, "service": seed_nodes_clients[seed_client.cl_service_name], "metrics_path": beacond.METRICS_PATH, }) # 5. Start full nodes (rpcs) full_node_configs = {} full_node_el_client_configs = [] full_node_el_clients = {} for n, full in enumerate(full_nodes): el_client_config = execution.generate_node_config(plan, node_modules, full, chain_id, chain_spec, genesis_files, el_enode_addrs) full_node_el_client_configs.append(el_client_config) if full_node_el_client_configs != []: full_node_el_clients = execution.deploy_nodes(plan, full_node_el_client_configs, True) for n, full in enumerate(full_nodes): metrics_enabled_services = execution.add_metrics(metrics_enabled_services, full, full.el_service_name, full_node_el_clients[full.el_service_name], node_modules) for n, full in enumerate(full_nodes): # 5b. Launch CL full_node_config = beacond.create_node_config(plan, full, consensus_node_peering_info, full.el_service_name, chain_id, chain_spec, genesis_deposits_root, genesis_deposit_count_hex, jwt_file, kzg_trusted_setup) full_node_configs[full.cl_service_name] = full_node_config if full_node_configs != {}: services = plan.add_services( configs = full_node_configs, ) for n, full_node in enumerate(full_nodes): peer_info = beacond.get_peer_info(plan, full_node.cl_service_name) all_consensus_peering_info[full_node.cl_service_name] = peer_info metrics_enabled_services.append({ "name": full_node.cl_service_name, "service": services[full_node.cl_service_name], "metrics_path": beacond.METRICS_PATH, }) # 7. Start network validators validator_node_el_clients = [] for n, validator in enumerate(validators): el_client_config = execution.generate_node_config(plan, node_modules, validator, chain_id, chain_spec, genesis_files, el_enode_addrs) validator_node_el_clients.append(el_client_config) validator_el_clients = execution.deploy_nodes(plan, validator_node_el_clients) for n, validator in enumerate(validators): metrics_enabled_services = execution.add_metrics(metrics_enabled_services, validator, validator.el_service_name, validator_el_clients[validator.el_service_name], node_modules) validator_node_configs = {} for n, validator in enumerate(validators): validator_node_config = beacond.create_node_config(plan, validator, consensus_node_peering_info, validator.el_service_name, chain_id, chain_spec, genesis_deposits_root, genesis_deposit_count_hex, jwt_file, kzg_trusted_setup) validator_node_configs[validator.cl_service_name] = validator_node_config cl_clients = plan.add_services( configs = validator_node_configs, ) for n, validator in enumerate(validators): peer_info = beacond.get_peer_info(plan, validator.cl_service_name) all_consensus_peering_info[validator.cl_service_name] = peer_info metrics_enabled_services.append({ "name": validator.cl_service_name, "service": cl_clients[validator.cl_service_name], "metrics_path": beacond.METRICS_PATH, }) for n, seed_node in enumerate(seed_nodes): beacond.dial_unsafe_peers(plan, seed_node.cl_service_name, all_consensus_peering_info) # If no seed nodes exist, bootstrap peering from the first validator # so that nodes can discover each other via PEX. if len(seed_nodes) == 0 and len(validators) > 0: beacond.dial_unsafe_peers(plan, validators[0].cl_service_name, all_consensus_peering_info) # Bootstrap EL peering: use first validator as a static peer so # all EL nodes can discover each other via devp2p. bootstrap_enode = execution.get_enode_addr(plan, validators[0].el_service_name) el_services_to_peer = [] for node in full_nodes: el_services_to_peer.append(node.el_service_name) for node in validators[1:]: el_services_to_peer.append(node.el_service_name) for el_name in el_services_to_peer: execution.add_peer(plan, el_name, bootstrap_enode) # 8. Start additional services prometheus_url = "" for s_dict in additional_services: s = service_module.parse_service_from_dict(s_dict) if s.name == "spamoor": plan.print("Launching spamoor") first_full_el_name = full_nodes[0].el_service_name first_full_el = full_node_el_clients[first_full_el_name] ip_spamoor = first_full_el.ip_address port_spamoor = first_full_el.ports["eth-json-rpc"].number spamoor.launch_spamoor( plan, constants.PRE_FUNDED_ACCOUNTS[next_free_prefunded_account], "http://{}:{}".format(ip_spamoor, port_spamoor), ) next_free_prefunded_account += 1 plan.print("Successfully launched spamoor") elif s.name == "tx-fuzz": plan.print("Launching tx-fuzz") if "replicas" not in s_dict: s.replicas = 1 next_free_prefunded_account = tx_fuzz.launch_tx_fuzzes(plan, s.replicas, next_free_prefunded_account, full_node_el_client_configs, full_node_el_clients, []) elif s.name == "prometheus": prometheus_url = prometheus.start(plan, metrics_enabled_services) elif s.name == "grafana": grafana.start(plan, prometheus_url) elif s.name == "pyroscope": pyroscope.run(plan) elif s.name == "blockscout": plan.print("Launching blockscout") blockscout.launch_blockscout( plan, full_node_el_clients, s.client, False, s.verifier_image, ) plan.print("Successfully launched development network") ================================================ FILE: kurtosis/src/constants.star ================================================ KURTOSIS_IP_ADDRESS_PLACEHOLDER = "KURTOSIS_IP_ADDR_PLACEHOLDER" GLOBAL_LOG_LEVEL = struct( info = "info", error = "error", warn = "warn", debug = "debug", trace = "trace", ) JWT_MOUNT_PATH_ON_CONTAINER = "/jwt/jwt-secret.hex" JWT_FILEPATH = "/kurtosis/src/nodes/jwt-secret.hex" KZG_TRUSTED_SETUP_FILEPATH = "/kurtosis/src/nodes/kzg-trusted-setup.json" def new_prefunded_account(address, private_key): return struct(address = address, private_key = private_key) PRE_FUNDED_ACCOUNTS = [ new_prefunded_account( "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4", "fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306", ), new_prefunded_account( "0x56898d1aFb10cad584961eb96AcD476C6826e41E", "9b9bc88a144fff869ae2f4ea8e252f2494d9b52ea1008d0b3537dad27ab489d5", ), # Starting here we use this mnemonic 'brass gallery tennis vintage crack virus outside bike fossil shock sword panda ritual about cover clap fruit festival parrot capable high vacant orchard hurt' new_prefunded_account( "0x1e2e53c2451d0f9ED4B7952991BE0c95165D5c01", "0x23b19fd0ba67f921bc1f5a133bfe452060d129f025fcf1be75c6964551b1208a", ), new_prefunded_account( "0x3bd0E8f1B1E8Ec99a4E1762F4058F9884C93af31", "0x0e67856b2a42ca52862a60d11e3ac57871988aefe7a28ecd20bd8c2dec55da25", ), new_prefunded_account( "0xD073a84e2ccDF91a9025179330438485E886D206", "0xa901724fadf8e33b97e907d903dda50553969f6c8be510199878989c459b629a", ), new_prefunded_account( "0x8a88215ae882dfA519730c40109556c1C235729f", "0x110ecfb76a8a19b4fc32d7842548e00d7d6c1ba48bbc5d760eb97c9cd6fdbdc6", ), new_prefunded_account( "0x1a0A57e5e6a66aD732295ddAF0aed286a4e64310", "0xc6b45ae662b588d7419202030581e1c104414dcd79b2c7d43b29908190b4b983", ), new_prefunded_account( "0x185F4Eebd01614aE3d12a5E49b184B054C46d37B", "0x668eedaaaa05e87a9e62364f4ee75aba0aa78e13fb0142882ecb5beb2b58eb09", ), new_prefunded_account( "0xdb96E9cDD1e457b602f97d33e51736D7a5216496", "0x11c442db1d30e3f926f7e8c4a4208574d682669c6d720cb7d4eec910c0cfc863", ), new_prefunded_account( "0x44a5FBfa7d6f3Fd92cca01f6764509f8Fc33dfa5", "0x2ad0867fb0a18a3c0d8ef4dfce28e5356575f7a4a583ea1be7e50b0294d44614", ), new_prefunded_account( "0x3649839562C8dA64E6215EB0f5371629Ead9729D", "0x79ffac4f8ea5fcab09114a00e83e36b4c509ed46cdf20e5f9ba080a43fa1ebb6", ), new_prefunded_account( "0x51e15e71c865FE702C9347610667f83658A20e00", "0xe8a6d4a8d7e48ad04111ef3c0727c77548a4e3f63ffae670a9a795c3c4273889", ), new_prefunded_account( "0xBC9BC89b295a14F3976234Cc37C73e3D286f3a49", "0x306e4df414d24524c01716fc26162506e760503a6ec8646fbdc7711a603608aa", ), new_prefunded_account( "0x12De044207a90709Ef2602D3D9D945d64dAe6147", "0x51dd5ac7fa687e86670623dbe48d19733fc89ed4ffec78effa6db68956afd3e5", ), new_prefunded_account( "0x4Afe0DFDAcc91F0fA2AEe39F9eAd66b64d03EbD6", "0xde57bd35f2dec5cd25c524f0bf0d62dcca84709fb1a9371a7efcd30a9af945cb", ), new_prefunded_account( "0xBC3c03b4185A6F10618CC4E7B9f4AdD59AB5FbbA", "0xd9a59c0514630682109fa233df2e86399835f72c1b30220af7e8fea11a971592", ), new_prefunded_account( "0xDc6De65f6070b409125217a12Cf576A208Cc1998", "0x00e89a500a096d53e2b2d1dfebc9f024ddc9ba5b2d3aeced79c87917cd3bddfc", ), new_prefunded_account( "0xF60fD8632Fc77E19b3A0637d115d0fdd06F36968", "0x634cffbe3f71b9dc4227563a4cb80204940dad303af48b0e66c9ef0ae0a6dd7c", ), new_prefunded_account( "0xbcC90AD39D377cA0b7b4F36eC463103E2728C33F", "0x00da370da5af1511feea6fbe327ce13d6f1355957781698fd5f31c4b7e68f568", ), new_prefunded_account( "0x6F69542fC88fF84C480FFf510aB7108120447247", "0x3536343125036f602508e7c5e05b102133360dcfbe98fb36ef76cebcfd3626d4", ), new_prefunded_account( "0x2f6eB3D9a41157322dE01A6E707F6F118Cb00A7b", "0x5612e01bb58597611457dfca072325b84d612be3b04378ba4be76a9ea681f5ec", ), new_prefunded_account( "0x187bE38A1f448b0F42423151A683dCAea949008B", "0x92b11cad0aa9a1c894157f4ff51bb905a13d0c47445e3033a0c46af802f2cd96", ), new_prefunded_account( "0xA1d283f1a11A36D20FF38F29e12CA8F7Cf8709c1", "0xb60dc9ebb4a6a301f28d69df14dfa48a699c941ae88bef1226d22034e7be4f90", ), new_prefunded_account( "0x868a33C94F91398B6245e1f0E4CF128B2F28714B", "0xa53464fd5ce1ad3f74bd2fef45fd81a4f8430b73900354b979a8cec409a6ddf0", ), new_prefunded_account( "0x67c942Ef50Fc690eA779067a6A0d444a8234baB5", "0x0310a72661205364e7f341b3a338d3a3bf6f2876403a3bd618be4f2f01af8b91", ), new_prefunded_account( "0xDE8E0E641E2Fb52c22460e6a1533c6BD13A00B37", "0x25e28dea3bc8c317608c6c8f6c394bce47fd5ff29ef8c101ec6f2bb678fc5093", ), new_prefunded_account( "0x9beFa0FB7a1A9E6cC7596204DbB8962E87091D64", "0x90e03f14c68e4c14b58b68668a68b8512bb21994cf05cb2c1af4d3e454a01999", ), new_prefunded_account( "0x62cB9bF32EA104f6D5eBf6879e876439f9492E4B", "0xa44b22fb3a02ec16a5c31b37878600647e5d43f51e2bb7e76fd0c6e2653db0a0", ), new_prefunded_account( "0xdb9cB94B166DfdC9F337EA63b32B448d993d7008", "0x71e76153038a529f306872ce3f01d246aa80982906d8c6092543fa8df76e0d73", ), new_prefunded_account( "0x7c4d7dB81c544B768E1f4782011077202B74B5C0", "0xe39d434543ebcc9db6467b4fc121220f06dad303df4f3cc0a51aff235273932f", ), new_prefunded_account( "0xaEf63D7F7e2637c99FeA1B63366b244B4da12D70", "0xb76ea4844f198d945449c28f795fa199f70f1bd37d0a1b4f489bf7f79639e6d0", ), new_prefunded_account( "0x3DFb4173ec41EB976260fd689E5AB9772C66beaf", "0x79b28c32e7b04ca737c6b9e9b2629ac8292285afa10ae73ee42706bea07a6940", ), new_prefunded_account( "0x5145b1B855bca67A119CB02A42aF4Bdbc66B725C", "0xa6e875f1d2991796746acada577196a56095ee2f684a00bb74b463336f3c0f0e", ), new_prefunded_account( "0xf4b2eb959A4C4b0E148340676999FC0446D446D4", "0x47b6a89108b41866932fa7448ad0feedec22b3baa9ab7f69c7564edf252420d4", ), new_prefunded_account( "0xb86d37333072eFb48cEaa46C67271A27CA5Bda82", "0x4ae54fa2370d6c515c30d9b0c04724dee47e684d1df754c775f5bf3d6ea03269", ), new_prefunded_account( "0x6CBcF4198fDA91D00fD469340E6DF6df086159e3", "0x9defa91490f3d1b6c67a682f06066bd72c7027dfd396e49aa9c10ab9c54b6196", ), new_prefunded_account( "0xE7F444b5f772281384117674002d540131e533Ca", "0xb0f3c0cea50abb97f50fa0777f7937ccfb4d558807a90c7eb4b0f674e7e74768", ), new_prefunded_account( "0x719Be866A77CeEc1BaC4FD37910c0975eFd52f55", "0x1c4e0bceb9d758e1aca207f430ef2963d483aeb6d5b073da049d8823ffe98a94", ), new_prefunded_account( "0x0e10cDAd84D788843aF48673C5b260A02ef78742", "0x20127f5feedc14aa3e3a6ac38d464e5c550093cc6b6d338f4a34bb9538e36e4c", ), new_prefunded_account( "0xcB6632daA65e6c921c2963C37320f63f54fC8fE3", "0x18500f6a8cf63787326c992e34d6d9ffad599ad14c62e8e9b383f889de935d7f", ), new_prefunded_account( "0xDe5C7198e2416baB7e7a1EA758858Cd7301740bF", "0x196df6fdda754bafd85228004b3c2173ccf6d42bdcd332ff78366185758aa44e", ), new_prefunded_account( "0x25fc16D8E2314B305dF05C032E617638284801D6", "0x0bb8e01ef0afe7715d1e0ee9ff33981862e680ae3299c32dc455ad256996ebbb", ), new_prefunded_account( "0xD2a3b89AE8D2c3bD39E2F24612ecFCD8600360C9", "0x7d3d3ace1f1164a8307c5187f43fe620d180be936391e36c435b0c594866d57f", ), new_prefunded_account( "0x2F4fD8a82A1400E654eeEC59b0e588445ffE0F96", "0x7916a06ca827d932627c7a82e9a68b7d79b1d64c139cfab14b97f9f0299cc576", ), new_prefunded_account( "0x10FdFa4EFc83d6CC42F5ef14c13da8b98E458214", "0x7f73e04379f0816b4eb5a579d575f34297f4a73713ffcfaf60a5b6116d6c1637", ), new_prefunded_account( "0x49cE37B2019bb2d0B8b6a094ef87a6Dd625454A0", "0x6174d6f44b02fac531b5cb0001b5c6a8ef7a94c349b70f2f1658f9e64120a9c5", ), new_prefunded_account( "0x800830F031ab1dd5895a5ec5B561427AD18f9ea8", "0xbb9de8caf4cd75f2775e2303f2f7d14127da8a32c029b3b6be195d0cb175cb34", ), new_prefunded_account( "0x3124d9885b11B52c56A2aee610AfCf5740d484F0", "0x67730ed1e0992a4541f1e24fe62e7356ee1affa9fa1e063025f803d594b796d0", ), new_prefunded_account( "0xA6177defF3b768b1D678EdF7583b8cf210C777c0", "0x5d3b93032a2a8422bc8188dcd86732e104a7e145ce1c417a425057ad84700a6d", ), new_prefunded_account( "0xF99139D2FCc5E25F57B0B91fd382a21B3AFF9cbA", "0xaedb174cee8faf87cfc89d1b0b8d3f71ce4fa093c1d3f6f95d66ca6d56c07a18", ), new_prefunded_account( "0xC4DD08191B4d5173e3698491A11e05b63F9Ee097", "0x794b0f636acc2d481d8a007c5c814b5ab0285b0f2dc4f09249cb140d232440c9", ), new_prefunded_account( "0xB8865B4B8C56861534CC07ebBD2EA569a9a16323", "0x5242412b3f8cfc334085ff367f7b0edcd9147128db5372f5af1c4a1653f65526", ), new_prefunded_account( "0x2B9935698dc5c19Ab7414AE22f27Da5F4478008a", "0x6c1f3aeff292aa72c4b3b29126acc1a3d221fb15cdd21a91afdea30197a3f693", ), new_prefunded_account( "0xAC3c80F41C3049A89Aba8072FFbFc38a90fb6D8c", "0x2a54bc87952ecdb225fecf5e17cda5e34a7af57a04f52f6cb3ea0fd73034b504", ), new_prefunded_account( "0xD6D4Fb22B91FAa54700852a05698B37d45514166", "0x5f5aafe935bdb54b7963f0a1198b5aa40fb076bb042d8cbb473202d223d4f661", ), new_prefunded_account( "0xAf325Ccc92ae883DEF1634D499d8B093192D7a0c", "0x12042bc310f17a3e138aed39d36db6a3fd79fc34af82d4579cb453bb106e20fd", ), new_prefunded_account( "0x7469CeEf99FB67e4990c5F1c085a1B39b2902331", "0x4763d00f07519325799eb96f1afc2b6495c962839f42c8947fcbb0fcb7714cb5", ), new_prefunded_account( "0x14DA5251a1EB236238969575ccE943e2Fb0f4AA1", "0x360d7a4c43661dc20b6b45aecc74731157820febd977d0e3f361c241505c2646", ), new_prefunded_account( "0xF9f58a87C3f0B3A4a0592938c80C41a7c659f855", "0x05ad2e2038fbbe5175b32ce433058ced25dcda16c1a9096a2babc67c6aded430", ), new_prefunded_account( "0x1CF7e940A657eE706718CF180eb21864DE9672C3", "0x77a7ea3cb368bfa6fafbb030fad7a8d1a5bb7522aaa6812f93cd48078cc9d777", ), new_prefunded_account( "0x440C37b22e8D7469128Ea7De6ac2f31419B4A8b1", "0x4eeb502b10d35d16f453e2c0c2047ec28040ca2535d1c3ef07e8a0df672a38d4", ), new_prefunded_account( "0x4bD04ABA9fc709835b1EE4789195d10E9e8E53F5", "0x7f3bc64adc04bb815c5308879e00adc474a6e5398753b2884d457dae9702edd7", ), new_prefunded_account( "0x4dC3aC871b22F8a98197B0aae976a8dE08e5Bebe", "0x4bb60046eed4f37440632278668a0f2137cd6853d716186b0feff56d3fac53d0", ), new_prefunded_account( "0x1f1D0FCa7e19b799c315d4fDf31bA50e6A2AB153", "0xaf68c285514858fdeb576b9a0b8429cad69d3a5b5e443b9da98a96a10b6e322b", ), new_prefunded_account( "0x28879749Dda99387bdB43295B28bdF251d999F3b", "0x411fad907c3951644ff9c1789488c70de8794913d53d946a5cb9af2f019f2396", ), new_prefunded_account( "0xC4eD09A472B82516daa3A4d8D1E38AE94CF4855C", "0x349d0efb83a78c04878e1b84dc50ba61f51d82dbcd4a93d6aa8469ed0bf36a76", ), new_prefunded_account( "0xf22FbA9cBeB75ED353931418E9eca71EF1Ab9921", "0x4b850afd62171d5152fd3ae606e9a54504331f5e05d2afd4425c8bb0593bc663", ), new_prefunded_account( "0xC59D8935c0570E75BA0E55E3C661f535C86e368B", "0x6df174e811caed865c56b85249da60ed6012d4a85defda84342080219408e615", ), new_prefunded_account( "0xf97a36c417D33D1fC60a9163A8715e1aecb29102", "0x4d2686dca939e451ada1c2c60b43ec51751a043013613e99a7f2657dc7e71857", ), new_prefunded_account( "0x4245537d9e3fb36fBBf054247FfFB28b0d931503", "0x771675f7f662ce044421ef85e9f4d01b67cbf4dc49bcd8c66ba051b58cfa36b1", ), new_prefunded_account( "0xFeb1eafa0154D291e28e393FAF10Bc89e5cCbB22", "0x2bad44bacec98635554cceec959a4913ed70bbc22c41652432ed8449c3ba8659", ), new_prefunded_account( "0xf11D16e2EE6BefED82Fbca0b005906E09303aB95", "0xc090fc69382106e7b4563b5132d1791950144611ace0a13c74660512f04d262f", ), new_prefunded_account( "0x9C75eD1A37ae420b4FC0a1F4c26B673227Fd3AFa", "0xf128a6a5e4465a627b97b0e5456a098550fcbac6688a9d7ec8f327934ee9f493", ), new_prefunded_account( "0x6a354C708fd248FD778F6adF75E41AA554700F68", "0xc3cc22368afd808e703e3679043a8803f9185e5be4c27a99805b3156970bcc62", ), new_prefunded_account( "0xea94749deFcc40dC5992687974b1C84B1bB9D6df", "0x1ea128368d1cd5ff6f548cf22e1e9f8a60acd5937dd5a77280cebe75705ba362", ), new_prefunded_account( "0x7689BE67b205EB5d32811d95D60587Eae4F3036F", "0x177933fe33ff1be7e031cdcbc90bd8c686aa8e809dbe9eaae4da2e7e659281ca", ), new_prefunded_account( "0xdBfb742BD2e0e6E353cb61E75B9e11257aC8fB1A", "0x4afe37059cee4b8dff36e6ede45fa47e96971a77a45e6e3e4a64ae204ab01ff4", ), new_prefunded_account( "0x2E5f031578e8FF82199aaF16f42c44D43Fe61819", "0x18bceb845b15b430b2fdb4dfa19bcf6a2ca9fc99f215df9d44c715ee7efe8067", ), new_prefunded_account( "0x611a42A2EF62c2461D123e3F0B64b93938bc4781", "0x206ff78c78e9301bc8b11fc658a9bbc722152b6739038938347e02ec4d0e9bc6", ), new_prefunded_account( "0x1a0c826048DF0E4661E3c53bBd447d497E3f701F", "0x40e62b0f968d1185354a33e2d63087f86e8925e1158419e467a327d4d115f732", ), new_prefunded_account( "0x7f0E54bc3C1a72405646F5dFbBE0D4565c649fe2", "0x62fd8b90b047849fed591bf2ff867a8437bd20c759376ceb587e7fb9b5eefef8", ), new_prefunded_account( "0x54e1F990Dc0B7367F1E8eD96dA63BC4bca0E8061", "0xaa4273b5eaf92f77bd98944d362a51001101b35c708b7a144074b8e6c05c8831", ), new_prefunded_account( "0xbE651bc261b9Da5499a24Bf4214fD494c6e1F5Ac", "0x95695009fe4132a590cfce1cc0a9980a51e730ea2ec8449c3f94531d55063d70", ), new_prefunded_account( "0xD3c5dAC705289cD005C402C79C8445a47502d8be", "0xcf89fbd9ef2d93c5839fded6a80be8af79c95cc9c62255c660e47fe03531789d", ), new_prefunded_account( "0xE5981AA0807eb05611cDb666e32e53b2001bd61d", "0xa511d7ddbd3de692c29330d9dfa9dbb6d910607848fb40f14f19107d07982d9a", ), new_prefunded_account( "0x0fb648Cb08e21602AF61AF53fE104E29d46433F7", "0x8b9e4e5748ac1768c78292daa4c4791af24fe0d67e8a98aab5ef02501d3dfa29", ), new_prefunded_account( "0x0474f52d25529c4db5f4E72F43303dA71B3541C6", "0x3c9ccc6a117204e9dca913ffc04b2ce235cafba8feb6dac15c47594c315d525d", ), new_prefunded_account( "0xe3024d098953661638d59E06f7FcD0B61c424854", "0xbaaf13a119fb0dfe196452d25b9452dd9ac6e2d9b18dc25ab141edab71433252", ), new_prefunded_account( "0x8b1e58f651CacaAa40291d2a6E0a6404d7Ed99e6", "0x5f3b3f4b7df21eb2032b9c5340ead919fe4b33788428c1634812e77b1f736da2", ), new_prefunded_account( "0x8724C57fb8f38A1FccA7177543dd1D8FcD49E5aa", "0xc24373d037a7e85f0b24fd0664fe9466955c04f97dad338bde0b6711e83db961", ), new_prefunded_account( "0xd0F043dED28773953562f824334C4cbb84210AE7", "0x5e66a59b22d0284554824c42043bca69d96b41693c8504228332743191fb5c41", ), new_prefunded_account( "0xE3d2b9191EaBD3636A5dd057D522335cfae8c7CF", "0x33663a07dcae30eabe33966af3c7346d7e6fda84d4f5f2d5c6ecb7182875255e", ), new_prefunded_account( "0x3f51B3BB6A18141282Ba002F7709c7E2f337F961", "0x1a9c0e36f536927b1bb371479e3e66da1d76c3cef38dc8df6abcd7f885eb2b37", ), new_prefunded_account( "0xf6B6A52aA9BD788837c6682f47ACE009BD84b6fc", "0x9d4f7b83d269e83cab82a829a4af8cdfc75f222266b59da05659fe81f0a9160a", ), new_prefunded_account( "0x795B761Db5969B7ba53472d5D37c230C859a472F", "0xb4f6c92d12dcaa5dde866306ba3bf13ee6a2f93579b9b5659df84e55043473cc", ), new_prefunded_account( "0x7d7f187C2A05cDDCF700dCF2E02c96E7eF03f9B0", "0xf5ef0b476332f7384b0d22dfe04079b71b75396ea31df7af83372dbddc34a758", ), new_prefunded_account( "0x2d88ECD4d8F4b0A954886eE8C0802aE14684cd07", "0x92765a2ecd92b6166663763194d31e89d6609b24222b5634cabf4b4813ac973d", ), new_prefunded_account( "0x92B3feac5b7816Dcef96a303c1D5112271A70D2c", "0x2846ec46730e70b54a766caac56d13832d19bdccf57254931cf195a54595d36c", ), new_prefunded_account( "0x5DD7bc3BEE395831ce499315ecAFE81DE0556F99", "0x9408db8dbf6eb04ce9d35b332dab7f82d9092c18f8bc591fa97fb3ed300f3254", ), new_prefunded_account( "0x5227aaebCA3E5e893547A667666E2e4e12Ca20e0", "0xb4eadccdc48d78d5c2bf1f608b68e971b27b49c984ada2c1237c092f823f1511", ), new_prefunded_account( "0x47575DAE85403cD408d4639068D1187C427B9897", "0x3f380d57c59b08cc54e5daa9edc2bbeb9946ed55800513ecac6c36e3216df1df", ), new_prefunded_account( "0xE69ac59e1DF47291AaB8DEc540C796f81De7c892", "0xe4f5eff00c76ec509ac9fc9f0dd4c90df9d275d72200da735ff318d7da102efc", ), new_prefunded_account( "0xb87fb371Bd3C2093b608cd0E7a8dDD60Bb05C995", "0x778b9f67675f289c9aeea78c80799ec5a625d655932733463e3a890f8f9d7e69", ), ] ================================================ FILE: kurtosis/src/lib/bash.star ================================================ def exec_on_service(plan, service_name, command): return plan.exec( service_name = service_name, recipe = ExecRecipe( command = ["bash", "-c", command], ), ) ================================================ FILE: kurtosis/src/lib/builtins.star ================================================ """ Helper library for type comparisons Typical usage examples: type(None) == builtins.types.none # True hello = "hello" type(hello) == builtins.types.bool # False """ types = struct( none = "NoneType", # the type of None bool = "bool", # True or False int = "int", # a signed integer of arbitrary magnitude float = "float", # an IEEE 754 double-precision floating-point number string = "string", # a text string, with Unicode encoded as UTF-8 or UTF-16 bytes = "bytes", # a byte string list = "list", # a fixed-length sequence of values tuple = "tuple", # a fixed-length sequence of values, unmodifiable dict = "dict", # a mapping from values to values function = "function", # a function serviceConfig = "ServiceConfig", # a service configuration object portSpec = "PortSpec", # a port spec object directory = "Directory", # a directory object execRecipe = "ExecRecipe", # an exec recipe object getHttpRequestRecipe = "GetHttpRequestRecipe", # a get http request recipe object imageBuildSpec = "ImageBuildSpec", # an image build spec object module = "module", # a module # TODO(types): add remaining kurtosis types ) # Types that can be used as keys in a dictionary due to being hashable # Note: tuples can also be hashable but only if they contain hashable elements hashable = [types.none, types.bool, types.int, types.float, types.string, types.bytes] ================================================ FILE: kurtosis/src/lib/helpers.star ================================================ def stop_service(plan, service_name): plan.stop_service(service_name) def start_service(plan, service_name): plan.start_service(service_name) ================================================ FILE: kurtosis/src/lib/port_spec.star ================================================ builtins = import_module("./builtins.star") DEFAULT_TRANSPORT_PROTOCOL = "tcp" DEFAULT_APPLICATION_PROTOCOL = "" DEFAULT_WAIT = "15s" def get_port_spec_template( number, transport_protocol = DEFAULT_TRANSPORT_PROTOCOL, application_protocol = DEFAULT_APPLICATION_PROTOCOL, wait = DEFAULT_WAIT): port_spec = { "number": number, "transport_protocol": transport_protocol, "application_protocol": application_protocol, "wait": wait, } validate_port_spec(port_spec) return port_spec def validate_port_spec(port_spec): if type(port_spec) != builtins.types.dict: fail("Port spec must be a dict, not {0}".format(type(port_spec))) if type(port_spec["number"]) != builtins.types.int: fail("Port spec number must be an int, not {0}".format(type(port_spec["number"]))) if port_spec["transport_protocol"] != None: if type(port_spec["transport_protocol"]) != builtins.types.string: fail("Port spec transport_protocol must be a string, not {0}".format(type(port_spec["transport_protocol"]))) if port_spec["application_protocol"] != None: if type(port_spec["application_protocol"]) != builtins.types.string: fail("Port spec application_protocol must be a string, not {0}".format(type(port_spec["application_protocol"]))) if port_spec["wait"] != None: if type(port_spec["wait"]) != builtins.types.string: fail("Port spec wait must be a bool, not {0}".format(type(port_spec["wait"]))) def create_port_specs_from_config(config): ports = {} for port_key, port_spec in config["ports"].items(): ports[port_key] = create_port_spec(port_spec) return ports def create_port_spec(port_spec_dict): return PortSpec( number = port_spec_dict["number"], transport_protocol = port_spec_dict["transport_protocol"], application_protocol = port_spec_dict["application_protocol"], wait = port_spec_dict["wait"], ) ================================================ FILE: kurtosis/src/lib/service_config.star ================================================ """ A library for manipulating Service Configs as dictionaries, prior to instantiating the actual ServiceConfig object This is necessary because Starlark structs are largely immutable. To pass a config around and make manipulations to it we represent the Service Config as a dictionary, and then convert it to a ServiceConfig object when we're ready to use it. We additionally support validations to ensure that the dictionary is well-formed. References: - https://docs.kurtosis.com/api-reference/starlark-reference/service-config/ - https://github.com/kurtosis-tech/kurtosis/blob/473d0ee07f2b16c39cf9a453c3c28afdb1e2493d/core/server/api_container/server/startosis_engine/kurtosis_types/service_config/service_config.go """ builtins = import_module("./builtins.star") port_spec_lib = import_module("./port_spec.star") DEFAULT_PRIVATE_IP_ADDRESS_PLACEHOLDER = "KURTOSIS_IP_ADDR_PLACEHOLDER" DEFAULT_MAX_CPU = 2000 # 2 cores DEFAULT_MAX_MEMORY = 2048 # 2 GB def get_service_config_template( name, image, ports = None, public_ports = None, files = None, entrypoint = None, cmd = None, env_vars = None, private_ip_address_placeholder = None, max_cpu = None, min_cpu = None, max_memory = None, min_memory = None, ready_conditions = None, labels = None, user = None, tolerations = None, node_selectors = None): service_config = { "name": name, "image": image, "ports": ports, "public_ports": public_ports, "files": files, "entrypoint": entrypoint, "cmd": cmd, "env_vars": env_vars, "private_ip_address_placeholder": private_ip_address_placeholder, "max_cpu": max_cpu, "min_cpu": min_cpu, "max_memory": max_memory, "min_memory": min_memory, "ready_conditions": ready_conditions, "labels": labels, "user": user, "tolerations": tolerations, "node_selectors": node_selectors, } # validate_service_config_types(service_config) return service_config def validate_service_config_types(service_config): if type(service_config) != builtins.types.dict: fail("Service config must be a dict, not {0}".format(type(service_config))) if type(service_config["name"]) != builtins.types.string: fail("Service config name must be a string, not {0}".format(type(service_config["name"]))) if type(service_config["image"]) != builtins.types.string: fail("Service config image must be a string, not {0}".format(type(service_config["image"]))) if service_config["ports"] != None: if type(service_config["ports"]) != builtins.types.dict: fail("Service config ports must be a dict, not {0}".format(type(service_config["ports"]))) for port_key, port_spec in service_config["ports"].items(): if type(port_key) != builtins.types.string: fail("Service config port key must be an int, not {0}".format(type(port_key))) port_spec_lib.validate_port_spec(port_spec) if service_config["files"] != None: if type(service_config["files"]) != builtins.types.dict: fail("Service config files must be a dict, not {0}".format(type(service_config["files"]))) for path, content in service_config["files"].items(): if type(path) != builtins.types.string: fail("Service config file path must be a string, not {0}".format(type(path))) if type(content) not in [builtins.types.string, builtins.types.directory]: fail("Service config file content must be a string or a Directory object, not {0}".format(type(content))) if service_config["entrypoint"] != None: if type(service_config["entrypoint"]) != builtins.types.list: fail("Service config entrypoint must be a list, not {0}".format(type(service_config["entrypoint"]))) for entrypoint in service_config["entrypoint"]: if type(entrypoint) != builtins.types.string: fail("Service config entrypoint must be a string, not {0}".format(type(entrypoint))) if service_config["cmd"] != None: if type(service_config["cmd"]) != builtins.types.list: fail("Service config cmd must be a list, not {0}".format(type(service_config["cmd"]))) for cmd in service_config["cmd"]: if type(cmd) != builtins.types.string: fail("Service config cmd must be a string, not {0}".format(type(cmd))) if service_config["env_vars"] != None: if type(service_config["env_vars"]) != builtins.types.dict: fail("Service config env_vars must be a dict, not {0}".format(type(service_config["env_vars"]))) for env_var_key, env_var_value in service_config["env_vars"].items(): if type(env_var_key) != builtins.types.string: fail("Service config env_var key must be a string, not {0}".format(type(env_var_key))) if type(env_var_value) != builtins.types.string: fail("Service config env_var value must be a string, not {0}".format(type(env_var_value))) if service_config["private_ip_address_placeholder"] != None: if type(service_config["private_ip_address_placeholder"]) != builtins.types.string: fail("Service config private_ip_address_placeholder must be a string, not {0}".format(type(service_config["private_ip_address_placeholder"]))) if service_config["max_cpu"] != None: if type(service_config["max_cpu"]) != builtins.types.int: fail("Service config max_cpu must be a int, not {0}".format(type(service_config["max_cpu"]))) if service_config["min_cpu"] != None: if type(service_config["min_cpu"]) != builtins.types.int: fail("Service config min_cpu must be a int, not {0}".format(type(service_config["min_cpu"]))) if service_config["max_memory"] != None: if type(service_config["max_memory"]) != builtins.types.int: fail("Service config max_memory must be a int, not {0}".format(type(service_config["max_memory"]))) if service_config["min_memory"] != None: if type(service_config["min_memory"]) != builtins.types.int: fail("Service config min_memory must be a int, not {0}".format(type(service_config["min_memory"]))) # TODO(validation): Implement validation for ready_conditions # TODO(validation): Implement validation for labels # TODO(validation): Implement validation for user # TODO(validation): Implement validation for tolerations # TODO(validation): Implement validation for node_selectors def create_public_port_specs_from_config(config, is_full_node): ports = {} if is_full_node: ports = {} for port_key, port_spec in config["public_ports"].items(): ports[port_key] = port_spec_lib.create_port_spec(port_spec) return ports def create_from_config(config, is_full_node = False): validate_service_config_types(config) return ServiceConfig( image = config["image"], ports = port_spec_lib.create_port_specs_from_config(config), # public port exposed for full node public_ports = create_public_port_specs_from_config(config, is_full_node) if config["public_ports"] else {}, files = config["files"] if config["files"] else {}, entrypoint = config["entrypoint"] if config["entrypoint"] else [], cmd = [" ".join(config["cmd"])] if config["cmd"] else [], env_vars = config["env_vars"] if config["env_vars"] else {}, private_ip_address_placeholder = config["private_ip_address_placeholder"] if config["private_ip_address_placeholder"] else DEFAULT_PRIVATE_IP_ADDRESS_PLACEHOLDER, max_cpu = config["max_cpu"] if config["max_cpu"] else DEFAULT_MAX_CPU, # Needs a default, as 0 does not flag as optional min_cpu = config["min_cpu"] if config["min_cpu"] else 0, max_memory = config["max_memory"] if config["max_memory"] else DEFAULT_MAX_MEMORY, # Needs a default, as 0 does not flag as optional min_memory = config["min_memory"] if config["min_memory"] else 0, #ready_conditions=config['ready_conditions'], Ready conditions not yet supported labels = config["labels"] if config["labels"] else {}, #user=config['user'], User config not yet supported tolerations = config["tolerations"] if config["tolerations"] else [], node_selectors = config["node_selectors"] if config["node_selectors"] else {}, ) ================================================ FILE: kurtosis/src/networks/kurtosis-devnet/README.md ================================================ # kurtosis-devnet This contains all of the required files to spin up a `kurtosis-devnet` on your local machine. ================================================ FILE: kurtosis/src/networks/kurtosis-devnet/network-configs/genesis.json.template ================================================ { "config": { "chainId": {{.CHAIN_ID}}, "homesteadBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "istanbulBlock": 0, "muirGlacierBlock": 0, "berlinBlock": 0, "londonBlock": 0, "arrowGlacierBlock": 0, "grayGlacierBlock": 0, "mergeNetsplitBlock": 0, "shanghaiTime": 0, "cancunTime": 0, "pragueTime": 0, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true, "ethash": {}, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 }, "prague": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 } }, "berachain": { "prague1": { "time": 0, "baseFeeChangeDenominator": 48, "minimumBaseFeeWei": 1000000000, "polDistributorAddress": "0x4200000000000000000000000000000000000042" }, "prague2": { "time": 0, "minimumBaseFeeWei": 0 } } }, "coinbase": "0x0000000000000000000000000000000000000000", "difficulty": "0x0", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", "nonce": "0x0000000000000000", "timestamp": "0x0", "alloc": { "0x4200000000000000000000000000000000000042": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063163db71b1461003857806360644a6b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b610065610060366004610137565b610067565b005b336002600160a01b031461008e57604051632f3a162d60e11b815260040160405180910390fd5b5f8054908061009c836101a5565b909155505060405163999da65b60e01b81526043602160991b019063999da65b906100cd90859085906004016101c9565b5f604051808303815f87803b1580156100e4575f80fd5b505af11580156100f6573d5f803e3d5ffd5b505050507f60b106db8802e863a4a9dc4af78cb0dd63feb55ad4ee60f0453c13309bfdbdd4828260405161012b9291906101c9565b60405180910390a15050565b5f8060208385031215610148575f80fd5b823567ffffffffffffffff81111561015e575f80fd5b8301601f8101851361016e575f80fd5b803567ffffffffffffffff811115610184575f80fd5b856020828401011115610195575f80fd5b6020919091019590945092505050565b5f600182016101c257634e487b7160e01b5f52601160045260245ffd5b5060010190565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c2930abe9036c3b4b2592fab2f2fd516d3698f5c696d82745ddc0af43f7096a764736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" }, "0x4200000000000000000000000000000000000043": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c80634b28f9a214610038578063999da65b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b6100656100603660046100b8565b610067565b005b5f8054908061007583610126565b91905055507fb3a8fa51f8d3759f320e88b7f8d3fb73a2a51b31b3324b37833c4816cf41e7c45f546040516100ac91815260200190565b60405180910390a15050565b5f80602083850312156100c9575f80fd5b823567ffffffffffffffff8111156100df575f80fd5b8301601f810185136100ef575f80fd5b803567ffffffffffffffff811115610105575f80fd5b856020828401011115610116575f80fd5b6020919091019590945092505050565b5f6001820161014357634e487b7160e01b5f52601160045260245ffd5b506001019056fea2646970667358221220350dbb7eed9e4d6e4ff72594b0582b0b2e4c1d6b11c3e5ad382201b47a638cc664736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" }, "0x00000961Ef480Eb55e80D19ad83579A64c007002": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd", "nonce": "0x1", "balance": "0x0", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } }, "0x0000BBdDc7CE488642fb579F8B00f3a590007251": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", "nonce": "0x1", "balance": "0x0", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } }, "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4": { "balance": "0x7E37BE2022C0914B2680000000" }, "0x56898d1aFb10cad584961eb96AcD476C6826e41E": { "balance": "0x12345000000000000000000" }, "0x1e2e53c2451d0f9ED4B7952991BE0c95165D5c01": { "balance": "0x12345000000000000000000" }, "0x3bd0E8f1B1E8Ec99a4E1762F4058F9884C93af31": { "balance": "0x12345000000000000000000" }, "0xD073a84e2ccDF91a9025179330438485E886D206": { "balance": "0x12345000000000000000000" }, "0x8a88215ae882dfA519730c40109556c1C235729f": { "balance": "0x12345000000000000000000" }, "0x1a0A57e5e6a66aD732295ddAF0aed286a4e64310": { "balance": "0x12345000000000000000000" }, "0x185F4Eebd01614aE3d12a5E49b184B054C46d37B": { "balance": "0x12345000000000000000000" }, "0xdb96E9cDD1e457b602f97d33e51736D7a5216496": { "balance": "0x12345000000000000000000" }, "0x44a5FBfa7d6f3Fd92cca01f6764509f8Fc33dfa5": { "balance": "0x12345000000000000000000" }, "0x3649839562C8dA64E6215EB0f5371629Ead9729D": { "balance": "0x12345000000000000000000" }, "0x51e15e71c865FE702C9347610667f83658A20e00": { "balance": "0x12345000000000000000000" }, "0xBC9BC89b295a14F3976234Cc37C73e3D286f3a49": { "balance": "0x12345000000000000000000" }, "0x12De044207a90709Ef2602D3D9D945d64dAe6147": { "balance": "0x12345000000000000000000" }, "0x4Afe0DFDAcc91F0fA2AEe39F9eAd66b64d03EbD6": { "balance": "0x12345000000000000000000" }, "0xBC3c03b4185A6F10618CC4E7B9f4AdD59AB5FbbA": { "balance": "0x12345000000000000000000" }, "0xDc6De65f6070b409125217a12Cf576A208Cc1998": { "balance": "0x12345000000000000000000" }, "0xF60fD8632Fc77E19b3A0637d115d0fdd06F36968": { "balance": "0x12345000000000000000000" }, "0xbcC90AD39D377cA0b7b4F36eC463103E2728C33F": { "balance": "0x12345000000000000000000" }, "0x6F69542fC88fF84C480FFf510aB7108120447247": { "balance": "0x12345000000000000000000" }, "0x2f6eB3D9a41157322dE01A6E707F6F118Cb00A7b": { "balance": "0x12345000000000000000000" }, "0x187bE38A1f448b0F42423151A683dCAea949008B": { "balance": "0x12345000000000000000000" }, "0xA1d283f1a11A36D20FF38F29e12CA8F7Cf8709c1": { "balance": "0x12345000000000000000000" }, "0x868a33C94F91398B6245e1f0E4CF128B2F28714B": { "balance": "0x12345000000000000000000" }, "0x67c942Ef50Fc690eA779067a6A0d444a8234baB5": { "balance": "0x12345000000000000000000" }, "0xDE8E0E641E2Fb52c22460e6a1533c6BD13A00B37": { "balance": "0x12345000000000000000000" }, "0x9beFa0FB7a1A9E6cC7596204DbB8962E87091D64": { "balance": "0x12345000000000000000000" }, "0x62cB9bF32EA104f6D5eBf6879e876439f9492E4B": { "balance": "0x12345000000000000000000" }, "0xdb9cB94B166DfdC9F337EA63b32B448d993d7008": { "balance": "0x12345000000000000000000" }, "0x7c4d7dB81c544B768E1f4782011077202B74B5C0": { "balance": "0x12345000000000000000000" }, "0xaEf63D7F7e2637c99FeA1B63366b244B4da12D70": { "balance": "0x12345000000000000000000" }, "0x3DFb4173ec41EB976260fd689E5AB9772C66beaf": { "balance": "0x12345000000000000000000" }, "0x5145b1B855bca67A119CB02A42aF4Bdbc66B725C": { "balance": "0x12345000000000000000000" }, "0xf4b2eb959A4C4b0E148340676999FC0446D446D4": { "balance": "0x12345000000000000000000" }, "0xb86d37333072eFb48cEaa46C67271A27CA5Bda82": { "balance": "0x12345000000000000000000" }, "0x6CBcF4198fDA91D00fD469340E6DF6df086159e3": { "balance": "0x12345000000000000000000" }, "0xE7F444b5f772281384117674002d540131e533Ca": { "balance": "0x12345000000000000000000" }, "0x719Be866A77CeEc1BaC4FD37910c0975eFd52f55": { "balance": "0x12345000000000000000000" }, "0x0e10cDAd84D788843aF48673C5b260A02ef78742": { "balance": "0x12345000000000000000000" }, "0xcB6632daA65e6c921c2963C37320f63f54fC8fE3": { "balance": "0x12345000000000000000000" }, "0xDe5C7198e2416baB7e7a1EA758858Cd7301740bF": { "balance": "0x12345000000000000000000" }, "0x25fc16D8E2314B305dF05C032E617638284801D6": { "balance": "0x12345000000000000000000" }, "0xD2a3b89AE8D2c3bD39E2F24612ecFCD8600360C9": { "balance": "0x12345000000000000000000" }, "0x2F4fD8a82A1400E654eeEC59b0e588445ffE0F96": { "balance": "0x12345000000000000000000" }, "0x10FdFa4EFc83d6CC42F5ef14c13da8b98E458214": { "balance": "0x12345000000000000000000" }, "0x49cE37B2019bb2d0B8b6a094ef87a6Dd625454A0": { "balance": "0x12345000000000000000000" }, "0x800830F031ab1dd5895a5ec5B561427AD18f9ea8": { "balance": "0x12345000000000000000000" }, "0x3124d9885b11B52c56A2aee610AfCf5740d484F0": { "balance": "0x12345000000000000000000" }, "0xA6177defF3b768b1D678EdF7583b8cf210C777c0": { "balance": "0x12345000000000000000000" }, "0xF99139D2FCc5E25F57B0B91fd382a21B3AFF9cbA": { "balance": "0x12345000000000000000000" }, "0xC4DD08191B4d5173e3698491A11e05b63F9Ee097": { "balance": "0x12345000000000000000000" }, "0xB8865B4B8C56861534CC07ebBD2EA569a9a16323": { "balance": "0x12345000000000000000000" }, "0x2B9935698dc5c19Ab7414AE22f27Da5F4478008a": { "balance": "0x12345000000000000000000" }, "0xAC3c80F41C3049A89Aba8072FFbFc38a90fb6D8c": { "balance": "0x12345000000000000000000" }, "0xD6D4Fb22B91FAa54700852a05698B37d45514166": { "balance": "0x12345000000000000000000" }, "0xAf325Ccc92ae883DEF1634D499d8B093192D7a0c": { "balance": "0x12345000000000000000000" }, "0x7469CeEf99FB67e4990c5F1c085a1B39b2902331": { "balance": "0x12345000000000000000000" }, "0x14DA5251a1EB236238969575ccE943e2Fb0f4AA1": { "balance": "0x12345000000000000000000" }, "0xF9f58a87C3f0B3A4a0592938c80C41a7c659f855": { "balance": "0x12345000000000000000000" }, "0x1CF7e940A657eE706718CF180eb21864DE9672C3": { "balance": "0x12345000000000000000000" }, "0x440C37b22e8D7469128Ea7De6ac2f31419B4A8b1": { "balance": "0x12345000000000000000000" }, "0x4bD04ABA9fc709835b1EE4789195d10E9e8E53F5": { "balance": "0x12345000000000000000000" }, "0x4dC3aC871b22F8a98197B0aae976a8dE08e5Bebe": { "balance": "0x12345000000000000000000" }, "0x1f1D0FCa7e19b799c315d4fDf31bA50e6A2AB153": { "balance": "0x12345000000000000000000" }, "0x28879749Dda99387bdB43295B28bdF251d999F3b": { "balance": "0x12345000000000000000000" }, "0xC4eD09A472B82516daa3A4d8D1E38AE94CF4855C": { "balance": "0x12345000000000000000000" }, "0xf22FbA9cBeB75ED353931418E9eca71EF1Ab9921": { "balance": "0x12345000000000000000000" }, "0xC59D8935c0570E75BA0E55E3C661f535C86e368B": { "balance": "0x12345000000000000000000" }, "0xf97a36c417D33D1fC60a9163A8715e1aecb29102": { "balance": "0x12345000000000000000000" }, "0x4245537d9e3fb36fBBf054247FfFB28b0d931503": { "balance": "0x12345000000000000000000" }, "0xFeb1eafa0154D291e28e393FAF10Bc89e5cCbB22": { "balance": "0x12345000000000000000000" }, "0xf11D16e2EE6BefED82Fbca0b005906E09303aB95": { "balance": "0x12345000000000000000000" }, "0x9C75eD1A37ae420b4FC0a1F4c26B673227Fd3AFa": { "balance": "0x12345000000000000000000" }, "0x6a354C708fd248FD778F6adF75E41AA554700F68": { "balance": "0x12345000000000000000000" }, "0xea94749deFcc40dC5992687974b1C84B1bB9D6df": { "balance": "0x12345000000000000000000" }, "0x7689BE67b205EB5d32811d95D60587Eae4F3036F": { "balance": "0x12345000000000000000000" }, "0xdBfb742BD2e0e6E353cb61E75B9e11257aC8fB1A": { "balance": "0x12345000000000000000000" }, "0x2E5f031578e8FF82199aaF16f42c44D43Fe61819": { "balance": "0x12345000000000000000000" }, "0x611a42A2EF62c2461D123e3F0B64b93938bc4781": { "balance": "0x12345000000000000000000" }, "0x1a0c826048DF0E4661E3c53bBd447d497E3f701F": { "balance": "0x12345000000000000000000" }, "0x7f0E54bc3C1a72405646F5dFbBE0D4565c649fe2": { "balance": "0x12345000000000000000000" }, "0x54e1F990Dc0B7367F1E8eD96dA63BC4bca0E8061": { "balance": "0x12345000000000000000000" }, "0xbE651bc261b9Da5499a24Bf4214fD494c6e1F5Ac": { "balance": "0x12345000000000000000000" }, "0xD3c5dAC705289cD005C402C79C8445a47502d8be": { "balance": "0x12345000000000000000000" }, "0xE5981AA0807eb05611cDb666e32e53b2001bd61d": { "balance": "0x12345000000000000000000" }, "0x0fb648Cb08e21602AF61AF53fE104E29d46433F7": { "balance": "0x12345000000000000000000" }, "0x0474f52d25529c4db5f4E72F43303dA71B3541C6": { "balance": "0x12345000000000000000000" }, "0xe3024d098953661638d59E06f7FcD0B61c424854": { "balance": "0x12345000000000000000000" }, "0x8b1e58f651CacaAa40291d2a6E0a6404d7Ed99e6": { "balance": "0x12345000000000000000000" }, "0x8724C57fb8f38A1FccA7177543dd1D8FcD49E5aa": { "balance": "0x12345000000000000000000" }, "0xd0F043dED28773953562f824334C4cbb84210AE7": { "balance": "0x12345000000000000000000" }, "0xE3d2b9191EaBD3636A5dd057D522335cfae8c7CF": { "balance": "0x12345000000000000000000" }, "0x3f51B3BB6A18141282Ba002F7709c7E2f337F961": { "balance": "0x12345000000000000000000" }, "0xf6B6A52aA9BD788837c6682f47ACE009BD84b6fc": { "balance": "0x12345000000000000000000" }, "0x795B761Db5969B7ba53472d5D37c230C859a472F": { "balance": "0x12345000000000000000000" }, "0x7d7f187C2A05cDDCF700dCF2E02c96E7eF03f9B0": { "balance": "0x12345000000000000000000" }, "0x2d88ECD4d8F4b0A954886eE8C0802aE14684cd07": { "balance": "0x12345000000000000000000" }, "0x92B3feac5b7816Dcef96a303c1D5112271A70D2c": { "balance": "0x12345000000000000000000" }, "0x5DD7bc3BEE395831ce499315ecAFE81DE0556F99": { "balance": "0x12345000000000000000000" }, "0x5227aaebCA3E5e893547A667666E2e4e12Ca20e0": { "balance": "0x12345000000000000000000" }, "0x47575DAE85403cD408d4639068D1187C427B9897": { "balance": "0x12345000000000000000000" }, "0xE69ac59e1DF47291AaB8DEc540C796f81De7c892": { "balance": "0x12345000000000000000000" }, "0xb87fb371Bd3C2093b608cd0E7a8dDD60Bb05C995": { "balance": "0x12345000000000000000000" }, "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": { "balance": "0x0", "nonce": "0x1", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500" }, "0x4e59b44847b379578588920cA78FbF26c0B4956C": { "balance": "0x0", "nonce": "0x1", "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3" }, "0x4242424242424242424242424242424242424242": { "balance": "0x0", "nonce": "0x1", "code": "0x608060405260043610610093575f3560e01c8063577212fe11610066578063c53925d91161004c578063c53925d914610231578063e12cf4cb14610250578063fea7ab7714610263575f80fd5b8063577212fe146101cc5780639eaffa96146101ed575f80fd5b806301ffc9a7146100975780632dfdf0b5146100cb5780633523f9bd14610103578063560036ec14610126575b5f80fd5b3480156100a2575f80fd5b506100b66100b1366004610bb7565b610282565b60405190151581526020015b60405180910390f35b3480156100d6575f80fd5b505f546100ea9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100c2565b34801561010e575f80fd5b5061011860015481565b6040519081526020016100c2565b348015610131575f80fd5b50610193610140366004610c2a565b80516020818301810180516003825292820191909301209152546bffffffffffffffffffffffff8116906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1682565b604080516bffffffffffffffffffffffff909316835273ffffffffffffffffffffffffffffffffffffffff9091166020830152016100c2565b3480156101d7575f80fd5b506101eb6101e6366004610d5f565b61031a565b005b3480156101f8575f80fd5b5061020c610207366004610d5f565b6103e7565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c2565b34801561023c575f80fd5b506101eb61024b366004610d5f565b610428565b6101eb61025e366004610dc1565b61063d565b34801561026e575f80fd5b506101eb61027d366004610e70565b61095c565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061031457507fffffffff0000000000000000000000000000000000000000000000000000000082167f136f920d00000000000000000000000000000000000000000000000000000000145b92915050565b6002828260405161032c929190610ec0565b908152604051908190036020019020543373ffffffffffffffffffffffffffffffffffffffff90911614610383576103837f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b60038282604051610395929190610ec0565b9081526040519081900360200181205f90556103b49083908390610ec0565b604051908190038120907f1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db905f90a25050565b5f600283836040516103fa929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f6003838360405161043b929190610ec0565b908152604051908190036020019020805490915073ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000820416906bffffffffffffffffffffffff163382146104b4576104b47f819a0d0b00000000000000000000000000000000000000000000000000000000610afc565b6bffffffffffffffffffffffff42166104d06201518083610efc565b6bffffffffffffffffffffffff16111561050d5761050d7fe8966d7a00000000000000000000000000000000000000000000000000000000610afc565b5f60028686604051610520929190610ec0565b9081526040519081900360200181205473ffffffffffffffffffffffffffffffffffffffff169150839060029061055a9089908990610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556003906105bf9088908890610ec0565b9081526040519081900360200181205f90556105de9087908790610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a2505050505050565b6030861461066e5761066e7f9f10647200000000000000000000000000000000000000000000000000000000610afc565b6020841461069f5761069f7fb39bca1600000000000000000000000000000000000000000000000000000000610afc565b606082146106d0576106d07f4be6321b00000000000000000000000000000000000000000000000000000000610afc565b5f73ffffffffffffffffffffffffffffffffffffffff16600288886040516106f9929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16036108375773ffffffffffffffffffffffffffffffffffffffff8116610768576107687f51969a7a00000000000000000000000000000000000000000000000000000000610afc565b806002888860405161077b929190610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556107dd9088908890610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff841683525f6020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a261087c565b73ffffffffffffffffffffffffffffffffffffffff81161561087c5761087c7fc4142b4100000000000000000000000000000000000000000000000000000000610afc565b5f610885610b04565b90506509184e72a00067ffffffffffffffff821610156108c8576108c87f0e1eddda00000000000000000000000000000000000000000000000000000000610afc565b5f80547f68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46918a918a918a918a9187918b918b9167ffffffffffffffff16908061091083610f20565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405161094a989796959493929190610f93565b60405180910390a15050505050505050565b5f6002848460405161096f929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690503381146109c7576109c77f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b73ffffffffffffffffffffffffffffffffffffffff8216610a0b57610a0b7fd92e233d00000000000000000000000000000000000000000000000000000000610afc565b5f60038585604051610a1e929190610ec0565b908152604051908190036020018120426bffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff86166c01000000000000000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000161781559150610a969086908690610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff8681168452851660208401524283830152905190917f7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f919081900360600190a25050505050565b805f5260045ffd5b5f610b13633b9aca003461102b565b15610b4157610b417f40567b3800000000000000000000000000000000000000000000000000000000610afc565b5f610b50633b9aca003461103e565b905067ffffffffffffffff811115610b8b57610b8b7f2aa6673400000000000000000000000000000000000000000000000000000000610afc565b610b955f34610b9a565b919050565b5f385f3884865af1610bb35763b12d13eb5f526004601cfd5b5050565b5f60208284031215610bc7575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610bf6575f80fd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215610c3a575f80fd5b813567ffffffffffffffff811115610c50575f80fd5b8201601f81018413610c60575f80fd5b803567ffffffffffffffff811115610c7a57610c7a610bfd565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715610ce657610ce6610bfd565b604052818152828201602001861015610cfd575f80fd5b816020840160208301375f91810160200191909152949350505050565b5f8083601f840112610d2a575f80fd5b50813567ffffffffffffffff811115610d41575f80fd5b602083019150836020828501011115610d58575f80fd5b9250929050565b5f8060208385031215610d70575f80fd5b823567ffffffffffffffff811115610d86575f80fd5b610d9285828601610d1a565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b95575f80fd5b5f805f805f805f6080888a031215610dd7575f80fd5b873567ffffffffffffffff811115610ded575f80fd5b610df98a828b01610d1a565b909850965050602088013567ffffffffffffffff811115610e18575f80fd5b610e248a828b01610d1a565b909650945050604088013567ffffffffffffffff811115610e43575f80fd5b610e4f8a828b01610d1a565b9094509250610e62905060608901610d9e565b905092959891949750929550565b5f805f60408486031215610e82575f80fd5b833567ffffffffffffffff811115610e98575f80fd5b610ea486828701610d1a565b9094509250610eb7905060208501610d9e565b90509250925092565b818382375f9101908152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6bffffffffffffffffffffffff818116838216019081111561031457610314610ecf565b5f67ffffffffffffffff821667ffffffffffffffff8103610f4357610f43610ecf565b60010192915050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60a081525f610fa660a083018a8c610f4c565b8281036020840152610fb981898b610f4c565b905067ffffffffffffffff871660408401528281036060840152610fde818688610f4c565b91505067ffffffffffffffff831660808301529998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261103957611039610ffe565b500690565b5f8261104c5761104c610ffe565b50049056fea164736f6c634300081a000a", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "{{.GENESIS_DEPOSIT_COUNT_HEX}}", "0x0000000000000000000000000000000000000000000000000000000000000001": "{{.GENESIS_DEPOSITS_ROOT}}" } } } } ================================================ FILE: kurtosis/src/networks/networks.star ================================================ el_cl_genesis_data = import_module( "github.com/ethpandaops/ethereum-package/src/prelaunch_data_generator/el_cl_genesis/el_cl_genesis_data.star", ) NETWORKS_DIR_PATH = "/kurtosis/src/networks/" NETWORKS = struct( kurtosis_devnet = "kurtosis-devnet/", ) def get_genesis_data(plan): genesis_file = plan.upload_files( NETWORKS_DIR_PATH + NETWORKS.kurtosis_devnet, "el_cl_genesis_data", ) return el_cl_genesis_data.new_el_cl_genesis_data( genesis_file, # The following fields are not relevant for our testing, but are required by the parent "", # genesis_validators_root 0, # cancun_time 0, # prague_time ) def get_genesis_path(network = "kurtosis-devnet"): return NETWORKS_DIR_PATH + network ================================================ FILE: kurtosis/src/networks/private-testnet-1/.gitkeep ================================================ We can put the testnet genesis files here, this will let people sync nodes easily once the testnet is actually live ================================================ FILE: kurtosis/src/nodes/consensus/beacond/launcher.star ================================================ shared_utils = import_module("github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star") execution = import_module("../../execution/execution.star") node = import_module("./node.star") bash = import_module("../../../lib/bash.star") COMETBFT_RPC_PORT_NUM = 26657 COMETBFT_P2P_PORT_NUM = 26656 COMETBFT_PPROF_PORT_NUM = 6060 METRICS_PORT_NUM = 26660 ENGINE_RPC_PORT_NUM = 8551 NODE_API_PORT_NUM = 3500 # Port IDs COMETBFT_RPC_PORT_ID = "cometbft-rpc" COMETBFT_P2P_PORT_ID = "cometbft-p2p" COMETBFT_GRPC_PORT_ID = "cometbft-grpc" COMETBFT_REST_PORT_ID = "cometbft-rest" COMETBFT_PPROF_PORT_ID = "cometbft-pprof" ENGINE_RPC_PORT_ID = "engine-rpc" METRICS_PORT_ID = "metrics" METRICS_PATH = "/metrics" NODE_API_PORT_ID = "node-api" USED_PORTS = { COMETBFT_RPC_PORT_ID: shared_utils.new_port_spec(COMETBFT_RPC_PORT_NUM, shared_utils.TCP_PROTOCOL), COMETBFT_P2P_PORT_ID: shared_utils.new_port_spec(COMETBFT_P2P_PORT_NUM, shared_utils.TCP_PROTOCOL), COMETBFT_PPROF_PORT_ID: shared_utils.new_port_spec(COMETBFT_PPROF_PORT_NUM, shared_utils.TCP_PROTOCOL), # ENGINE_RPC_PORT_ID: shared_utils.new_port_spec(ENGINE_RPC_PORT_NUM, shared_utils.TCP_PROTOCOL), METRICS_PORT_ID: shared_utils.new_port_spec(METRICS_PORT_NUM, shared_utils.TCP_PROTOCOL, wait = None), NODE_API_PORT_ID: shared_utils.new_port_spec(NODE_API_PORT_NUM, shared_utils.TCP_PROTOCOL), } def get_config(node_struct, engine_dial_url, chain_id, chain_spec, genesis_deposits_root, genesis_deposit_count_hex, entrypoint = [], cmd = [], persistent_peers = "", expose_ports = True, jwt_file = None, kzg_trusted_setup_file = None): exposed_ports = {} if expose_ports: exposed_ports = USED_PORTS files = {} if jwt_file: files["/root/jwt"] = jwt_file if kzg_trusted_setup_file: files["/root/kzg"] = kzg_trusted_setup_file settings = node_struct.consensus_settings node_labels = dict(settings.labels) node_labels["node_type"] = "consensus" config = ServiceConfig( image = node_struct.cl_image, files = files, entrypoint = entrypoint, cmd = cmd, min_cpu = settings.specs.min_cpu, max_cpu = settings.specs.max_cpu, min_memory = settings.specs.min_memory, max_memory = settings.specs.max_memory, env_vars = { "BEACOND_MONIKER": node_struct.cl_service_name, "BEACOND_NET": "VALUE_2", "BEACOND_HOME": "/root/.beacond", "BEACOND_CHAIN_ID": "beacon-kurtosis-{}".format(chain_id), "BEACOND_DEBUG": "false", "BEACOND_KEYRING_BACKEND": "test", "BEACOND_MINIMUM_GAS_PRICE": "0abgt", "BEACOND_ENGINE_DIAL_URL": engine_dial_url, "BEACOND_ETH_CHAIN_ID": str(chain_id), "BEACOND_PERSISTENT_PEERS": persistent_peers, "BEACOND_ENABLE_PROMETHEUS": "true", "CHAIN_SPEC": chain_spec, "BEACOND_CHAIN_SPEC": chain_spec, "WITHDRAWAL_ADDRESS": "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4", "DEPOSIT_AMOUNT": "32000000000", "GENESIS_DEPOSIT_COUNT_HEX": genesis_deposit_count_hex, "GENESIS_DEPOSITS_ROOT": genesis_deposits_root, }, ports = exposed_ports, labels = node_labels, node_selectors = settings.node_selectors, ) return config def perform_genesis_deposits_ceremony(plan, validators, jwt_file, chain_id, chain_spec): num_validators = len(validators) node_peering_info = [] beacond_configs = [] stored_configs = [] for n in range(num_validators): beacond_configs.append("node-beacond-config-{}".format(n)) stored_configs.append(StoreSpec(src = "/tmp/config{}".format(n), name = beacond_configs[n])) stored_configs.append(StoreSpec(src = "/tmp/config_genesis/.beacond/config/genesis.json", name = "cosmos-genesis-final")) multiple_gentx_file = plan.upload_files( src = "./scripts/multiple-premined-deposits-cl.sh", name = "multiple-premined-deposits", description = "Uploading multiple-premined-deposits script", ) multiple_gentx_env_vars = node.get_genesis_env_vars("cl-validator-beaconkit-0", chain_id, chain_spec) multiple_gentx_env_vars["NUM_VALS"] = str(num_validators) plan.print(multiple_gentx_env_vars) plan.print(stored_configs) result = plan.run_sh( run = "chmod +x /app/scripts/multiple-premined-deposits-cl.sh && /app/scripts/multiple-premined-deposits-cl.sh", image = validators[0].cl_image, files = { "/app/scripts": "multiple-premined-deposits", }, env_vars = multiple_gentx_env_vars, store = stored_configs, description = "Collecting beacond genesis files", ) # Return both the StoreSpec list (for names) and the future references (for dependencies) return struct( configs = stored_configs, artifacts = result.files_artifacts, ) def modify_genesis_files_deposits(plan, validators, genesis_files, chain_id, chain_spec, stored_configs): num_validators = len(validators) modify_genesis_file = plan.upload_files( src = "./scripts/modify-genesis-with-deposits.sh", name = "modify-genesis-with-deposits", description = "Uploading modify-genesis-with-deposits script", ) genesis_env_vars = node.get_genesis_env_vars("cl-validator-beaconkit-0", chain_id, chain_spec) # First operation: Get deposit values and store to files deposit_count_store = StoreSpec( src = "/tmp/values/deposit_count.txt", name = "deposit-count", ) deposit_root_store = StoreSpec( src = "/tmp/values/deposit_root.txt", name = "deposit-root", ) # Run the script and store the output files result = plan.run_sh( run = "chmod +x /app/scripts/modify-genesis-with-deposits.sh && /app/scripts/modify-genesis-with-deposits.sh", image = validators[0].cl_image, files = { "/app/scripts": "modify-genesis-with-deposits", "/root/eth_genesis": genesis_files["default"], "/tmp/config_genesis/.beacond/config": "cosmos-genesis-final", }, env_vars = genesis_env_vars, store = [deposit_count_store, deposit_root_store, stored_configs[num_validators]], description = "Running modify genesis with deposits", ) # Second operation: Read deposit count result_one = plan.run_sh( run = "cat /tmp/values/deposit_count.txt", image = validators[0].cl_image, files = { "/tmp/values": "deposit-count", }, description = "Reading deposit count", ) deposit_count = result_one.output.strip().rstrip("\n") plan.print("Deposit count:", deposit_count) # Third operation: Read deposit root result_two = plan.run_sh( run = "cat /tmp/values/deposit_root.txt", image = validators[0].cl_image, files = { "/tmp/values": "deposit-root", }, description = "Reading deposit root", ) deposit_root = result_two.output.strip().rstrip("\n") plan.print("Deposit root:", deposit_root) # Update env vars with parsed values genesis_env_vars["GENESIS_DEPOSIT_COUNT_HEX"] = deposit_count genesis_env_vars["GENESIS_DEPOSITS_ROOT"] = deposit_root return genesis_env_vars def get_persistent_peers(plan, peers): persistent_peers = peers[:] for i in range(len(persistent_peers)): peer_cl_service_name = "cl-seed-beaconkit-{}".format(i) peer_service = plan.get_service(peer_cl_service_name) persistent_peers[i] = persistent_peers[i] + "@" + peer_service.ip_address + ":26656" return ",".join(persistent_peers) def init_consensus_nodes(): genesis_file = "{}/config/genesis.json".format("$BEACOND_HOME") # Check if genesis file exists, if not then initialize the beacond init_node = "if [ ! -f {} ]; then /usr/bin/beacond init --beacon-kit.chain-spec {} --chain-id {} {} --home {}; fi".format(genesis_file, "$BEACOND_CHAIN_SPEC", "$BEACOND_CHAIN_ID", "$BEACOND_MONIKER", "$BEACOND_HOME") add_validator = "/usr/bin/beacond genesis add-premined-deposit {} {} --beacon-kit.chain-spec {} --home {}".format("$DEPOSIT_AMOUNT", "$WITHDRAWAL_ADDRESS", "$BEACOND_CHAIN_SPEC", "$BEACOND_HOME") collect_gentx = "/usr/bin/beacond genesis collect-premined-deposits --beacon-kit.chain-spec {} --home {}".format("$BEACOND_CHAIN_SPEC", "$BEACOND_HOME") return "{} && {} && {}".format(init_node, add_validator, collect_gentx) def create_node_config(plan, node_struct, peers, paired_el_client_name, chain_id, chain_spec, genesis_deposits_root, genesis_deposit_count_hex, jwt_file = None, kzg_trusted_setup_file = None): engine_dial_url = "http://{}:{}".format(paired_el_client_name, execution.ENGINE_RPC_PORT_NUM) persistent_peers = get_persistent_peers(plan, peers) config_settings = node_struct.consensus_settings.config app_settings = node_struct.consensus_settings.app kzg_impl = node_struct.kzg_impl cmd = "{} && {}".format(init_consensus_nodes(), node.start(persistent_peers, False, 0, config_settings, app_settings, kzg_impl)) if node_struct.node_type == "validator": cmd = node.start(persistent_peers, False, node_struct.index, config_settings, app_settings, kzg_impl) elif node_struct.node_type == "seed": cmd = "{} && {}".format(init_consensus_nodes(), node.start(persistent_peers, True, 0, config_settings, app_settings, kzg_impl)) beacond_config = get_config( node_struct, engine_dial_url, chain_id, chain_spec, genesis_deposits_root, genesis_deposit_count_hex, entrypoint = ["bash", "-c"], cmd = [cmd], persistent_peers = persistent_peers, jwt_file = jwt_file, kzg_trusted_setup_file = kzg_trusted_setup_file, ) if node_struct.node_type == "validator": # Add back in the node's config data and overwrite genesis.json with final genesis file beacond_config.files["/root"] = Directory( artifact_names = ["node-beacond-config-{}".format(node_struct.index)], ) beacond_config.files["/root/.tmp_genesis"] = Directory(artifact_names = ["cosmos-genesis-final"]) plan.print(beacond_config) return beacond_config def get_peer_info(plan, cl_service_name): peer_result = bash.exec_on_service(plan, cl_service_name, "/usr/bin/beacond comet show-node-id --home $BEACOND_HOME | tr -d '\n'") return peer_result["output"] def dial_unsafe_peers(plan, seed_service_name, peers): peers_list = [] for cl_service_name, peer_info in peers.items(): p2p_addr = "\"{}@{}:26656\"".format(peer_info, plan.get_service(cl_service_name).ip_address) peers_list.append(p2p_addr) # Split peers_list into groups of 20 peer_groups = [peers_list[i:i + 20] for i in range(0, len(peers_list), 20)] for group in peer_groups: peer_string = ",".join(group) endpoint = "/dial_peers?peers=%5B{}%5D&persistent=false".format(peer_string) curl_command = ["curl", "-X", "GET", "http://localhost:{}{}".format(COMETBFT_RPC_PORT_NUM, endpoint)] exec_recipe = ExecRecipe( command = curl_command, ) plan.exec( service_name = seed_service_name, recipe = exec_recipe, description = "Adding peers to seed node", ) ================================================ FILE: kurtosis/src/nodes/consensus/beacond/node.star ================================================ # Contains functionality for initializing and starting the nodes def start(persistent_peers, is_seed, validator_index, config_settings, app_settings, kzg_impl): mv_genesis = "mv root/.tmp_genesis/genesis.json /root/.beacond/config/genesis.json" set_config = 'sed -i "s/^prometheus = false$/prometheus = {}/" {}/config/config.toml'.format("$BEACOND_ENABLE_PROMETHEUS", "$BEACOND_HOME") set_config += '\nsed -i "s/^pprof_laddr = \\".*\\"/pprof_laddr = \\"0.0.0.0:6060\\"/" {}/config/config.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/\\":26660/\\"0.0.0.0:26660/" {}/config/config.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^flush_throttle_timeout = \\".*\\"$/flush_throttle_timeout = \\"10ms\\"/" {}/config/config.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^timeout_propose = \\".*\\"$/timeout_propose = \\"{}\\"/" {}/config/config.toml'.format(config_settings.timeout_propose, "$BEACOND_HOME") set_config += '\nsed -i "s/^timeout_propose_delta = \\".*\\"$/timeout_propose_delta = \\"500ms\\"/" {}/config/config.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^timeout_prevote = \\".*\\"$/timeout_prevote = \\"{}\\"/" {}/config/config.toml'.format(config_settings.timeout_prevote, "$BEACOND_HOME") set_config += '\nsed -i "s/^timeout_precommit = \\".*\\"$/timeout_precommit = \\"{}\\"/" {}/config/config.toml'.format(config_settings.timeout_precommit, "$BEACOND_HOME") set_config += '\nsed -i "s/^addr_book_strict = .*/addr_book_strict = false/" "{}/config/config.toml"'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^unsafe = false$/unsafe = true/" "{}/config/config.toml"'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^type = \\".*\\"$/type = \\"nop\\"/" {}/config/config.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^discard_abci_responses = false$/discard_abci_responses = true/" {}/config/config.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^# other sinks such as Prometheus.\nenabled = false$/# other sinks such as Prometheus.\nenabled = true/" {}/config/app.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^prometheus-retention-time = 0$/prometheus-retention-time = 60/" {}/config/app.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^payload-timeout = \\".*\\"$/payload-timeout = \\"{}\\"/" {}/config/app.toml'.format(app_settings.payload_timeout, "$BEACOND_HOME") set_config += '\nsed -i "s/^suggested-fee-recipient = \\"0x0000000000000000000000000000000000000000\\"/suggested-fee-recipient = \\"0x$(printf \"%040d\" {})\\"/" {}/config/app.toml'.format(validator_index, "$BEACOND_HOME") persistent_peers_option = "" seed_option = "" if persistent_peers != "": persistent_peers_option = "--p2p.seeds {}".format("$BEACOND_PERSISTENT_PEERS") if is_seed: set_config += '\nsed -i "s/^max_num_inbound_peers = 40$/max_num_inbound_peers = 200/" {}/config/config.toml'.format("$BEACOND_HOME") set_config += '\nsed -i "s/^max_num_outbound_peers = 10$/max_num_outbound_peers = 200/" {}/config/config.toml'.format("$BEACOND_HOME") seed_option = "--p2p.seed_mode true" else: set_config += '\nsed -i "s/^max_num_inbound_peers = 40$/max_num_inbound_peers = {}/" {}/config/config.toml'.format(config_settings.max_num_inbound_peers, "$BEACOND_HOME") set_config += '\nsed -i "s/^max_num_outbound_peers = 10$/max_num_outbound_peers = {}/" {}/config/config.toml'.format(config_settings.max_num_outbound_peers, "$BEACOND_HOME") start_node = "/usr/bin/beacond start --rpc.laddr tcp://0.0.0.0:26657 \ --beacon-kit.chain-spec={} \ --beacon-kit.engine.jwt-secret-path=/root/jwt/jwt-secret.hex \ --beacon-kit.kzg.trusted-setup-path=/root/kzg/kzg-trusted-setup.json \ --beacon-kit.kzg.implementation={} \ --beacon-kit.engine.rpc-dial-url {} \ --beacon-kit.node-api.enabled --beacon-kit.node-api.logging --beacon-kit.node-api.address 0.0.0.0:3500 \ --pruning=nothing \ {} {}".format("$BEACOND_CHAIN_SPEC", kzg_impl, "$BEACOND_ENGINE_DIAL_URL", seed_option, persistent_peers_option) return "{} && {} && {}".format(mv_genesis, set_config, start_node) def get_genesis_env_vars(cl_service_name, chain_id, chain_spec): return { "BEACOND_MONIKER": cl_service_name, "BEACOND_NET": "VALUE_2", "BEACOND_HOME": "/root/.beacond", "BEACOND_CHAIN_ID": "beacon-kurtosis-{}".format(chain_id), "BEACOND_DEBUG": "false", "BEACOND_KEYRING_BACKEND": "test", "BEACOND_MINIMUM_GAS_PRICE": "0abgt", "BEACOND_ETH_CHAIN_ID": str(chain_id), "BEACOND_ENABLE_PROMETHEUS": "true", "ETH_GENESIS": "/root/eth_genesis/genesis.json", # For devnet/testing purposes, we use the same withdrawal address for all validators. # In production, each validator should use an address derived from their own withdrawal credentials. # This is fine for a local development network. "WITHDRAWAL_ADDRESS": "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4", "DEPOSIT_AMOUNT": "32000000000", "BEACOND_CHAIN_SPEC": chain_spec, "CHAIN_SPEC": chain_spec, } ================================================ FILE: kurtosis/src/nodes/consensus/beacond/scripts/modify-genesis-with-deposits.sh ================================================ #!/usr/bin/env bash # SPDX-License-Identifier: BUSL-1.1 # # Copyright (C) 2025, Berachain Foundation. All rights reserved. # Use of this software is governed by the Business Source License included # in the LICENSE file of this repository and at www.mariadb.com/bsl11. # # ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY # TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER # VERSIONS OF THE LICENSED WORK. # # THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF # LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF # LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). # # TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON # AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, # EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND # TITLE. # Sets the deposit storage in the new eth-genesis file in the home directory. /usr/bin/beacond genesis set-deposit-storage $ETH_GENESIS --beacon-kit.chain-spec $CHAIN_SPEC --home /tmp/config_genesis/.beacond # Get values directly from the storage fields DEPOSIT_COUNT=$(jq -r '.alloc["0x4242424242424242424242424242424242424242"].storage["0x0000000000000000000000000000000000000000000000000000000000000000"]' /tmp/config_genesis/.beacond/genesis.json) DEPOSIT_ROOT=$(jq -r '.alloc["0x4242424242424242424242424242424242424242"].storage["0x0000000000000000000000000000000000000000000000000000000000000001"]' /tmp/config_genesis/.beacond/genesis.json) /usr/bin/beacond genesis execution-payload /tmp/config_genesis/.beacond/genesis.json --beacon-kit.chain-spec $CHAIN_SPEC --home /tmp/config_genesis/.beacond # Write each value to separate files for easier parsing mkdir -p /tmp/values printf "%s" "$DEPOSIT_COUNT" > /tmp/values/deposit_count.txt printf "%s" "$DEPOSIT_ROOT" > /tmp/values/deposit_root.txt ================================================ FILE: kurtosis/src/nodes/consensus/beacond/scripts/multiple-premined-deposits-cl.sh ================================================ #!/usr/bin/env bash # SPDX-License-Identifier: BUSL-1.1 # # Copyright (C) 2025, Berachain Foundation. All rights reserved. # Use of this software is governed by the Business Source License included # in the LICENSE file of this repository and at www.mariadb.com/bsl11. # # ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY # TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER # VERSIONS OF THE LICENSED WORK. # # THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF # LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF # LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). # # TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON # AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, # EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND # TITLE. /usr/bin/beacond init --beacon-kit.chain-spec $CHAIN_SPEC --chain-id $BEACOND_CHAIN_ID $BEACOND_MONIKER --home /tmp/config0/.beacond /usr/bin/beacond genesis add-premined-deposit $DEPOSIT_AMOUNT $WITHDRAWAL_ADDRESS --beacon-kit.chain-spec $CHAIN_SPEC --home /tmp/config0/.beacond cp -r /tmp/config0 /tmp/config_genesis for ((i=1; i<$NUM_VALS; i++)); do BEACOND_HOME=/tmp/config${i}/.beacond echo $BEACOND_HOME BEACOND_MONIKER=cl-validator-beaconkit-${i} /usr/bin/beacond init --beacon-kit.chain-spec $CHAIN_SPEC --chain-id $BEACOND_CHAIN_ID $BEACOND_MONIKER --home $BEACOND_HOME /usr/bin/beacond genesis add-premined-deposit $DEPOSIT_AMOUNT $WITHDRAWAL_ADDRESS --beacon-kit.chain-spec $CHAIN_SPEC --home $BEACOND_HOME cp -r /tmp/config${i}/.beacond/config/premined-deposits/premined-deposit* /tmp/config_genesis/.beacond/config/premined-deposits/ done /usr/bin/beacond genesis collect-premined-deposits --beacon-kit.chain-spec $CHAIN_SPEC --home /tmp/config_genesis/.beacond ================================================ FILE: kurtosis/src/nodes/consensus/types.star ================================================ CLIENTS = struct( beacond = "beacond", ) ================================================ FILE: kurtosis/src/nodes/execution/config.star ================================================ port_spec_lib = import_module("../../lib/port_spec.star") shared_utils = import_module("github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star") # ETH Execution constants RPC_PORT_NUM = 8545 WS_PORT_NUM = 8546 DISCOVERY_PORT_NUM = 30303 ENGINE_RPC_PORT_NUM = 8551 METRICS_PORT_NUM = 9001 # Port IDs RPC_PORT_ID = "eth-json-rpc" WS_PORT_ID = "eth-json-rpc-ws" TCP_DISCOVERY_PORT_ID = "tcp-discovery" UDP_DISCOVERY_PORT_ID = "udp-discovery" ENGINE_RPC_PORT_ID = "engine-rpc" ENGINE_WS_PORT_ID = "engineWs" METRICS_PORT_ID = "metrics" METRICS_PATH = "/debug/metrics/prometheus" # The dirpath of the execution data directory on the client container EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER = "/data/execution-data" USED_PORTS = { RPC_PORT_ID: shared_utils.new_port_spec(RPC_PORT_NUM, shared_utils.TCP_PROTOCOL), WS_PORT_ID: shared_utils.new_port_spec(WS_PORT_NUM, shared_utils.TCP_PROTOCOL), TCP_DISCOVERY_PORT_ID: shared_utils.new_port_spec( DISCOVERY_PORT_NUM, shared_utils.TCP_PROTOCOL, ), UDP_DISCOVERY_PORT_ID: shared_utils.new_port_spec( DISCOVERY_PORT_NUM, shared_utils.UDP_PROTOCOL, ), ENGINE_RPC_PORT_ID: shared_utils.new_port_spec( ENGINE_RPC_PORT_NUM, shared_utils.TCP_PROTOCOL, ), METRICS_PORT_ID: shared_utils.new_port_spec( METRICS_PORT_NUM, shared_utils.TCP_PROTOCOL, ), } USED_PORTS_TEMPLATE = { RPC_PORT_ID: port_spec_lib.get_port_spec_template(RPC_PORT_NUM, shared_utils.TCP_PROTOCOL), WS_PORT_ID: port_spec_lib.get_port_spec_template(WS_PORT_NUM, shared_utils.TCP_PROTOCOL), TCP_DISCOVERY_PORT_ID: port_spec_lib.get_port_spec_template( DISCOVERY_PORT_NUM, shared_utils.TCP_PROTOCOL, ), UDP_DISCOVERY_PORT_ID: port_spec_lib.get_port_spec_template( DISCOVERY_PORT_NUM, shared_utils.UDP_PROTOCOL, ), ENGINE_RPC_PORT_ID: port_spec_lib.get_port_spec_template( ENGINE_RPC_PORT_NUM, shared_utils.TCP_PROTOCOL, ), METRICS_PORT_ID: port_spec_lib.get_port_spec_template( METRICS_PORT_NUM, shared_utils.TCP_PROTOCOL, ), } ================================================ FILE: kurtosis/src/nodes/execution/execution.star ================================================ constants = import_module("../../constants.star") service_config_lib = import_module("../../lib/service_config.star") builtins = import_module("../../lib/builtins.star") port_spec_lib = import_module("../../lib/port_spec.star") shared_utils = import_module("github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star") RPC_PORT_NUM = 8545 ENGINE_RPC_PORT_NUM = 8551 PUBLIC_RPC_PORT_NUM = 8547 # Port IDs RPC_PORT_ID = "eth-json-rpc" # Because structs are immutable, we pass around a map to allow full modification up until we create the final ServiceConfig def get_default_service_config(plan, node_struct, node_module, chain_id, chain_spec, genesis_files): settings = node_struct.execution_settings node_labels = dict(settings.labels) node_labels["node_type"] = "execution" # Get the default genesis file default_genesis_file = genesis_files["default"] # Create a copy of the module files files_dict = dict(node_module.FILES) # Default path for all supported clients files_dict["/root/genesis"] = Directory( artifact_names = [default_genesis_file], ) # Define common parameters common_params = { "name": node_struct.el_service_name, "image": node_struct.el_image, "ports": node_module.USED_PORTS_TEMPLATE, "entrypoint": node_module.ENTRYPOINT, "cmd": node_module.CMD, "env_vars": { "CHAIN_ID": str(chain_id), "CHAIN_SPEC": chain_spec, }, "files": files_dict, "min_cpu": settings.specs.min_cpu, "max_cpu": settings.specs.max_cpu, "min_memory": settings.specs.min_memory, "max_memory": settings.specs.max_memory, "labels": node_labels, "node_selectors": settings.node_selectors, } # Get the service config template sc = service_config_lib.get_service_config_template(**common_params) return sc def upload_global_files(plan, node_modules, chain_id): jwt_file = plan.upload_files( src = constants.JWT_FILEPATH, name = "jwt_file", ) kzg_trusted_setup_file = plan.upload_files( src = constants.KZG_TRUSTED_SETUP_FILEPATH, name = "kzg_trusted_setup", ) for node_module in node_modules.values(): for global_file in node_module.GLOBAL_FILES: plan.upload_files( src = global_file[0], name = global_file[1], ) return jwt_file, kzg_trusted_setup_file def get_enode_addr(plan, el_service_name): extract_statement = {"enode": """.result.enode | split("?") | .[0]"""} request_recipe = PostHttpRequestRecipe( endpoint = "", body = '{"method":"admin_nodeInfo","params":[],"id":1,"jsonrpc":"2.0"}', content_type = "application/json", port_id = RPC_PORT_ID, extract = extract_statement, ) response = plan.request( service_name = el_service_name, recipe = request_recipe, ) enode = response["extract.enode"] return enode def set_max_peers(node_module, config, max_peers): node_module.set_max_peers(config, max_peers) return config def add_bootnodes(node_module, config, bootnodes): if type(bootnodes) == builtins.types.list: if len(bootnodes) > 0: cmdList = config["cmd"][:] cmdList.append(node_module.BOOTNODE_CMD) config["cmd"] = cmdList bootnodes_str = ",".join(bootnodes) config["cmd"].append(bootnodes_str) elif type(bootnodes) == builtins.types.str: if len(bootnodes) > 0: config["cmd"].append(node_module.BOOTNODE_CMD) config["cmd"].append(bootnodes) else: fail("Bootnodes was not a list or string, but instead a {}", type(bootnodes)) return config def deploy_nodes(plan, configs, is_full_node = False): service_configs = {} for config in configs: service_configs[config["name"]] = service_config_lib.create_from_config(config, is_full_node) return plan.add_services( configs = service_configs, ) def generate_node_config(plan, node_modules, node_struct, chain_id, chain_spec, genesis_files, bootnode_enode_addrs = []): node_module = node_modules[node_struct.el_type] # 4a. Launch EL el_service_config_dict = get_default_service_config(plan, node_struct, node_module, chain_id, chain_spec, genesis_files) if node_struct.node_type == "seed": el_service_config_dict = set_max_peers(node_module, el_service_config_dict, "200") else: el_service_config_dict = add_bootnodes(node_module, el_service_config_dict, bootnode_enode_addrs) return el_service_config_dict def add_peer(plan, el_service_name, enode_addr): """Adds a peer to the given EL node via admin_addPeer JSON-RPC.""" request_recipe = PostHttpRequestRecipe( endpoint = "", body = '{{"method":"admin_addPeer","params":["{}"],"id":1,"jsonrpc":"2.0"}}'.format(enode_addr), content_type = "application/json", port_id = RPC_PORT_ID, ) plan.request( service_name = el_service_name, recipe = request_recipe, ) def add_metrics(metrics_enabled_services, node, el_service_name, el_client_service, node_modules): metrics_enabled_services.append({ "name": el_service_name, "service": el_client_service, "metrics_path": node_modules[node.el_type].METRICS_PATH, }) return metrics_enabled_services ================================================ FILE: kurtosis/src/nodes/execution/reth/config.star ================================================ global_constants = import_module("../../../constants.star") defaults = import_module("./../config.star") GLOBAL_LOG_LEVEL = global_constants.GLOBAL_LOG_LEVEL KURTOSIS_IP_ADDRESS_PLACEHOLDER = global_constants.KURTOSIS_IP_ADDRESS_PLACEHOLDER # The dirpath of the execution data directory on the client container EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER = defaults.EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER NODE_CONFIG_ARTIFACT_NAME = "reth-config" CONFIG_FILENAME = "reth-config.toml" GENESIS_FILENAME = "genesis.json" # The files that only need to be uploaded once to be read by every node # NOTE: THIS MUST REFERENCE THE FILEPATH RELATIVE TO execution.star GLOBAL_FILES = [ ("./reth/reth-config.toml", NODE_CONFIG_ARTIFACT_NAME), ] WS_PORT_NUM = defaults.WS_PORT_NUM ENGINE_RPC_PORT_NUM = defaults.ENGINE_RPC_PORT_NUM METRICS_PORT_NUM = defaults.METRICS_PORT_NUM METRICS_PATH = defaults.METRICS_PATH ENTRYPOINT = ["sh", "-c"] FILES = { "/root/.reth": NODE_CONFIG_ARTIFACT_NAME, "/root/genesis": "genesis_file", "/jwt": "jwt_file", } CMD = [ "bera-reth", "init", "--datadir", EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER, "--chain", "/root/genesis/{}".format(GENESIS_FILENAME), "&&", "bera-reth", "node", "--datadir", EXECUTION_DATA_DIRPATH_ON_CLIENT_CONTAINER, "--chain", "/root/genesis/{}".format(GENESIS_FILENAME), "--http", "--http.addr", "0.0.0.0", "--http.corsdomain", "'*'", "--http.api", "admin,eth,net,web3,txpool,debug,trace", "--ws", "--ws.addr", "0.0.0.0", "--ws.port", str(WS_PORT_NUM), "--ws.api", "net,eth", "--ws.origins", "'*'", "--authrpc.port", str(ENGINE_RPC_PORT_NUM), "--authrpc.jwtsecret", global_constants.JWT_MOUNT_PATH_ON_CONTAINER, "--authrpc.addr", "0.0.0.0", "--metrics", "0.0.0.0:{0}".format(METRICS_PORT_NUM), # "--config", CONFIG_LOCATION, "--nat", "extip:" + KURTOSIS_IP_ADDRESS_PLACEHOLDER, "--builder.deadline", "2", "--builder.max-tasks", "20", "--txpool.pending-max-count", "100000", "--txpool.pending-max-size", "100", "--txpool.basefee-max-count", "100000", "--txpool.basefee-max-size", "100", "--txpool.queued-max-count", "100000", "--txpool.queued-max-size", "100", "--txpool.max-account-slots", "1000", "--txpool.max-cached-entries", "1000", "--rpc-cache.max-receipts", "10000", ] BOOTNODE_CMD = "--bootnodes" MAX_PEERS_OUTBOUND_CMD = "--max-outbound-peers" MAX_PEERS_INBOUND_CMD = "--max-inbound-peers" # Modify command flag --verbosity to change the verbosity level VERBOSITY_LEVELS = { GLOBAL_LOG_LEVEL.error: "1", GLOBAL_LOG_LEVEL.warn: "2", GLOBAL_LOG_LEVEL.info: "3", GLOBAL_LOG_LEVEL.debug: "4", GLOBAL_LOG_LEVEL.trace: "5", } USED_PORTS = defaults.USED_PORTS USED_PORTS_TEMPLATE = defaults.USED_PORTS_TEMPLATE def set_max_peers(config, max_peers): cmd_list = config["cmd"][:] cmd_list.append(MAX_PEERS_OUTBOUND_CMD) cmd_list.append(max_peers) cmd_list.append(MAX_PEERS_INBOUND_CMD) cmd_list.append(max_peers) config["cmd"] = cmd_list return config ================================================ FILE: kurtosis/src/nodes/execution/reth/reth-config.toml ================================================ [stages.headers] downloader_max_concurrent_requests = 100 downloader_min_concurrent_requests = 5 downloader_max_buffered_responses = 100 downloader_request_limit = 1000 commit_threshold = 10000 [stages.bodies] downloader_request_limit = 200 downloader_stream_batch_size = 1000 downloader_max_buffered_blocks_size_bytes = 2147483648 downloader_min_concurrent_requests = 5 downloader_max_concurrent_requests = 100 [stages.sender_recovery] commit_threshold = 5000000 [stages.execution] max_blocks = 500000 max_changes = 5000000 max_cumulative_gas = 1500000000000 max_duration = "10m" [stages.account_hashing] clean_threshold = 500000 commit_threshold = 100000 [stages.storage_hashing] clean_threshold = 500000 commit_threshold = 100000 [stages.merkle] clean_threshold = 50000 [stages.transaction_lookup] chunk_size = 5000000 [stages.index_account_history] commit_threshold = 100000 [stages.index_storage_history] commit_threshold = 100000 [peers] refill_slots_interval = "5s" trusted_nodes = [] connect_trusted_nodes_only = false max_backoff_count = 5 ban_duration = "12h" [peers.connection_info] max_outbound = 100 max_inbound = 30 max_concurrent_outbound_dials = 10 [peers.reputation_weights] bad_message = -16384 bad_block = -16384 bad_transactions = -16384 already_seen_transactions = 0 timeout = -4096 bad_protocol = -2147483648 failed_to_connect = -25600 dropped = -4096 bad_announcement = -1024 [peers.backoff_durations] low = "30s" medium = "3m" high = "15m" max = "1h" [sessions] session_command_buffer = 32 session_event_buffer = 260 [sessions.limits] [sessions.initial_internal_request_timeout] secs = 20 nanos = 0 [sessions.protocol_breach_request_timeout] secs = 120 nanos = 0 ================================================ FILE: kurtosis/src/nodes/jwt-secret.hex ================================================ 0x1b8d34037ac04570b76cb1a13d1db17729a5b6a90f10497b2bc4422fbd39615a ================================================ FILE: kurtosis/src/nodes/kzg-trusted-setup.json ================================================ { "g1_lagrange": [ "0xa0413c0dcafec6dbc9f47d66785cf1e8c981044f7d13cfe3e4fcbb71b5408dfde6312493cb3c1d30516cb3ca88c03654", "0x8b997fb25730d661918371bb41f2a6e899cac23f04fc5365800b75433c0a953250e15e7a98fb5ca5cc56a8cd34c20c57", "0x83302852db89424d5699f3f157e79e91dc1380f8d5895c5a772bb4ea3a5928e7c26c07db6775203ce33e62a114adaa99", "0xa759c48b7e4a685e735c01e5aa6ef9c248705001f470f9ad856cd87806983e917a8742a3bd5ee27db8d76080269b7c83", "0x967f8dc45ebc3be14c8705f43249a30ff48e96205fb02ae28daeab47b72eb3f45df0625928582aa1eb4368381c33e127", "0xa418eb1e9fb84cb32b370610f56f3cb470706a40ac5a47c411c464299c45c91f25b63ae3fcd623172aa0f273c0526c13", "0x8f44e3f0387293bc7931e978165abbaed08f53acd72a0a23ac85f6da0091196b886233bcee5b4a194db02f3d5a9b3f78", "0x97173434b336be73c89412a6d70d416e170ea355bf1956c32d464090b107c090ef2d4e1a467a5632fbc332eeb679bf2d", "0xa24052ad8d55ad04bc5d951f78e14213435681594110fd18173482609d5019105b8045182d53ffce4fc29fc8810516c1", "0xb950768136b260277590b5bec3f56bbc2f7a8bc383d44ce8600e85bf8cf19f479898bcc999d96dfbd2001ede01d94949", "0x92ab8077871037bd3b57b95cbb9fb10eb11efde9191690dcac655356986fd02841d8fdb25396faa0feadfe3f50baf56d", "0xa79b096dff98038ac30f91112dd14b78f8ad428268af36d20c292e2b3b6d9ed4fb28480bb04e465071cc67d05786b6d1", "0xb9ff71461328f370ce68bf591aa7fb13027044f42a575517f3319e2be4aa4843fa281e756d0aa5645428d6dfa857cef2", "0x8d765808c00b3543ff182e2d159c38ae174b12d1314da88ea08e13bd9d1c37184cb515e6bf6420531b5d41767987d7ce", "0xb8c9a837d20c3b53e6f578e4a257bb7ef8fc43178614ec2a154915b267ad2be135981d01ed2ee1b5fbd9d9bb27f0800a", "0xa9773d92cf23f65f98ef68f6cf95c72b53d0683af2f9bf886bb9036e4a38184b1131b26fd24397910b494fbef856f3aa", "0xb41ebe38962d112da4a01bf101cb248d808fbd50aaf749fc7c151cf332032eb3e3bdbd716db899724b734d392f26c412", "0x90fbb030167fb47dcc13d604a726c0339418567c1d287d1d87423fa0cb92eec3455fbb46bcbe2e697144a2d3972142e4", "0xb11d298bd167464b35fb923520d14832bd9ed50ed841bf6d7618424fd6f3699190af21759e351b89142d355952149da1", "0x8bc36066f69dc89f7c4d1e58d67497675050c6aa002244cebd9fc957ec5e364c46bab4735ea3db02b73b3ca43c96e019", "0xab7ab92c5d4d773068e485aa5831941ebd63db7118674ca38089635f3b4186833af2455a6fb9ed2b745df53b3ce96727", "0xaf191ca3089892cb943cd97cf11a51f38e38bd9be50844a4e8da99f27e305e876f9ed4ab0628e8ae3939066b7d34a15f", "0xa3204c1747feabc2c11339a542195e7cb6628fd3964f846e71e2e3f2d6bb379a5e51700682ea1844eba12756adb13216", "0x903a29883846b7c50c15968b20e30c471aeac07b872c40a4d19eb1a42da18b649d5bbfde4b4cf6225d215a461b0deb6d", "0x8e6e9c15ffbf1e16e5865a5fef7ed751dc81957a9757b535cb38b649e1098cda25d42381dc4f776778573cdf90c3e6e0", "0xa8f6dd26100b512a8c96c52e00715c4b2cb9ac457f17aed8ffe1cf1ea524068fe5a1ddf218149845fc1417b789ecfc98", "0xa5b0ffc819451ea639cfd1c18cbc9365cc79368d3b2e736c0ae54eba2f0801e6eb0ee14a5f373f4a70ca463bdb696c09", "0x879f91ccd56a1b9736fbfd20d8747354da743fb121f0e308a0d298ff0d9344431890e41da66b5009af3f442c636b4f43", "0x81bf3a2d9755e206b515a508ac4d1109bf933c282a46a4ae4a1b4cb4a94e1d23642fad6bd452428845afa155742ade7e", "0x8de778d4742f945df40004964e165592f9c6b1946263adcdd5a88b00244bda46c7bb49098c8eb6b3d97a0dd46148a8ca", "0xb7a57b21d13121907ee28c5c1f80ee2e3e83a3135a8101e933cf57171209a96173ff5037f5af606e9fd6d066de6ed693", "0xb0877d1963fd9200414a38753dffd9f23a10eb3198912790d7eddbc9f6b477019d52ddd4ebdcb9f60818db076938a5a9", "0x88da2d7a6611bc16adc55fc1c377480c828aba4496c645e3efe0e1a67f333c05a0307f7f1d2df8ac013602c655c6e209", "0x95719eb02e8a9dede1a888c656a778b1c69b7716fbe3d1538fe8afd4a1bc972183c7d32aa7d6073376f7701df80116d8", "0x8e8a1ca971f2444b35af3376e85dccda3abb8e8e11d095d0a4c37628dfe5d3e043a377c3de68289ef142e4308e9941a0", "0xb720caaff02f6d798ac84c4f527203e823ff685869e3943c979e388e1c34c3f77f5c242c6daa7e3b30e511aab917b866", "0x86040d55809afeec10e315d1ad950d269d37cfee8c144cd8dd4126459e3b15a53b3e68df5981df3c2346d23c7b4baaf4", "0x82d8cabf13ab853db0377504f0aec00dba3a5cd3119787e8ad378ddf2c40b022ecfc67c642b7acc8c1e3dd03ab50993e", "0xb8d873927936719d2484cd03a6687d65697e17dcf4f0d5aed6f5e4750f52ef2133d4645894e7ebfc4ef6ce6788d404c8", "0xb1235594dbb15b674a419ff2b2deb644ad2a93791ca05af402823f87114483d6aa1689b7a9bea0f547ad12fe270e4344", "0xa53fda86571b0651f5affb74312551a082fffc0385cfd24c1d779985b72a5b1cf7c78b42b4f7e51e77055f8e5e915b00", "0xb579adcfd9c6ef916a5a999e77a0cb21d378c4ea67e13b7c58709d5da23a56c2e54218691fc4ac39a4a3d74f88cc31f7", "0xab79e584011713e8a2f583e483a91a0c2a40771b77d91475825b5acbea82db4262132901cb3e4a108c46d7c9ee217a4e", "0xa0fe58ea9eb982d7654c8aaf9366230578fc1362f6faae0594f8b9e659bcb405dff4aac0c7888bbe07f614ecf0d800a6", "0x867e50e74281f28ecd4925560e2e7a6f8911b135557b688254623acce0dbc41e23ac3e706a184a45d54c586edc416eb0", "0x89f81b61adda20ea9d0b387a36d0ab073dc7c7cbff518501962038be19867042f11fcc7ff78096e5d3b68c6d8dc04d9b", "0xa58ee91bb556d43cf01f1398c5811f76dc0f11efdd569eed9ef178b3b0715e122060ec8f945b4dbf6eebfa2b90af6fa6", "0xac460be540f4c840def2eef19fc754a9af34608d107cbadb53334cf194cc91138d53b9538fcd0ec970b5d4aa455b224a", "0xb09b91f929de52c09d48ca0893be6eb44e2f5210a6c394689dc1f7729d4be4e11d0474b178e80cea8c2ac0d081f0e811", "0x8d37a442a76b06a02a4e64c2504aea72c8b9b020ab7bcc94580fe2b9603c7c50d7b1e9d70d2a7daea19c68667e8f8c31", "0xa9838d4c4e3f3a0075a952cf7dd623307ec633fcc81a7cf9e52e66c31780de33dbb3d74c320dc7f0a4b72f7a49949515", "0xa44766b6251af458fe4f5f9ed1e02950f35703520b8656f09fc42d9a2d38a700c11a7c8a0436ac2e5e9f053d0bb8ff91", "0xad78d9481c840f5202546bea0d13c776826feb8b1b7c72e83d99a947622f0bf38a4208551c4c41beb1270d7792075457", "0xb619ffa8733b470039451e224b777845021e8dc1125f247a4ff2476cc774657d0ff9c5279da841fc1236047de9d81c60", "0xaf760b0a30a1d6af3bc5cd6686f396bd41779aeeb6e0d70a09349bd5da17ca2e7965afc5c8ec22744198fbe3f02fb331", "0xa0cc209abdb768b589fcb7b376b6e1cac07743288c95a1cf1a0354b47f0cf91fca78a75c1fcafa6f5926d6c379116608", "0x864add673c89c41c754eeb3cd8dcff5cdde1d739fce65c30e474a082bb5d813cba6412e61154ce88fdb6c12c5d9be35b", "0xb091443b0ce279327dc37cb484e9a5b69b257a714ce21895d67539172f95ffa326903747b64a3649e99aea7bb10d03f7", "0xa8c452b8c4ca8e0a61942a8e08e28f17fb0ef4c5b018b4e6d1a64038280afa2bf1169202f05f14af24a06ca72f448ccd", "0xa23c24721d18bc48d5dcf70effcbef89a7ae24e67158d70ae1d8169ee75d9a051d34b14e9cf06488bac324fe58549f26", "0x92a730e30eb5f3231feb85f6720489dbb1afd42c43f05a1610c6b3c67bb949ec8fde507e924498f4ffc646f7b07d9123", "0x8dbe5abf4031ec9ba6bb06d1a47dd1121fb9e03b652804069250967fd5e9577d0039e233441b7f837a7c9d67ba18c28e", "0xaa456bcfef6a21bb88181482b279df260297b3778e84594ebddbdf337e85d9e3d46ca1d0b516622fb0b103df8ec519b7", "0xa3b31ae621bd210a2b767e0e6f22eb28fe3c4943498a7e91753225426168b9a26da0e02f1dc5264da53a5ad240d9f51b", "0xaa8d66857127e6e71874ce2202923385a7d2818b84cb73a6c42d71afe70972a70c6bdd2aad1a6e8c5e4ca728382a8ea8", "0xac7e8e7a82f439127a5e40558d90d17990f8229852d21c13d753c2e97facf077cf59582b603984c3dd3faebd80aff4f5", "0x93a8bcf4159f455d1baa73d2ef2450dcd4100420de84169bbe28b8b7a5d1746273f870091a87a057e834f754f34204b1", "0x89d0ebb287c3613cdcae7f5acc43f17f09c0213fc40c074660120b755d664109ffb9902ed981ede79e018ddb0c845698", "0xa87ccbfad431406aadbee878d9cf7d91b13649d5f7e19938b7dfd32645a43b114eef64ff3a13201398bd9b0337832e5a", "0x833c51d0d0048f70c3eefb4e70e4ff66d0809c41838e8d2c21c288dd3ae9d9dfaf26d1742bf4976dab83a2b381677011", "0x8bcd6b1c3b02fffead432e8b1680bad0a1ac5a712d4225e220690ee18df3e7406e2769e1f309e2e803b850bc96f0e768", "0xb61e3dbd88aaf4ff1401521781e2eea9ef8b66d1fac5387c83b1da9e65c2aa2a56c262dea9eceeb4ad86c90211672db0", "0x866d3090db944ecf190dd0651abf67659caafd31ae861bab9992c1e3915cb0952da7c561cc7e203560a610f48fae633b", "0xa5e8971543c14274a8dc892b0be188c1b4fbc75c692ed29f166e0ea80874bc5520c2791342b7c1d2fb5dd454b03b8a5b", "0x8f2f9fc50471bae9ea87487ebd1bc8576ef844cc42d606af5c4c0969670fdf2189afd643e4de3145864e7773d215f37f", "0xb1bb0f2527db6d51f42b9224383c0f96048bbc03d469bf01fe1383173ef8b1cc9455d9dd8ba04d46057f46949bfc92b5", "0xaa7c99d906b4d7922296cfe2520473fc50137c03d68b7865c5bfb8adbc316b1034310ec4b5670c47295f4a80fb8d61e9", "0xa5d1da4d6aba555919df44cbaa8ff79378a1c9e2cfdfbf9d39c63a4a00f284c5a5724e28ecbc2d9dba27fe4ee5018bd5", "0xa8db53224f70af4d991b9aae4ffe92d2aa5b618ad9137784b55843e9f16cefbfd25ada355d308e9bbf55f6d2f7976fb3", "0xb6536c4232bb20e22af1a8bb12de76d5fec2ad9a3b48af1f38fa67e0f8504ef60f305a73d19385095bb6a9603fe29889", "0x87f7e371a1817a63d6838a8cf4ab3a8473d19ce0d4f40fd013c03d5ddd5f4985df2956531cc9f187928ef54c68f4f9a9", "0xae13530b1dbc5e4dced9d909ea61286ec09e25c12f37a1ed2f309b0eb99863d236c3b25ed3484acc8c076ad2fa8cd430", "0x98928d850247c6f7606190e687d5c94a627550198dbdbea0161ef9515eacdb1a0f195cae3bb293112179082daccf8b35", "0x918528bb8e6a055ad4db6230d3a405e9e55866da15c4721f5ddd1f1f37962d4904aad7a419218fe6d906fe191a991806", "0xb71e31a06afe065773dd3f4a6e9ef81c3292e27a3b7fdfdd452d03e05af3b6dd654c355f7516b2a93553360c6681a73a", "0x8870b83ab78a98820866f91ac643af9f3ff792a2b7fda34185a9456a63abdce42bfe8ad4dc67f08a6392f250d4062df4", "0x91eea1b668e52f7a7a5087fabf1cab803b0316f78d9fff469fbfde2162f660c250e4336a9eea4cb0450bd30ac067bc8b", "0x8b74990946de7b72a92147ceac1bd9d55999a8b576e8df68639e40ed5dc2062cfcd727903133de482b6dca19d0aaed82", "0x8ebad537fece090ebbab662bdf2618e21ca30cf6329c50935e8346d1217dcbe3c1fe1ea28efca369c6003ce0a94703c1", "0xa8640479556fb59ebd1c40c5f368fbd960932fdbb782665e4a0e24e2bdb598fc0164ce8c0726d7759cfc59e60a62e182", "0xa9a52a6bf98ee4d749f6d38be2c60a6d54b64d5cbe4e67266633dc096cf28c97fe998596707d31968cbe2064b72256bf", "0x847953c48a4ce6032780e9b39d0ed4384e0be202c2bbe2dfda3910f5d87aa5cd3c2ffbfcfae4dddce16d6ab657599b95", "0xb6f6e1485d3ec2a06abaecd23028b200b2e4a0096c16144d07403e1720ff8f9ba9d919016b5eb8dc5103880a7a77a1d3", "0x98dfc2065b1622f596dbe27131ea60bef7a193b12922cecb27f8c571404f483014f8014572e86ae2e341ab738e4887ef", "0xacb0d205566bacc87bbe2e25d10793f63f7a1f27fd9e58f4f653ceae3ffeba511eaf658e068fad289eeb28f9edbeb35b", "0xae4411ed5b263673cee894c11fe4abc72a4bf642d94022a5c0f3369380fcdfc1c21e277f2902972252503f91ada3029a", "0xac4a7a27ba390a75d0a247d93d4a8ef1f0485f8d373a4af4e1139369ec274b91b3464d9738eeaceb19cd6f509e2f8262", "0x87379c3bf231fdafcf6472a79e9e55a938d851d4dd662ab6e0d95fd47a478ed99e2ad1e6e39be3c0fc4f6d996a7dd833", "0x81316904b035a8bcc2041199a789a2e6879486ba9fddcba0a82c745cc8dd8374a39e523b91792170cd30be7aa3005b85", "0xb8206809c6cd027ed019f472581b45f7e12288f89047928ba32b4856b6560ad30395830d71e5e30c556f6f182b1fe690", "0x88d76c028f534a62e019b4a52967bb8642ede6becfa3807be68fdd36d366fc84a4ac8dc176e80a68bc59eb62caf5dff9", "0x8c3b8be685b0f8aad131ee7544d0e12f223f08a6f8edaf464b385ac644e0ddc9eff7cc7cb5c1b50ab5d71ea0f41d2213", "0x8d91410e004f76c50fdc05784157b4d839cb5090022c629c7c97a5e0c3536eeafee17a527b54b1165c3cd81774bb54ce", "0xb25c2863bc28ec5281ce800ddf91a7e1a53f4c6d5da1e6c86ef4616e93bcf55ed49e297216d01379f5c6e7b3c1e46728", "0x865f7b09ac3ca03f20be90c48f6975dd2588838c2536c7a3532a6aa5187ed0b709cd03d91ff4048061c10d0aa72b69ce", "0xb3f7477c90c11596eb4f8bbf34adbcb832638c4ff3cdd090d4d477ee50472ac9ddaf5be9ad7eca3f148960d362bbd098", "0x8db35fd53fca04faecd1c76a8227160b3ab46ac1af070f2492445a19d8ff7c25bbaef6c9fa0c8c088444561e9f7e4eb2", "0xa478b6e9d058a2e01d2fc053b739092e113c23a6a2770a16afbef044a3709a9e32f425ace9ba7981325f02667c3f9609", "0x98caa6bd38916c08cf221722a675a4f7577f33452623de801d2b3429595f988090907a7e99960fff7c076d6d8e877b31", "0xb79aaaacefc49c3038a14d2ac468cfec8c2161e88bdae91798d63552cdbe39e0e02f9225717436b9b8a40a022c633c6e", "0x845a31006c680ee6a0cc41d3dc6c0c95d833fcf426f2e7c573fa15b2c4c641fbd6fe5ebb0e23720cc3467d6ee1d80dc4", "0xa1bc287e272cf8b74dbf6405b3a5190883195806aa351f1dc8e525aa342283f0a35ff687e3b434324dedee74946dd185", "0xa4fd2dc8db75d3783a020856e2b3aa266dc6926e84f5c491ef739a3bddd46dc8e9e0fc1177937839ef1b18d062ffbb9e", "0xacbf0d3c697f57c202bb8c5dc4f3fc341b8fc509a455d44bd86acc67cad2a04495d5537bcd3e98680185e8aa286f2587", "0xa5caf423a917352e1b8e844f5968a6da4fdeae467d10c6f4bbd82b5eea46a660b82d2f5440d3641c717b2c3c9ed0be52", "0x8a39d763c08b926599ab1233219c49c825368fad14d9afc7c0c039224d37c00d8743293fd21645bf0b91eaf579a99867", "0xb2b53a496def0ba06e80b28f36530fbe0fb5d70a601a2f10722e59abee529369c1ae8fd0f2db9184dd4a2519bb832d94", "0xa73980fcef053f1b60ebbb5d78ba6332a475e0b96a0c724741a3abf3b59dd344772527f07203cf4c9cb5155ebed81fa0", "0xa070d20acce42518ece322c9db096f16aed620303a39d8d5735a0df6e70fbeceb940e8d9f5cc38f3314b2240394ec47b", "0xa50cf591f522f19ca337b73089557f75929d9f645f3e57d4f241e14cdd1ea3fb48d84bcf05e4f0377afbb789fbdb5d20", "0x82a5ffce451096aca8eeb0cd2ae9d83db3ed76da3f531a80d9a70a346359bf05d74863ce6a7c848522b526156a5e20cd", "0x88e0e84d358cbb93755a906f329db1537c3894845f32b9b0b691c29cbb455373d9452fadd1e77e20a623f6eaf624de6f", "0xaa07ac7b84a6d6838826e0b9e350d8ec75e398a52e9824e6b0da6ae4010e5943fec4f00239e96433f291fef9d1d1e609", "0xac8887bf39366034bc63f6cc5db0c26fd27307cbc3d6cce47894a8a019c22dd51322fb5096edc018227edfafc053a8f6", "0xb7d26c26c5b33f77422191dca94977588ab1d4b9ce7d0e19c4a3b4cd1c25211b78c328dbf81e755e78cd7d1d622ad23e", "0x99a676d5af49f0ba44047009298d8474cabf2d5bca1a76ba21eff7ee3c4691a102fdefea27bc948ccad8894a658abd02", "0xb0d09a91909ab3620c183bdf1d53d43d39eb750dc7a722c661c3de3a1a5d383ad221f71bae374f8a71867505958a3f76", "0x84681a883de8e4b93d68ac10e91899c2bbb815ce2de74bb48a11a6113b2a3f4df8aceabda1f5f67bc5aacac8c9da7221", "0x9470259957780fa9b43521fab3644f555f5343281c72582b56d2efd11991d897b3b481cafa48681c5aeb80c9663b68f7", "0xab1b29f7ece686e6fa968a4815da1d64f3579fed3bc92e1f3e51cd13a3c076b6cf695ed269d373300a62463dc98a4234", "0x8ab415bfcd5f1061f7687597024c96dd9c7cb4942b5989379a7a3b5742f7d394337886317659cbeacaf030234a24f972", "0xb9b524aad924f9acc63d002d617488f31b0016e0f0548f050cada285ce7491b74a125621638f19e9c96eabb091d945be", "0x8c4c373e79415061837dd0def4f28a2d5d74d21cb13a76c9049ad678ca40228405ab0c3941df49249847ecdefc1a5b78", "0xa8edf4710b5ab2929d3db6c1c0e3e242261bbaa8bcec56908ddadd7d2dad2dca9d6eb9de630b960b122ebeea41040421", "0x8d66bb3b50b9df8f373163629f9221b3d4b6980a05ea81dc3741bfe9519cf3ebba7ab98e98390bae475e8ede5821bd5c", "0x8d3c21bae7f0cfb97c56952bb22084b58e7bb718890935b73103f33adf5e4d99cd262f929c6eeab96209814f0dbae50a", "0xa5c66cfab3d9ebf733c4af24bebc97070e7989fe3c73e79ac85fb0e4d40ae44fb571e0fad4ad72560e13ed453900d14f", "0x9362e6b50b43dbefbc3254471372297b5dcce809cd3b60bf74a1268ab68bdb50e46e462cbd78f0d6c056330e982846af", "0x854630d08e3f0243d570cc2e856234cb4c1a158d9c1883bf028a76525aaa34be897fe918d5f6da9764a3735fa9ebd24a", "0x8c7d246985469ff252c3f4df6c7c9196fc79f05c1c66a609d84725c78001d0837c7a7049394ba5cf7e863e2d58af8417", "0xae050271e01b528925302e71903f785b782f7bf4e4e7a7f537140219bc352dc7540c657ed03d3a297ad36798ecdb98cd", "0x8d2ae9179fcf2b0c69850554580b52c1f4a5bd865af5f3028f222f4acad9c1ad69a8ef6c7dc7b03715ee5c506b74325e", "0xb8ef8de6ce6369a8851cd36db0ccf00a85077e816c14c4e601f533330af9e3acf0743a95d28962ed8bfcfc2520ef3cfe", "0xa6ecad6fdfb851b40356a8b1060f38235407a0f2706e7b8bb4a13465ca3f81d4f5b99466ac2565c60af15f022d26732e", "0x819ff14cdea3ab89d98e133cd2d0379361e2e2c67ad94eeddcdb9232efd509f51d12f4f03ebd4dd953bd262a886281f7", "0x8561cd0f7a6dbcddd83fcd7f472d7dbcba95b2d4fb98276f48fccf69f76d284e626d7e41314b633352df8e6333fd52a1", "0xb42557ccce32d9a894d538c48712cb3e212d06ac05cd5e0527ccd2db1078ee6ae399bf6a601ffdab1f5913d35fc0b20c", "0x89b4008d767aad3c6f93c349d3b956e28307311a5b1cec237e8d74bb0dee7e972c24f347fd56afd915a2342bd7bc32f0", "0x877487384b207e53f5492f4e36c832c2227f92d1bb60542cfeb35e025a4a7afc2b885fae2528b33b40ab09510398f83e", "0x8c411050b63c9053dd0cd81dacb48753c3d7f162028098e024d17cd6348482703a69df31ad6256e3d25a8bbf7783de39", "0xa8506b54a88d17ac10fb1b0d1fe4aa40eae7553a064863d7f6b52ccc4236dd4b82d01dca6ba87da9a239e3069ba879fb", "0xb1a24caef9df64750c1350789bb8d8a0db0f39474a1c74ea9ba064b1516db6923f00af8d57c632d58844fb8786c3d47a", "0x959d6e255f212b0708c58a2f75cb1fe932248c9d93424612c1b8d1e640149656059737e4db2139afd5556bcdacf3eda2", "0x84525af21a8d78748680b6535bbc9dc2f0cf9a1d1740d12f382f6ecb2e73811d6c1da2ad9956070b1a617c61fcff9fe5", "0xb74417d84597a485d0a8e1be07bf78f17ebb2e7b3521b748f73935b9afbbd82f34b710fb7749e7d4ab55b0c7f9de127d", "0xa4a9aecb19a6bab167af96d8b9d9aa5308eab19e6bfb78f5a580f9bf89bdf250a7b52a09b75f715d651cb73febd08e84", "0x9777b30be2c5ffe7d29cc2803a562a32fb43b59d8c3f05a707ab60ec05b28293716230a7d264d7cd9dd358fc031cc13e", "0x95dce7a3d4f23ac0050c510999f5fbf8042f771e8f8f94192e17bcbfa213470802ebdbe33a876cb621cf42e275cbfc8b", "0xb0b963ebcbbee847ab8ae740478544350b3ac7e86887e4dfb2299ee5096247cd2b03c1de74c774d9bde94ae2ee2dcd59", "0xa4ab20bafa316030264e13f7ef5891a2c3b29ab62e1668fcb5881f50a9acac6adbe3d706c07e62f2539715db768f6c43", "0x901478a297669d608e406fe4989be75264b6c8be12169aa9e0ad5234f459ca377f78484ffd2099a2fe2db5e457826427", "0x88c76e5c250810c057004a03408b85cd918e0c8903dc55a0dd8bb9b4fc2b25c87f9b8cf5943eb19fbbe99d36490050c5", "0x91607322bbad4a4f03fc0012d0821eff5f8c516fda45d1ec1133bface6f858bf04b25547be24159cab931a7aa08344d4", "0x843203e07fce3c6c81f84bc6dc5fb5e9d1c50c8811ace522dc66e8658433a0ef9784c947e6a62c11bf705307ef05212e", "0x91dd8813a5d6dddcda7b0f87f672b83198cd0959d8311b2b26fb1fae745185c01f796fbd03aad9db9b58482483fdadd8", "0x8d15911aacf76c8bcd7136e958febd6963104addcd751ce5c06b6c37213f9c4fb0ffd4e0d12c8e40c36d658999724bfd", "0x8a36c5732d3f1b497ebe9250610605ee62a78eaa9e1a45f329d09aaa1061131cf1d9df00f3a7d0fe8ad614a1ff9caaae", "0xa407d06affae03660881ce20dab5e2d2d6cddc23cd09b95502a9181c465e57597841144cb34d22889902aff23a76d049", "0xb5fd856d0578620a7e25674d9503be7d97a2222900e1b4738c1d81ff6483b144e19e46802e91161e246271f90270e6cf", "0x91b7708869cdb5a7317f88c0312d103f8ce90be14fb4f219c2e074045a2a83636fdc3e69e862049fc7c1ef000e832541", "0xb64719cc5480709d1dae958f1d3082b32a43376da446c8f9f64cb02a301effc9c34d9102051733315a8179aed94d53cc", "0x94347a9542ff9d18f7d9eaa2f4d9b832d0e535fe49d52aa2de08aa8192400eddabdb6444a2a78883e27c779eed7fdf5a", "0x840ef44a733ff1376466698cd26f82cf56bb44811e196340467f932efa3ae1ef9958a0701b3b032f50fd9c1d2aed9ab5", "0x90ab3f6f67688888a31ffc2a882bb37adab32d1a4b278951a21646f90d03385fc976715fc639a785d015751171016f10", "0xb56f35d164c24b557dbcbc8a4bfa681ec916f8741ffcb27fb389c164f4e3ed2be325210ef5bdaeae7a172ca9599ab442", "0xa7921a5a80d7cf6ae81ba9ee05e0579b18c20cd2852762c89d6496aa4c8ca9d1ca2434a67b2c16d333ea8e382cdab1e3", "0xa506bcfbd7e7e5a92f68a1bd87d07ad5fe3b97aeee40af2bf2cae4efcd77fff03f872732c5b7883aa6584bee65d6f8cb", "0xa8c46cff58931a1ce9cbe1501e1da90b174cddd6d50f3dfdfb759d1d4ad4673c0a8feed6c1f24c7af32865a7d6c984e5", "0xb45686265a83bff69e312c5149db7bb70ac3ec790dc92e392b54d9c85a656e2bf58596ce269f014a906eafc97461aa5f", "0x8d4009a75ccb2f29f54a5f16684b93202c570d7a56ec1a8b20173269c5f7115894f210c26b41e8d54d4072de2d1c75d0", "0xaef8810af4fc676bf84a0d57b189760ddc3375c64e982539107422e3de2580b89bd27aa6da44e827b56db1b5555e4ee8", "0x888f0e1e4a34f48eb9a18ef4de334c27564d72f2cf8073e3d46d881853ac1424d79e88d8ddb251914890588937c8f711", "0xb64b0aa7b3a8f6e0d4b3499fe54e751b8c3e946377c0d5a6dbb677be23736b86a7e8a6be022411601dd75012012c3555", "0x8d57776f519f0dd912ea14f79fbab53a30624e102f9575c0bad08d2dc754e6be54f39b11278c290977d9b9c7c0e1e0ad", "0xa018fc00d532ceb2e4de908a15606db9b6e0665dd77190e2338da7c87a1713e6b9b61554e7c1462f0f6d4934b960b15c", "0x8c932be83ace46f65c78e145b384f58e41546dc0395270c1397874d88626fdeda395c8a289d602b4c312fe98c1311856", "0x89174838e21639d6bdd91a0621f04dc056907b88e305dd66e46a08f6d65f731dea72ae87ca5e3042d609e8de8de9aa26", "0xb7b7f508bb74f7a827ac8189daa855598ff1d96fa3a02394891fd105d8f0816224cd50ac4bf2ed1cf469ace516c48184", "0xb31877ad682583283baadd68dc1bebd83f5748b165aadd7fe9ef61a343773b88bcd3a022f36d6c92f339b7bfd72820a9", "0xb79d77260b25daf9126dab7a193df2d7d30542786fa1733ffaf6261734770275d3ca8bae1d9915d1181a78510b3439db", "0x91894fb94cd4c1dd2ceaf9c53a7020c5799ba1217cf2d251ea5bc91ed26e1159dd758e98282ebe35a0395ef9f1ed15a0", "0xab59895cdafd33934ceedfc3f0d5d89880482cba6c99a6db93245f9e41987efd76e0640e80aef31782c9a8c7a83fccec", "0xaa22ea63654315e033e09d4d4432331904a6fc5fb1732557987846e3c564668ca67c60a324b4af01663a23af11a9ce4b", "0xb53ba3ef342601467e1f71aa280e100fbabbd38518fa0193e0099505036ee517c1ac78e96e9baeb549bb6879bb698fb0", "0x943fd69fd656f37487cca3605dc7e5a215fddd811caf228595ec428751fc1de484a0cb84c667fe4d7c35599bfa0e5e34", "0x9353128b5ebe0dddc555093cf3e5942754f938173541033e8788d7331fafc56f68d9f97b4131e37963ab7f1c8946f5f1", "0xa76cd3c566691f65cfb86453b5b31dbaf3cab8f84fe1f795dd1e570784b9b01bdd5f0b3c1e233942b1b5838290e00598", "0x983d84b2e53ffa4ae7f3ba29ef2345247ea2377686b74a10479a0ef105ecf90427bf53b74c96dfa346d0f842b6ffb25b", "0x92e0fe9063306894a2c6970c001781cff416c87e87cb5fbac927a3192655c3da4063e6fa93539f6ff58efac6adcc5514", "0xb00a81f03c2b8703acd4e2e4c21e06973aba696415d0ea1a648ace2b0ea19b242fede10e4f9d7dcd61c546ab878bc8f9", "0xb0d08d880f3b456a10bf65cff983f754f545c840c413aea90ce7101a66eb0a0b9b1549d6c4d57725315828607963f15a", "0x90cb64d03534f913b411375cce88a9e8b1329ce67a9f89ca5df8a22b8c1c97707fec727dbcbb9737f20c4cf751359277", "0x8327c2d42590dfcdb78477fc18dcf71608686ad66c49bce64d7ee874668be7e1c17cc1042a754bbc77c9daf50b2dae07", "0x8532171ea13aa7e37178e51a6c775da469d2e26ec854eb16e60f3307db4acec110d2155832c202e9ba525fc99174e3b0", "0x83ca44b15393d021de2a511fa5511c5bd4e0ac7d67259dce5a5328f38a3cce9c3a269405959a2486016bc27bb140f9ff", "0xb1d36e8ca812be545505c8214943b36cabee48112cf0de369957afa796d37f86bf7249d9f36e8e990f26f1076f292b13", "0x9803abf45be5271e2f3164c328d449efc4b8fc92dfc1225d38e09630909fe92e90a5c77618daa5f592d23fc3ad667094", "0xb268ad68c7bf432a01039cd889afae815c3e120f57930d463aece10af4fd330b5bd7d8869ef1bcf6b2e78e4229922edc", "0xa4c91a0d6f16b1553264592b4cbbbf3ca5da32ab053ffbdd3dbb1aed1afb650fb6e0dc5274f71a51d7160856477228db", "0xad89d043c2f0f17806277ffdf3ecf007448e93968663f8a0b674254f36170447b7527d5906035e5e56f4146b89b5af56", "0x8b6964f757a72a22a642e4d69102951897e20c21449184e44717bd0681d75f7c5bfa5ee5397f6e53febf85a1810d6ed1", "0xb08f5cdaabec910856920cd6e836c830b863eb578423edf0b32529488f71fe8257d90aed4a127448204df498b6815d79", "0xaf26bb3358be9d280d39b21d831bb53145c4527a642446073fee5a86215c4c89ff49a3877a7a549486262f6f57a0f476", "0xb4010b37ec4d7c2af20800e272539200a6b623ae4636ecbd0e619484f4ab9240d02bc5541ace3a3fb955dc0a3d774212", "0x82752ab52bdcc3cc2fc405cb05a2e694d3df4a3a68f2179ec0652536d067b43660b96f85f573f26fbd664a9ef899f650", "0x96d392dde067473a81faf2d1fea55b6429126b88b160e39b4210d31d0a82833ffd3a80e07d24d495aea2d96be7251547", "0xa76d8236d6671204d440c33ac5b8deb71fa389f6563d80e73be8b043ec77d4c9b06f9a586117c7f957f4af0331cbc871", "0xb6c90961f68b5e385d85c9830ec765d22a425f506904c4d506b87d8944c2b2c09615e740ed351df0f9321a7b93979cae", "0xa6ec5ea80c7558403485b3b1869cdc63bde239bafdf936d9b62a37031628402a36a2cfa5cfbb8e26ac922cb0a209b3ba", "0x8c3195bbdbf9bc0fc95fa7e3d7f739353c947f7767d1e3cb24d8c8602d8ea0a1790ac30b815be2a2ba26caa5227891e2", "0xa7f8a63d809f1155722c57f375ea00412b00147776ae4444f342550279ef4415450d6f400000a326bf11fea6c77bf941", "0x97fa404df48433a00c85793440e89bb1af44c7267588ae937a1f5d53e01e1c4d4fc8e4a6d517f3978bfdd6c2dfde012f", "0xa984a0a3836de3d8d909c4629a2636aacb85393f6f214a2ef68860081e9db05ad608024762db0dc35e895dc00e2d4cdd", "0x9526cf088ab90335add1db4d3a4ac631b58cbfbe88fa0845a877d33247d1cfeb85994522e1eb8f8874651bfb1df03e2a", "0xac83443fd0afe99ad49de9bf8230158c118e2814c9c89db5ac951c240d6c2ce45e7677221279d9e97848ec466b99aafe", "0xaeeefdbaba612e971697798ceaf63b247949dc823a0ad771ae5b988a5e882b338a98d3d0796230f49d533ec5ba411b39", "0xae3f248b5a7b0f92b7820a6c5ae21e5bd8f4265d4f6e21a22512079b8ee9be06393fd3133ce8ebac0faf23f4f8517e36", "0xa64a831b908eee784b8388b45447d2885ec0551b26b0c2b15e5f417d0a12c79e867fb7bd3d008d0af98b44336f8ec1ad", "0xb242238cd8362b6e440ba21806905714dd55172db25ec7195f3fc4937b2aba146d5cbf3cf691a1384b4752dc3b54d627", "0x819f97f337eea1ffb2a678cc25f556f1aab751c6b048993a1d430fe1a3ddd8bb411c152e12ca60ec6e057c190cd1db9a", "0xb9d7d187407380df54ee9fef224c54eec1bfabf17dc8abf60765b7951f538f59aa26fffd5846cfe05546c35f59b573f4", "0xaa6e3c14efa6a5962812e3f94f8ce673a433f4a82d07a67577285ea0eaa07f8be7115853122d12d6d4e1fdf64c504be1", "0x82268bee9c1662d3ddb5fb785abfae6fb8b774190f30267f1d47091d2cd4b3874db4372625aa36c32f27b0eee986269b", "0xb236459565b7b966166c4a35b2fa71030b40321821b8e96879d95f0e83a0baf33fa25721f30af4a631df209e25b96061", "0x8708d752632d2435d2d5b1db4ad1fa2558d776a013655f88e9a3556d86b71976e7dfe5b8834fdec97682cd94560d0d0d", "0xae1424a68ae2dbfb0f01211f11773732a50510b5585c1fb005cb892b2c6a58f4a55490b5c5b4483c6fce40e9d3236a52", "0xb3f5f722af9dddb07293c871ce97abbccba0093ca98c8d74b1318fa21396fc1b45b69c15084f63d728f9908442024506", "0x9606f3ce5e63886853ca476dc0949e7f1051889d529365c0cb0296fdc02abd088f0f0318ecd2cf36740a3634132d36f6", "0xb11a833a49fa138db46b25ff8cdda665295226595bc212c0931b4931d0a55c99da972c12b4ef753f7e37c6332356e350", "0xafede34e7dab0a9e074bc19a7daddb27df65735581ca24ad70c891c98b1349fcebbcf3ba6b32c2617fe06a5818dabc2d", "0x97993d456e459e66322d01f8eb13918979761c3e8590910453944bdff90b24091bb018ac6499792515c9923be289f99f", "0x977e3e967eff19290a192cd11df3667d511b398fb3ac9a5114a0f3707e25a0edcb56105648b1b85a8b7519fc529fc6f6", "0xb873a7c88bf58731fe1bf61ff6828bf114cf5228f254083304a4570e854e83748fc98683ddba62d978fff7909f2c5c47", "0xad4b2691f6f19da1d123aaa23cca3e876247ed9a4ab23c599afdbc0d3aa49776442a7ceaa996ac550d0313d9b9a36cee", "0xb9210713c78e19685608c6475bfa974b57ac276808a443f8b280945c5d5f9c39da43effa294bfb1a6c6f7b6b9f85bf6c", "0xa65152f376113e61a0e468759de38d742caa260291b4753391ee408dea55927af08a4d4a9918600a3bdf1df462dffe76", "0x8bf8c27ad5140dde7f3d2280fd4cc6b29ab76537e8d7aa7011a9d2796ee3e56e9a60c27b5c2da6c5e14fc866301dc195", "0x92fde8effc9f61393a2771155812b863cff2a0c5423d7d40aa04d621d396b44af94ddd376c28e7d2f53c930aea947484", "0x97a01d1dd9ee30553ce676011aea97fa93d55038ada95f0057d2362ae9437f3ed13de8290e2ff21e3167dd7ba10b9c3f", "0x89affffaa63cb2df3490f76f0d1e1d6ca35c221dd34057176ba739fa18d492355e6d2a5a5ad93a136d3b1fed0bb8aa19", "0x928b8e255a77e1f0495c86d3c63b83677b4561a5fcbbe5d3210f1e0fc947496e426d6bf3b49394a5df796c9f25673fc4", "0x842a0af91799c9b533e79ee081efe2a634cac6c584c2f054fb7d1db67dde90ae36de36cbf712ec9cd1a0c7ee79e151ea", "0xa65b946cf637e090baf2107c9a42f354b390e7316beb8913638130dbc67c918926eb87bec3b1fe92ef72bc77a170fa3b", "0xaafc0f19bfd71ab5ae4a8510c7861458b70ad062a44107b1b1dbacbfa44ba3217028c2824bd7058e2fa32455f624040b", "0x95269dc787653814e0be899c95dba8cfa384f575a25e671c0806fd80816ad6797dc819d30ae06e1d0ed9cb01c3950d47", "0xa1e760f7fa5775a1b2964b719ff961a92083c5c617f637fc46e0c9c20ab233f8686f7f38c3cb27d825c54dd95e93a59b", "0xac3b8a7c2317ea967f229eddc3e23e279427f665c4705c7532ed33443f1243d33453c1088f57088d2ab1e3df690a9cc9", "0xb787beeddfbfe36dd51ec4efd9cf83e59e84d354c3353cc9c447be53ae53d366ed1c59b686e52a92f002142c8652bfe0", "0xb7a64198300cb6716aa7ac6b25621f8bdec46ad5c07a27e165b3f774cdf65bcfdbf31e9bae0c16b44de4b00ada7a4244", "0xb8ae9f1452909e0c412c7a7fe075027691ea8df1347f65a5507bc8848f1d2c833d69748076db1129e5b4fb912f65c86c", "0x9682e41872456b9fa67def89e71f06d362d6c8ca85c9c48536615bc401442711e1c9803f10ab7f8ab5feaec0f9df20a6", "0x88889ff4e271dc1c7e21989cc39f73cde2f0475acd98078281591ff6c944fadeb9954e72334319050205d745d4df73df", "0x8f79b5b8159e7fd0d93b0645f3c416464f39aec353b57d99ecf24f96272df8a068ad67a6c90c78d82c63b40bb73989bb", "0x838c01a009a3d8558a3f0bdd5e22de21af71ca1aefc8423c91dc577d50920e9516880e87dce3e6d086e11cd45c9052d9", "0xb97f1c6eee8a78f137c840667cc288256e39294268a3009419298a04a1d0087c9c9077b33c917c65caf76637702dda8a", "0x972284ce72f96a61c899260203dfa06fc3268981732bef74060641c1a5068ead723e3399431c247ca034b0dae861e8df", "0x945a8d52d6d3db6663dbd3110c6587f9e9c44132045eeffba15621576d178315cb52870fa5861669f84f0bee646183fe", "0xa0a547b5f0967b1c3e5ec6c6a9a99f0578521489180dfdfbb5561f4d166baac43a2f06f950f645ce991664e167537eed", "0xa0592cda5cdddf1340033a745fd13a6eff2021f2e26587116c61c60edead067e0f217bc2bef4172a3c9839b0b978ab35", "0xb9c223b65a3281587fa44ec829e609154b32f801fd1de6950e01eafb07a8324243b960d5735288d0f89f0078b2c42b5b", "0x99ebfc3b8f9f98249f4d37a0023149ed85edd7a5abe062c8fb30c8c84555258b998bdcdd1d400bc0fa2a4aaa8b224466", "0x955b68526e6cb3937b26843270f4e60f9c6c8ece2fa9308fe3e23afa433309c068c66a4bc16ee2cf04220f095e9afce4", "0xb766caeafcc00378135ae53397f8a67ed586f5e30795462c4a35853de6681b1f17401a1c40958de32b197c083b7279c1", "0x921bf87cad947c2c33fa596d819423c10337a76fe5a63813c0a9dc78a728207ae7b339407a402fc4d0f7cba3af6da6fc", "0xa74ba1f3bc3e6c025db411308f49b347ec91da1c916bda9da61e510ec8d71d25e0ac0f124811b7860e5204f93099af27", "0xa29b4d144e0bf17a7e8353f2824cef0ce85621396babe8a0b873ca1e8a5f8d508b87866cf86da348470649fceefd735c", "0xa8040e12ffc3480dd83a349d06741d1572ef91932c46f5cf03aee8454254156ee95786fd013d5654725e674c920cec32", "0x8c4cf34ca60afd33923f219ffed054f90cd3f253ffeb2204a3b61b0183417e366c16c07fae860e362b0f2bfe3e1a1d35", "0x8195eede4ddb1c950459df6c396b2e99d83059f282b420acc34220cadeed16ab65c856f2c52568d86d3c682818ed7b37", "0x91fff19e54c15932260aa990c7fcb3c3c3da94845cc5aa8740ef56cf9f58d19b4c3c55596f8d6c877f9f4d22921d93aa", "0xa3e0bf7e5d02a80b75cf75f2db7e66cb625250c45436e3c136d86297d652590ec97c2311bafe407ad357c79ab29d107b", "0x81917ff87e5ed2ae4656b481a63ced9e6e5ff653b8aa6b7986911b8bc1ee5b8ef4f4d7882c3f250f2238e141b227e510", "0x915fdbe5e7de09c66c0416ae14a8750db9412e11dc576cf6158755fdcaf67abdbf0fa79b554cac4fe91c4ec245be073f", "0x8df27eafb5c3996ba4dc5773c1a45ca77e626b52e454dc1c4058aa94c2067c18332280630cc3d364821ee53bf2b8c130", "0x934f8a17c5cbb827d7868f5c8ca00cb027728a841000a16a3428ab16aa28733f16b52f58c9c4fbf75ccc45df72d9c4df", "0xb83f4da811f9183c25de8958bc73b504cf790e0f357cbe74ef696efa7aca97ad3b7ead1faf76e9f982c65b6a4d888fc2", "0x87188213c8b5c268dc2b6da413f0501c95749e953791b727450af3e43714149c115b596b33b63a2f006a1a271b87efd0", "0x83e9e888ab9c3e30761de635d9aabd31248cdd92f7675fc43e4b21fd96a03ec1dc4ad2ec94fec857ffb52683ac98e360", "0xb4b9a1823fe2d983dc4ec4e3aaea297e581c3fc5ab4b4af5fa1370caa37af2d1cc7fc6bfc5e7da60ad8fdce27dfe4b24", "0x856388bc78aef465dbcdd1f559252e028c9e9a2225c37d645c138e78f008f764124522705822a61326a6d1c79781e189", "0xa6431b36db93c3b47353ba22e7c9592c9cdfb9cbdd052ecf2cc3793f5b60c1e89bc96e6bae117bfd047f2308da00dd2f", "0xb619972d48e7e4291542dcde08f7a9cdc883c892986ded2f23ccb216e245cd8d9ad1d285347b0f9d7611d63bf4cee2bc", "0x8845cca6ff8595955f37440232f8e61d5351500bd016dfadd182b9d39544db77a62f4e0102ff74dd4173ae2c181d24ef", "0xb2f5f7fa26dcd3b6550879520172db2d64ee6aaa213cbef1a12befbce03f0973a22eb4e5d7b977f466ac2bf8323dcedd", "0x858b7f7e2d44bdf5235841164aa8b4f3d33934e8cb122794d90e0c1cac726417b220529e4f896d7b77902ab0ccd35b3a", "0x80b0408a092dae2b287a5e32ea1ad52b78b10e9c12f49282976cd738f5d834e03d1ad59b09c5ccaccc39818b87d06092", "0xb996b0a9c6a2d14d984edcd6ab56bc941674102980d65b3ad9733455f49473d3f587c8cbf661228a7e125ddbe07e3198", "0x90224fcebb36865293bd63af786e0c5ade6b67c4938d77eb0cbae730d514fdd0fe2d6632788e858afd29d46310cf86df", "0xb71351fdfff7168b0a5ec48397ecc27ac36657a8033d9981e97002dcca0303e3715ce6dd3f39423bc8ef286fa2e9e669", "0xae2a3f078b89fb753ce4ed87e0c1a58bb19b4f0cfb6586dedb9fcab99d097d659a489fb40e14651741e1375cfc4b6c5f", "0x8ef476b118e0b868caed297c161f4231bbeb863cdfa5e2eaa0fc6b6669425ce7af50dc374abceac154c287de50c22307", "0x92e46ab472c56cfc6458955270d3c72b7bde563bb32f7d4ab4d959db6f885764a3d864e1aa19802fefaa5e16b0cb0b54", "0x96a3f68323d1c94e73d5938a18a377af31b782f56212de3f489d22bc289cf24793a95b37f1d6776edf88114b5c1fa695", "0x962cc068cfce6faaa27213c4e43e44eeff0dfbb6d25b814e82c7da981fb81d7d91868fa2344f05fb552362f98cfd4a72", "0x895d4e4c4ad670abf66d43d59675b1add7afad7438ada8f42a0360c704cee2060f9ac15b4d27e9b9d0996bb801276fe3", "0xb3ad18d7ece71f89f2ef749b853c45dc56bf1c796250024b39a1e91ed11ca32713864049c9aaaea60cde309b47486bbf", "0x8f05404e0c0258fdbae50e97ccb9b72ee17e0bd2400d9102c0dad981dac8c4c71585f03e9b5d50086d0a2d3334cb55d1", "0x8bd877e9d4591d02c63c6f9fc9976c109de2d0d2df2bfa5f6a3232bab5b0b8b46e255679520480c2d7a318545efa1245", "0x8d4c16b5d98957c9da13d3f36c46f176e64e5be879f22be3179a2c0e624fe4758a82bf8c8027410002f973a3b84cd55a", "0x86e2a8dea86427b424fa8eada881bdff896907084a495546e66556cbdf070b78ba312bf441eb1be6a80006d25d5097a3", "0x8608b0c117fd8652fdab0495b08fadbeba95d9c37068e570de6fddfef1ba4a1773b42ac2be212836141d1bdcdef11a17", "0xa13d6febf5fb993ae76cae08423ca28da8b818d6ef0fde32976a4db57839cd45b085026b28ee5795f10a9a8e3098c683", "0x8e261967fa6de96f00bc94a199d7f72896a6ad8a7bbb1d6187cca8fad824e522880e20f766620f4f7e191c53321d70f9", "0x8b8e8972ac0218d7e3d922c734302803878ad508ca19f5f012bc047babd8a5c5a53deb5fe7c15a4c00fd6d1cb9b1dbd0", "0xb5616b233fb3574a2717d125a434a2682ff68546dccf116dd8a3b750a096982f185614b9fb6c7678107ff40a451f56fa", "0xaa6adf9b0c3334b0d0663f583a4914523b2ac2e7adffdb026ab9109295ff6af003ef8357026dbcf789896d2afded8d73", "0xacb72df56a0b65496cd534448ed4f62950bb1e11e50873b6ed349c088ee364441821294ce0f7c61bd7d38105bea3b442", "0xabae12df83e01ec947249fedd0115dc501d2b03ff7232092979eda531dbbca29ace1d46923427c7dde4c17bdf3fd7708", "0x820b4fc2b63a9fda7964acf5caf19a2fc4965007cb6d6b511fcafcb1f71c3f673a1c0791d3f86e3a9a1eb6955b191cc0", "0xaf277259d78c6b0f4f030a10c53577555df5e83319ddbad91afbd7c30bc58e7671c56d00d66ec3ab5ef56470cd910cee", "0xad4a861c59f1f5ca1beedd488fb3d131dea924fffd8e038741a1a7371fad7370ca5cf80dc01f177fbb9576713bb9a5b3", "0xb67a5162982ce6a55ccfb2f177b1ec26b110043cf18abd6a6c451cf140b5af2d634591eb4f28ad92177d8c7e5cd0a5e8", "0x96176d0a83816330187798072d449cbfccff682561e668faf6b1220c9a6535b32a6e4f852e8abb00f79abb87493df16b", "0xb0afe6e7cb672e18f0206e4423f51f8bd0017bf464c4b186d46332c5a5847647f89ff7fa4801a41c1b0b42f6135bcc92", "0x8fc5e7a95ef20c1278c645892811f6fe3f15c431ebc998a32ec0da44e7213ea934ed2be65239f3f49b8ec471e9914160", "0xb7793e41adda6c82ba1f2a31f656f6205f65bf8a3d50d836ee631bc7ce77c153345a2d0fc5c60edf8b37457c3729c4ec", "0xa504dd7e4d6b2f4379f22cc867c65535079c75ccc575955f961677fa63ecb9f74026fa2f60c9fb6323c1699259e5e9c8", "0xab899d00ae693649cc1afdf30fb80d728973d2177c006e428bf61c7be01e183866614e05410041bc82cb14a33330e69c", "0x8a3bd8b0b1be570b65c4432a0f6dc42f48a2000e30ab089cf781d38f4090467b54f79c0d472fcbf18ef6a00df69cc6f3", "0xb4d7028f7f76a96a3d7803fca7f507ae11a77c5346e9cdfccb120a833a59bda1f4264e425aa588e7a16f8e7638061d84", "0xb9c7511a76ea5fb105de905d44b02edb17008335766ee357ed386b7b3cf19640a98b38785cb14603c1192bee5886c9b6", "0x8563afb12e53aed71ac7103ab8602bfa8371ae095207cb0d59e8fd389b6ad1aff0641147e53cb6a7ca16c7f37c9c5e6b", "0x8e108be614604e09974a9ed90960c28c4ea330a3d9a0cb4af6dd6f193f84ab282b243ecdf549b3131036bebc8905690c", "0xb794d127fbedb9c5b58e31822361706ffac55ce023fbfe55716c3c48c2fd2f2c7660a67346864dfe588812d369cb50b6", "0xb797a3442fc3b44f41baefd30346f9ac7f96e770d010d53c146ce74ce424c10fb62758b7e108b8abfdc5fafd89d745cb", "0x993bb71e031e8096442e6205625e1bfddfe6dd6a83a81f3e2f84fafa9e5082ab4cad80a099f21eff2e81c83457c725c3", "0x8711ab833fc03e37acf2e1e74cfd9133b101ff4144fe30260654398ae48912ab46549d552eb9d15d2ea57760d35ac62e", "0xb21321fd2a12083863a1576c5930e1aecb330391ef83326d9d92e1f6f0d066d1394519284ddab55b2cb77417d4b0292f", "0x877d98f731ffe3ee94b0b5b72d127630fa8a96f6ca4f913d2aa581f67732df6709493693053b3e22b0181632ac6c1e3b", "0xae391c12e0eb8c145103c62ea64f41345973311c3bf7281fa6bf9b7faafac87bcf0998e5649b9ef81e288c369c827e07", "0xb83a2842f36998890492ab1cd5a088d9423d192681b9a3a90ec518d4c541bce63e6c5f4df0f734f31fbfdd87785a2463", "0xa21b6a790011396e1569ec5b2a423857b9bec16f543e63af28024e116c1ea24a3b96e8e4c75c6537c3e4611fd265e896", "0xb4251a9c4aab3a495da7a42e684ba4860dbcf940ad1da4b6d5ec46050cbe8dab0ab9ae6b63b5879de97b905723a41576", "0x8222f70aebfe6ac037f8543a08498f4cadb3edaac00336fc00437eb09f2cba758f6c38e887cc634b4d5b7112b6334836", "0x86f05038e060594c46b5d94621a1d9620aa8ba59a6995baf448734e21f58e23c1ea2993d3002ad5250d6edd5ba59b34f", "0xa7c0c749baef811ab31b973c39ceb1d94750e2bc559c90dc5eeb20d8bb6b78586a2b363c599ba2107d6be65cd435f24e", "0x861d46a5d70b38d6c1cd72817a2813803d9f34c00320c8b62f8b9deb67f5b5687bc0b37c16d28fd017367b92e05da9ca", "0xb3365d3dab639bffbe38e35383686a435c8c88b397b717cd4aeced2772ea1053ceb670f811f883f4e02975e5f1c4ac58", "0xa5750285f61ab8f64cd771f6466e2c0395e01b692fd878f2ef2d5c78bdd8212a73a3b1dfa5e4c8d9e1afda7c84857d3b", "0x835a10809ccf939bc46cf950a33b36d71be418774f51861f1cd98a016ade30f289114a88225a2c11e771b8b346cbe6ef", "0xa4f59473a037077181a0a62f1856ec271028546ca9452b45cedfcb229d0f4d1aabfc13062b07e536cc8a0d4b113156a2", "0x95cd14802180b224d44a73cc1ed599d6c4ca62ddcaa503513ccdc80aaa8be050cc98bd4b4f3b639549beb4587ac6caf9", "0x973b731992a3e69996253d7f36dd7a0af1982b5ed21624b77a7965d69e9a377b010d6dabf88a8a97eec2a476259859cc", "0xaf8a1655d6f9c78c8eb9a95051aa3baaf9c811adf0ae8c944a8d3fcba87b15f61021f3baf6996fa0aa51c81b3cb69de1", "0x835aad5c56872d2a2d6c252507b85dd742bf9b8c211ccb6b25b52d15c07245b6d89b2a40f722aeb5083a47cca159c947", "0xabf4e970b02bef8a102df983e22e97e2541dd3650b46e26be9ee394a3ea8b577019331857241d3d12b41d4eacd29a3ac", "0xa13c32449dbedf158721c13db9539ae076a6ce5aeaf68491e90e6ad4e20e20d1cdcc4a89ed9fd49cb8c0dd50c17633c1", "0x8c8f78f88b7e22dd7e9150ab1c000f10c28e696e21d85d6469a6fe315254740f32e73d81ab1f3c1cf8f544c86df506e8", "0xb4b77f2acfe945abf81f2605f906c10b88fb4d28628487fb4feb3a09f17f28e9780445dfcee4878349d4c6387a9d17d4", "0x8d255c235f3812c6ecc646f855fa3832be5cb4dbb9c9e544989fafdf3f69f05bfd370732eaf954012f0044aa013fc9c6", "0xb982efd3f34b47df37c910148ac56a84e8116647bea24145a49e34e0a6c0176e3284d838dae6230cb40d0be91c078b85", "0x983f365aa09bd85df2a6a2ad8e4318996b1e27d02090755391d4486144e40d80b1fbfe1c798d626db92f52e33aa634da", "0x95fd1981271f3ea3a41d654cf497e6696730d9ff7369f26bc4d7d15c7adb4823dd0c42e4a005a810af12d234065e5390", "0xa9f5219bd4b913c186ef30c02f995a08f0f6f1462614ea5f236964e02bdaa33db9d9b816c4aee5829947840a9a07ba60", "0x9210e6ceb05c09b46fd09d036287ca33c45124ab86315e5d6911ff89054f1101faaa3e83d123b7805056d388bcec6664", "0x8ed9cbf69c6ff3a5c62dd9fe0d7264578c0f826a29e614bc2fb4d621d90c8c9992438accdd7a614b1dca5d1bb73dc315", "0x85cf2a8cca93e00da459e3cecd22c342d697eee13c74d5851634844fc215f60053cf84b0e03c327cb395f48d1c71a8a4", "0x8818a18e9a2ec90a271b784400c1903089ffb0e0b40bc5abbbe12fbebe0f731f91959d98c5519ef1694543e31e2016d4", "0x8dabc130f296fa7a82870bf9a8405aaf542b222ed9276bba9bd3c3555a0f473acb97d655ee7280baff766a827a8993f0", "0xac7952b84b0dc60c4d858f034093b4d322c35959605a3dad2b806af9813a4680cb038c6d7f4485b4d6b2ff502aaeca25", "0xad65cb6d57b48a2602568d2ec8010baed0eb440eec7638c5ec8f02687d764e9de5b5d42ad5582934e592b48471c22d26", "0xa02ab8bd4c3d114ea23aebdd880952f9495912817da8c0c08eabc4e6755439899d635034413d51134c72a6320f807f1c", "0x8319567764b8295402ec1ebef4c2930a138480b37e6d7d01c8b4c9cd1f2fc3f6e9a44ae6e380a0c469b25b06db23305f", "0xafec53b2301dc0caa8034cd9daef78c48905e6068d692ca23d589b84a6fa9ddc2ed24a39480597e19cb3e83eec213b3f", "0xac0b4ffdb5ae08e586a9cdb98f9fe56f4712af3a97065e89e274feacfb52b53c839565aee93c4cfaaccfe51432c4fab0", "0x8972cbf07a738549205b1094c5987818124144bf187bc0a85287c94fdb22ce038c0f11df1aa16ec5992e91b44d1af793", "0xb7267aa6f9e3de864179b7da30319f1d4cb2a3560f2ea980254775963f1523b44c680f917095879bebfa3dc2b603efcf", "0x80f68f4bfc337952e29504ee5149f15093824ea7ab02507efd1317a670f6cbc3611201848560312e3e52e9d9af72eccf", "0x8897fee93ce8fc1e1122e46b6d640bba309384dbd92e46e185e6364aa8210ebf5f9ee7e5e604b6ffba99aa80a10dd7d0", "0xb58ea6c02f2360be60595223d692e82ee64874fda41a9f75930f7d28586f89be34b1083e03bbc1575bbfdda2d30db1ea", "0x85a523a33d903280d70ac5938770453a58293480170c84926457ac2df45c10d5ff34322ab130ef4a38c916e70d81af53", "0xa2cbf045e1bed38937492c1f2f93a5ba41875f1f262291914bc1fc40c60bd0740fb3fea428faf6da38b7c180fe8ac109", "0x8c09328770ed8eb17afc6ac7ddd87bb476de18ed63cab80027234a605806895959990c47bd10d259d7f3e2ecb50074c9", "0xb4b9e19edb4a33bde8b7289956568a5b6b6557404e0a34584b5721fe6f564821091013fbb158e2858c6d398293bb4b59", "0x8a47377df61733a2aa5a0e945fce00267f8e950f37e109d4487d92d878fb8b573317bb382d902de515b544e9e233458d", "0xb5804c9d97efeff5ca94f3689b8088c62422d92a1506fd1d8d3b1b30e8a866ad0d6dad4abfa051dfc4471250cac4c5d9", "0x9084a6ee8ec22d4881e9dcc8a9eb3c2513523d8bc141942370fd191ad2601bf9537a0b1e84316f3209b3d8a54368051e", "0x85447eea2fa26656a649f8519fa67279183044791d61cf8563d0783d46d747d96af31d0a93507bbb2242666aa87d3720", "0x97566a84481027b60116c751aec552adfff2d9038e68d48c4db9811fb0cbfdb3f1d91fc176a0b0d988a765f8a020bce1", "0xae87e5c1b9e86c49a23dceda4ecfd1dcf08567f1db8e5b6ec752ebd45433c11e7da4988573cdaebbb6f4135814fc059e", "0xabee05cf9abdbc52897ac1ce9ed157f5466ed6c383d6497de28616238d60409e5e92619e528af8b62cc552bf09970dc2", "0xae6d31cd7bf9599e5ee0828bab00ceb4856d829bba967278a73706b5f388465367aa8a6c7da24b5e5f1fdd3256ef8e63", "0xac33e7b1ee47e1ee4af472e37ab9e9175260e506a4e5ce449788075da1b53c44cb035f3792d1eea2aa24b1f688cc6ed3", "0x80f65b205666b0e089bb62152251c48c380a831e5f277f11f3ef4f0d52533f0851c1b612267042802f019ec900dc0e8f", "0x858520ad7aa1c9fed738e3b583c84168f2927837ad0e1d326afe9935c26e9b473d7f8c382e82ef1fe37d2b39bb40a1ee", "0xb842dd4af8befe00a97c2d0f0c33c93974761e2cb9e5ab8331b25170318ddd5e4bdbc02d8f90cbfdd5f348f4f371c1f7", "0x8bf2cb79bc783cb57088aae7363320cbeaabd078ffdec9d41bc74ff49e0043d0dad0086a30e5112b689fd2f5a606365d", "0x982eb03bbe563e8850847cd37e6a3306d298ab08c4d63ab6334e6b8c1fa13fce80cf2693b09714c7621d74261a0ff306", "0xb143edb113dec9f1e5105d4a93fbe502b859e587640d3db2f628c09a17060e6aec9e900e2c8c411cda99bc301ff96625", "0xaf472d9befa750dcebc5428fe1a024f18ec1c07bca0f95643ce6b5f4189892a910285afb03fd7ed7068fbe614e80d33c", "0xa97e3bc57ede73ecd1bbf02de8f51b4e7c1a067da68a3cd719f4ba26a0156cbf1cef2169fd35a18c5a4cced50d475998", "0xa862253c937cf3d75d7183e5f5be6a4385d526aeda5171c1c60a8381fea79f88f5f52a4fab244ecc70765d5765e6dfd5", "0x90cb776f8e5a108f1719df4a355bebb04bf023349356382cae55991b31720f0fd03206b895fa10c56c98f52453be8778", "0xa7614e8d0769dccd520ea4b46f7646e12489951efaef5176bc889e9eb65f6e31758df136b5bf1e9107e68472fa9b46ec", "0xac3a9b80a3254c42e5ed3a090a0dd7aee2352f480de96ad187027a3bb6c791eddfc3074b6ffd74eea825188f107cda4d", "0x82a01d0168238ef04180d4b6e0a0e39024c02c2d75b065017c2928039e154d093e1af4503f4d1f3d8a948917abb5d09f", "0x8fab000a2b0eef851a483aec8d2dd85fe60504794411a2f73ed82e116960547ac58766cb73df71aea71079302630258d", "0x872451a35c6db61c63e9b8bb9f16b217f985c20be4451c14282c814adb29d7fb13f201367c664435c7f1d4d9375d7a58", "0x887d9ff54cc96b35d562df4a537ff972d7c4b3fd91ab06354969a4cfede0b9fc68bbffb61d0dbf1a58948dc701e54f5a", "0x8cb5c2a6bd956875d88f41ae24574434f1308514d44057b55c9c70f13a3366ed054150eed0955a38fda3f757be73d55f", "0x89ad0163cad93e24129d63f8e38422b7674632a8d0a9016ee8636184cab177659a676c4ee7efba3abe1a68807c656d60", "0xb9ec01c7cab6d00359b5a0b4a1573467d09476e05ca51a9227cd16b589a9943d161eef62dcc73f0de2ec504d81f4d252", "0x8031d17635d39dfe9705c485d2c94830b6fc9bc67b91300d9d2591b51e36a782e77ab5904662effa9382d9cca201f525", "0x8be5a5f6bc8d680e5092d6f9a6585acbaaaa2ddc671da560dcf5cfa4472f4f184b9597b5b539438accd40dda885687cc", "0xb1fc0f052fae038a2e3de3b3a96b0a1024b009de8457b8b3adb2d315ae68a89af905720108a30038e5ab8d0d97087785", "0x8b8bdc77bd3a6bc7ca5492b6f8c614852c39a70d6c8a74916eaca0aeb4533b11898b8820a4c2620a97bf35e275480029", "0xaf35f4dc538d4ad5cdf710caa38fd1eb496c3fa890a047b6a659619c5ad3054158371d1e88e0894428282eed9f47f76b", "0x8166454a7089cc07758ad78724654f4e7a1a13e305bbf88ddb86f1a4b2904c4fc8ab872d7da364cdd6a6c0365239e2ad", "0xab287c7d3addce74ce40491871c768abe01daaa0833481276ff2e56926b38a7c6d2681ffe837d2cc323045ad1a4414f9", "0xb90317f4505793094d89365beb35537f55a6b5618904236258dd04ca61f21476837624a2f45fef8168acf732cab65579", "0x98ae5ea27448e236b6657ab5ef7b1cccb5372f92ab25f5fa651fbac97d08353a1dae1b280b1cd42b17d2c6a70a63ab9d", "0xadcf54e752d32cbaa6cb98fbca48d8cd087b1db1d131d465705a0d8042c8393c8f4d26b59006eb50129b21e6240f0c06", "0xb591a3e4db18a7345fa935a8dd7994bbac5cc270b8ebd84c8304c44484c7a74afb45471fdbe4ab22156a30fae1149b40", "0x806b53ac049a42f1dcc1d6335505371da0bf27c614f441b03bbf2e356be7b2fb4eed7117eabcce9e427a542eaa2bf7d8", "0x800482e7a772d49210b81c4a907f5ce97f270b959e745621ee293cf8c71e8989363d61f66a98f2d16914439544ca84c7", "0x99de9eafdad3617445312341644f2bb888680ff01ce95ca9276b1d2e5ef83fa02dab5e948ebf66c17df0752f1bd37b70", "0x961ee30810aa4c93ae157fbe9009b8e443c082192bd36a73a6764ff9b2ad8b0948fe9a73344556e01399dd77badb4257", "0xae0a361067c52efbe56c8adf982c00432cd478929459fc7f74052c8ee9531cd031fe1335418fde53f7c2ef34254eb7ac", "0xa3503d16b6b27eb20c1b177bcf90d13706169220523a6271b85b2ce35a9a2b9c5bed088540031c0a4ebfdae3a4c6ab04", "0x909420122c3e723289ca4e7b81c2df5aff312972a2203f4c45821b176e7c862bf9cac7f7df3adf1d59278f02694d06e7", "0x989f42380ae904b982f85d0c6186c1aef5d6bcba29bcfbb658e811b587eb2749c65c6e4a8cc6409c229a107499a4f5d7", "0x8037a6337195c8e26a27ea4ef218c6e7d79a9720aaab43932d343192abc2320fe72955f5e431c109093bda074103330a", "0xb312e168663842099b88445e940249cc508f080ab0c94331f672e7760258dbd86be5267e4cf25ea25facb80bff82a7e9", "0xaaa3ff8639496864fcdbfdda1ac97edc4f08e3c9288b768f6c8073038c9fbbf7e1c4bea169b4d45c31935cdf0680d45e", "0x97dbd3df37f0b481a311dfc5f40e59227720f367912200d71908ef6650f32cc985cb05b981e3eea38958f7e48d10a15d", "0xa89d49d1e267bb452d6cb621b9a90826fe55e9b489c0427b94442d02a16f390eed758e209991687f73f6b5a032321f42", "0x9530dea4e0e19d6496f536f2e75cf7d814d65fde567055eb20db48fd8d20d501cd2a22fb506db566b94c9ee10f413d43", "0x81a7009b9e67f1965fa7da6a57591c307de91bf0cd35ab4348dc4a98a4961e096d004d7e7ad318000011dc4342c1b809", "0x83440a9402b766045d7aca61a58bba2aa29cac1cf718199e472ba086f5d48093d9dda4d135292ba51d049a23964eceae", "0xa06c9ce5e802df14f6b064a3d1a0735d429b452f0e2e276042800b0a4f16df988fd94cf3945921d5dd3802ab2636f867", "0xb1359e358b89936dee9e678a187aad3e9ab14ac40e96a0a68f70ee2583cdcf467ae03bef4215e92893f4e12f902adec8", "0x835304f8619188b4d14674d803103d5a3fa594d48e96d9699e653115dd05fdc2dda6ba3641cf7ad53994d448da155f02", "0x8327cba5a9ff0d3f5cd0ae55e77167448926d5fcf76550c0ad978092a14122723090c51c415e88e42a2b62eb07cc3981", "0xb373dcdaea85f85ce9978b1426a7ef4945f65f2d3467a9f1cc551a99766aac95df4a09e2251d3f89ca8c9d1a7cfd7b0e", "0xab1422dc41af2a227b973a6fd124dfcb2367e2a11a21faa1d381d404f51b7257e5bc82e9cf20cd7fe37d7ae761a2ab37", "0xa93774a03519d2f20fdf2ef46547b0a5b77c137d6a3434b48d56a2cbef9e77120d1b85d0092cf8842909213826699477", "0x8eb967a495a38130ea28711580b7e61bcd1d051cd9e4f2dbf62f1380bd86e0d60e978d72f6f31e909eb97b3b9a2b867c", "0xae8213378da1287ba1fe4242e1acaec19b877b6fe872400013c6eac1084b8d03156792fa3020201725b08228a1e80f49", "0xb143daf6893d674d607772b3b02d8ac48f294237e2f2c87963c0d4e26d9227d94a2a13512457c3d5883544bbc259f0ef", "0xb343bd2aca8973888e42542218924e2dda2e938fd1150d06878af76f777546213912b7c7a34a0f94186817d80ffa185c", "0xb188ebc6a8c3007001aa347ae72cc0b15d09bc6c19a80e386ee4b334734ec0cc2fe8b493c2422f38d1e6d133cc3db6fe", "0xb795f6a8b9b826aaeee18ccd6baf6c5adeeec85f95eb5b6d19450085ec7217e95a2d9e221d77f583b297d0872073ba0e", "0xb1c7dbd998ad32ae57bfa95deafa147024afd57389e98992c36b6e52df915d3d5a39db585141ec2423173e85d212fed8", "0x812bcdeb9fe5f12d0e1df9964798056e1f1c3de3b17b6bd2919b6356c4b86d8e763c01933efbe0224c86a96d5198a4be", "0xb19ebeda61c23d255cbf472ef0b8a441f4c55b70f0d8ed47078c248b1d3c7c62e076b43b95c00a958ec8b16d5a7cb0d7", "0xb02adc9aaa20e0368a989c2af14ff48b67233d28ebee44ff3418bb0473592e6b681af1cc45450bd4b175df9051df63d9", "0x8d87f0714acee522eb58cec00360e762adc411901dba46adc9227124fa70ee679f9a47e91a6306d6030dd4eb8de2f3c1", "0x8be54cec21e74bcc71de29dc621444263737db15f16d0bb13670f64e42f818154e04b484593d19ef95f2ee17e4b3fe21", "0xab8e20546c1db38d31493b5d5f535758afb17e459645c1b70813b1cf7d242fd5d1f4354a7c929e8f7259f6a25302e351", "0x89f035a1ed8a1e302ac893349ba8ddf967580fcb6e73d44af09e3929cde445e97ff60c87dafe489e2c0ab9c9986cfa00", "0x8b2b0851a795c19191a692af55f7e72ad2474efdc5401bc3733cfdd910e34c918aaebe69d5ea951bdddf3c01cabbfc67", "0xa4edb52c2b51495ccd1ee6450fc14b7b3ede8b3d106808929d02fb31475bacb403e112ba9c818d2857651e508b3a7dd1", "0x9569341fded45d19f00bcf3cbf3f20eb2b4d82ef92aba3c8abd95866398438a2387437e580d8b646f17cf6fde8c5af23", "0xaa4b671c6d20f72f2f18a939a6ff21cc37e0084b44b4a717f1be859a80b39fb1be026b3205adec2a66a608ec2bcd578f", "0x94902e980de23c4de394ad8aec91b46f888d18f045753541492bfbb92c59d3daa8de37ae755a6853744af8472ba7b72b", "0xaf651ef1b2a0d30a7884557edfad95b6b5d445a7561caebdc46a485aedd25932c62c0798465c340a76f6feaa196dd712", "0xb7b669b8e5a763452128846dd46b530dca4893ace5cc5881c7ddcd3d45969d7e73fbebdb0e78aa81686e5f7b22ec5759", "0x82507fd4ebe9fa656a7f2e084d64a1fa6777a2b0bc106d686e2d9d2edafc58997e58cb6bfd0453b2bf415704aa82ae62", "0xb40bce2b42b88678400ecd52955bbdadd15f8b9e1b3751a1a3375dc0efb5ca3ee258cf201e1140b3c09ad41217d1d49e", "0xb0210d0cbb3fbf3b8cdb39e862f036b0ff941cd838e7aaf3a8354e24246e64778d22f3de34572e6b2a580614fb6425be", "0x876693cba4301b251523c7d034108831df3ce133d8be5a514e7a2ca494c268ca0556fa2ad8310a1d92a16b55bcd99ea9", "0x8660281406d22a4950f5ef050bf71dd3090edb16eff27fa29ef600cdea628315e2054211ed2cc6eaf8f2a1771ef689fd", "0xa610e7e41e41ab66955b809ba4ade0330b8e9057d8efc9144753caed81995edeb1a42a53f93ce93540feca1fae708dac", "0xa49e2c176a350251daef1218efaccc07a1e06203386ede59c136699d25ca5cb2ac1b800c25b28dd05678f14e78e51891", "0x83e0915aa2b09359604566080d411874af8c993beba97d4547782fdbe1a68e59324b800ff1f07b8db30c71adcbd102a8", "0xa19e84e3541fb6498e9bb8a099c495cbfcad113330e0262a7e4c6544495bb8a754b2208d0c2d895c93463558013a5a32", "0x87f2bd49859a364912023aca7b19a592c60214b8d6239e2be887ae80b69ebdeb59742bdebcfa73a586ab23b2c945586c", "0xb8e8fdddae934a14b57bc274b8dcd0d45ebb95ddbaabef4454e0f6ce7d3a5a61c86181929546b3d60c447a15134d08e1", "0x87e0c31dcb736ea4604727e92dc1d9a3cf00adcff79df3546e02108355260f3dd171531c3c0f57be78d8b28058fcc8c0", "0x9617d74e8f808a4165a8ac2e30878c349e1c3d40972006f0787b31ea62d248c2d9f3fc3da83181c6e57e95feedfd0e8c", "0x8949e2cee582a2f8db86e89785a6e46bc1565c2d8627d5b6bf43ba71ffadfab7e3c5710f88dcb5fb2fc6edf6f4fae216", "0xad3fa7b0edceb83118972a2935a09f409d09a8db3869f30be3a76f67aa9fb379cabb3a3aff805ba023a331cad7d7eb64", "0x8c95718a4112512c4efbd496be38bf3ca6cdcaad8a0d128f32a3f9aae57f3a57bdf295a3b372a8c549fda8f4707cffed", "0x88f3261d1e28a58b2dee3fcc799777ad1c0eb68b3560f9b4410d134672d9533532a91ea7be28a041784872632d3c9d80", "0xb47472a41d72dd2e8b72f5c4f8ad626737dde3717f63d6bc776639ab299e564cbad0a2ad5452a07f02ff49a359c437e5", "0x9896d21dc2e8aad87b76d6df1654f10cd7bceed4884159d50a818bea391f8e473e01e14684814c7780235f28e69dca6e", "0x82d47c332bbd31bbe83b5eb44a23da76d4a7a06c45d7f80f395035822bc27f62f59281d5174e6f8e77cc9b5c3193d6f0", "0x95c74cd46206e7f70c9766117c34c0ec45c2b0f927a15ea167901a160e1530d8522943c29b61e03568aa0f9c55926c53", "0xa89d7757825ae73a6e81829ff788ea7b3d7409857b378ebccd7df73fdbe62c8d9073741cf038314971b39af6c29c9030", "0x8c1cd212d0b010905d560688cfc036ae6535bc334fa8b812519d810b7e7dcf1bb7c5f43deaa40f097158358987324a7f", "0xb86993c383c015ed8d847c6b795164114dd3e9efd25143f509da318bfba89389ea72a420699e339423afd68b6512fafb", "0x8d06bd379c6d87c6ed841d8c6e9d2d0de21653a073725ff74be1934301cc3a79b81ef6dd0aad4e7a9dc6eac9b73019bc", "0x81af4d2d87219985b9b1202d724fe39ef988f14fef07dfe3c3b11714e90ffba2a97250838e8535eb63f107abfe645e96", "0x8c5e0af6330a8becb787e4b502f34f528ef5756e298a77dc0c7467433454347f3a2e0bd2641fbc2a45b95e231c6e1c02", "0x8e2a8f0f04562820dc8e7da681d5cad9fe2e85dd11c785fb6fba6786c57a857e0b3bd838fb849b0376c34ce1665e4837", "0xa39be8269449bfdfc61b1f62077033649f18dae9bef7c6163b9314ca8923691fb832f42776f0160b9e8abd4d143aa4e1", "0x8c154e665706355e1cc98e0a4cabf294ab019545ba9c4c399d666e6ec5c869ca9e1faf8fb06cd9c0a5c2f51a7d51b70a", "0xa046a7d4de879d3ebd4284f08f24398e9e3bf006cd4e25b5c67273ade248689c69affff92ae810c07941e4904296a563", "0xafd94c1cb48758e5917804df03fb38a6da0e48cd9b6262413ea13b26973f9e266690a1b7d9d24bbaf7e82718e0e594b0", "0x859e21080310c8d6a38e12e2ac9f90a156578cdeb4bb2e324700e97d9a5511cd6045dc39d1d0de3f94aeed043a24119d", "0xa219fb0303c379d0ab50893264919f598e753aac9065e1f23ef2949abc992577ab43c636a1d2c089203ec9ddb941e27d", "0xb0fdb639d449588a2ca730afcba59334e7c387342d56defdfb7ef79c493f7fd0e5277eff18e7203e756c7bdda5803047", "0x87f9c3b7ed01f54368aca6dbcf2f6e06bff96e183c4b2c65f8baa23b377988863a0a125d5cdd41a072da8462ced4c070", "0x99ef7a5d5ac2f1c567160e1f8c95f2f38d41881850f30c461a205f7b1b9fb181277311333839b13fb3ae203447e17727", "0xaeaca9b1c2afd24e443326cc68de67b4d9cedb22ad7b501a799d30d39c85bb2ea910d4672673e39e154d699e12d9b3dc", "0xa11675a1721a4ba24dd3d0e4c3c33a6edf4cd1b9f6b471070b4386c61f77452266eae6e3f566a40cfc885eada9a29f23", "0xb228334445e37b9b49cb4f2cc56b454575e92173ddb01370a553bba665adadd52df353ad74470d512561c2c3473c7bb9", "0xa18177087c996572d76f81178d18ed1ceebc8362a396348ce289f1d8bd708b9e99539be6fccd4acb1112381cfc5749b4", "0x8e7b8bf460f0d3c99abb19803b9e43422e91507a1c0c22b29ee8b2c52d1a384da4b87c292e28eff040db5be7b1f8641f", "0xb03d038d813e29688b6e6f444eb56fec3abba64c3d6f890a6bcf2e916507091cdb2b9d2c7484617be6b26552ed1c56cb", "0xa1c88ccd30e934adfc5494b72655f8afe1865a84196abfb376968f22ddc07761210b6a9fb7638f1413d1b4073d430290", "0x961b714faebf172ad2dbc11902461e286e4f24a99a939152a53406117767682a571057044decbeb3d3feef81f4488497", "0xa03dc4059b46effdd786a0a03cc17cfee8585683faa35bb07936ded3fa3f3a097f518c0b8e2db92fd700149db1937789", "0xadf60180c99ca574191cbcc23e8d025b2f931f98ca7dfcebfc380226239b6329347100fcb8b0fcb12db108c6ad101c07", "0x805d4f5ef24d46911cbf942f62cb84b0346e5e712284f82b0db223db26d51aabf43204755eb19519b00e665c7719fcaa", "0x8dea7243e9c139662a7fe3526c6c601eee72fd8847c54c8e1f2ad93ef7f9e1826b170afe58817dac212427164a88e87f", "0xa2ba42356606d651b077983de1ad643650997bb2babb188c9a3b27245bb65d2036e46667c37d4ce02cb1be5ae8547abe", "0xaf2ae50b392bdc013db2d12ce2544883472d72424fc767d3f5cb0ca2d973fc7d1f425880101e61970e1a988d0670c81b", "0x98e6bec0568d3939b31d00eb1040e9b8b2a35db46ddf4369bdaee41bbb63cc84423d29ee510a170fb5b0e2df434ba589", "0x822ff3cd12fbef4f508f3ca813c04a2e0b9b799c99848e5ad3563265979e753ee61a48f6adc2984a850f1b46c1a43d35", "0x891e8b8b92a394f36653d55725ef514bd2e2a46840a0a2975c76c2a935577f85289026aaa74384da0afe26775cbddfb9", "0xb2a3131a5d2fe7c8967047aa66e4524babae941d90552171cc109527f345f42aa0df06dcbb2fa01b33d0043917bbed69", "0x80c869469900431f3eeefafdbe07b8afd8cee7739e659e6d0109b397cacff85a88247698f87dc4e2fe39a592f250ac64", "0x9091594f488b38f9d2bb5df49fd8b4f8829d9c2f11a197dd1431ed5abbc5c954bbde3387088f9ee3a5a834beb7619bce", "0xb472e241e6956146cca57b97a8a204668d050423b4e76f857bad5b47f43b203a04c8391ba9d9c3e95093c071f9d376a1", "0xb7dd2de0284844392f7dfb56fe7ca3ede41e27519753ffc579a0a8d2d65ceb8108d06b6b0d4c3c1a2588951297bd1a1e", "0x902116ce70d0a079ac190321c1f48701318c05f8e69ee09694754885d33a835a849cafe56f499a2f49f6cda413ddf9a7", "0xb18105cc736787fafaf7c3c11c448bce9466e683159dff52723b7951dff429565e466e4841d982e3aaa9ee2066838666", "0x97ab9911f3f659691762d568ae0b7faa1047b0aed1009c319fa79d15d0db8db9f808fc385dc9a68fa388c10224985379", "0xb2a2cba65f5b927e64d2904ba412e2bac1cf18c9c3eda9c72fb70262497ecf505b640827e2afebecf10eebbcf48ccd3e", "0xb36a3fd677baa0d3ef0dac4f1548ff50a1730286b8c99d276a0a45d576e17b39b3cbadd2fe55e003796d370d4be43ce3", "0xa5dfec96ca3c272566e89dc453a458909247e3895d3e44831528130bc47cc9d0a0dac78dd3cad680a4351d399d241967", "0x8029382113909af6340959c3e61db27392531d62d90f92370a432aec3eb1e4c36ae1d4ef2ba8ec6edb4d7320c7a453f6", "0x971d85121ea108e6769d54f9c51299b0381ece8b51d46d49c89f65bedc123bab4d5a8bc14d6f67f4f680077529cbae4c", "0x98ff6afc01d0bec80a278f25912e1b1ebff80117adae72e31d5b9fa4d9624db4ba2065b444df49b489b0607c45e26c4c", "0x8fa29be10fb3ab30ce25920fec0187e6e91e458947009dabb869aade7136c8ba23602682b71e390c251f3743164cbdaa", "0xb3345c89eb1653418fe3940cf3e56a9a9c66526389b98f45ca02dd62bfb37baa69a4baaa7132d7320695f8ea6ad1fd94", "0xb72c7f5541c9ac6b60a7ec9f5415e7fb14da03f7164ea529952a29399f3a071576608dbbcc0d45994f21f92ddbeb1e19", "0xaa3450bb155a5f9043d0ef95f546a2e6ade167280bfb75c9f09c6f9cdb1fffb7ce8181436161a538433afa3681c7a141", "0x92a18fecaded7854b349f441e7102b638ababa75b1b0281dd0bded6541abe7aa37d96693595be0b01fe0a2e2133d50f9", "0x980756ddf9d2253cfe6c94960b516c94889d09e612810935150892627d2ecee9a2517e04968eea295d0106850c04ca44", "0xae68c6ccc454318cdd92f32b11d89116a3b8350207a36d22a0f626718cad671d960090e054c0c77ac3162ae180ecfd4b", "0x99f31f66eaaa551749ad91d48a0d4e3ff4d82ef0e8b28f3184c54e852422ba1bdafd53b1e753f3a070f3b55f3c23b6a2", "0xa44eaeaa6589206069e9c0a45ff9fc51c68da38d4edff1d15529b7932e6f403d12b9387019c44a1488a5d5f27782a51f", "0xb80b5d54d4b344840e45b79e621bd77a3f83fb4ce6d8796b7d6915107b3f3c34d2e7d95bdafd120f285669e5acf2437a", "0xb36c069ec085a612b5908314d6b84c00a83031780261d1c77a0384c406867c9847d5b0845deddfa512cc04a8df2046fb", "0xb09dbe501583220f640d201acea7ee3e39bf9eda8b91aa07b5c50b7641d86d71acb619b38d27835ce97c3759787f08e9", "0x87403d46a2bf63170fff0b857acacf42ee801afe9ccba8e5b4aea967b68eac73a499a65ca46906c2eb4c8f27bc739faa", "0x82b93669f42a0a2aa5e250ffe6097269da06a9c02fcd1801abbad415a7729a64f830754bafc702e64600ba47671c2208", "0x8e3a3029be7edb8dd3ab1f8216664c8dc50d395f603736061d802cef77627db7b859ef287ed850382c13b4d22d6a2d80", "0x968e9ec7194ff424409d182ce0259acd950c384c163c04463bc8700a40b79beba6146d22b7fa7016875a249b7b31c602", "0x8b42c984bbe4996e0c20862059167c6bdc5164b1ffcd928f29512664459212d263e89f0f0e30eed4e672ffa5ed0b01b5", "0x96bac54062110dada905363211133f1f15dc7e4fd80a4c6e4a83bc9a0bcbbaba11cd2c7a13debcf0985e1a954c1da66b", "0xa16dc8a653d67a7cd7ae90b2fffac0bf1ca587005430fe5ba9403edd70ca33e38ba5661d2ed6e9d2864400d997626a62", "0xa68ab11a570a27853c8d67e491591dcba746bfbee08a2e75ae0790399130d027ed387f41ef1d7de8df38b472df309161", "0x92532b74886874447c0300d07eda9bbe4b41ed25349a3da2e072a93fe32c89d280f740d8ff70d5816793d7f2b97373cc", "0x88e35711b471e89218fd5f4d0eadea8a29405af1cd81974427bc4a5fb26ed60798daaf94f726c96e779b403a2cd82820", "0xb5c72aa4147c19f8c4f3a0a62d32315b0f4606e0a7025edc5445571eaf4daff64f4b7a585464821574dd50dbe1b49d08", "0x9305d9b4095258e79744338683fd93f9e657367b3ab32d78080e51d54eec331edbc224fad5093ebf8ee4bd4286757eb8", "0xb2a17abb3f6a05bcb14dc7b98321fa8b46d299626c73d7c6eb12140bf4c3f8e1795250870947af817834f033c88a59d6", "0xb3477004837dbd8ba594e4296f960fc91ab3f13551458445e6c232eb04b326da803c4d93e2e8dcd268b4413305ff84da", "0x924b4b2ebaafdcfdfedb2829a8bf46cd32e1407d8d725a5bd28bdc821f1bafb3614f030ea4352c671076a63494275a3f", "0x8b81b9ef6125c82a9bece6fdcb9888a767ac16e70527753428cc87c56a1236e437da8be4f7ecfe57b9296dc3ae7ba807", "0x906e19ec8b8edd58bdf9ae05610a86e4ea2282b1bbc1e8b00b7021d093194e0837d74cf27ac9916bdb8ec308b00da3da", "0xb41c5185869071760ac786078a57a2ab4e2af60a890037ac0c0c28d6826f15c2cf028fddd42a9b6de632c3d550bfbc14", "0xa646e5dec1b713ae9dfdf7bdc6cd474d5731a320403c7dfcfd666ffc9ae0cff4b5a79530e8df3f4aa9cb80568cb138e9", "0xb0efad22827e562bd3c3e925acbd0d9425d19057868608d78c2209a531cccd0f2c43dc5673acf9822247428ffa2bb821", "0xa94c19468d14b6f99002fc52ac06bbe59e5c472e4a0cdb225144a62f8870b3f10593749df7a2de0bd3c9476ce682e148", "0x803864a91162f0273d49271dafaab632d93d494d1af935aefa522768af058fce52165018512e8d6774976d52bd797e22", "0xa08711c2f7d45c68fb340ac23597332e1bcaec9198f72967b9921204b9d48a7843561ff318f87908c05a44fc35e3cc9d", "0x91c3cad94a11a3197ae4f9461faab91a669e0dddb0371d3cab3ed9aeb1267badc797d8375181130e461eadd05099b2a2", "0x81bdaaf48aae4f7b480fc13f1e7f4dd3023a41439ba231760409ce9292c11128ab2b0bdbbf28b98af4f97b3551f363af", "0x8d60f9df9fd303f625af90e8272c4ecb95bb94e6efc5da17b8ab663ee3b3f673e9f6420d890ccc94acf4d2cae7a860d8", "0xa7b75901520c06e9495ab983f70b61483504c7ff2a0980c51115d11e0744683ce022d76e3e09f4e99e698cbd21432a0d", "0x82956072df0586562fda7e7738226f694e1c73518dd86e0799d2e820d7f79233667192c9236dcb27637e4c65ef19d493", "0xa586beb9b6ffd06ad200957490803a7cd8c9bf76e782734e0f55e04a3dc38949de75dc607822ec405736c576cf83bca3", "0xa179a30d00def9b34a7e85607a447eea0401e32ab5abeee1a281f2acd1cf6ec81a178020666f641d9492b1bdf66f05a3", "0x83e129705c538787ed8e0fdc1275e6466a3f4ee21a1e6abedd239393b1df72244723b92f9d9d9339a0cab6ebf28f5a16", "0x811bd8d1e3722b64cd2f5b431167e7f91456e8bba2cc669d3fbbce7d553e29c3c19f629fcedd2498bc26d33a24891d17", "0xa243c030c858f1f60cccd26b45b024698cc6d9d9e6198c1ed4964a235d9f8d0baf9cde10c8e63dfaa47f8e74e51a6e85", "0xab839eb82e23ca52663281f863b55b0a3d6d4425c33ffb4eeb1d7979488ab068bf99e2a60e82cea4dc42c56c26cbfebe", "0x8b896f9bb21d49343e67aec6ad175b58c0c81a3ca73d44d113ae4354a0065d98eb1a5cafedaf232a2bb9cdc62152f309", "0xaf6230340cc0b66f5bf845540ed4fc3e7d6077f361d60762e488d57834c3e7eb7eacc1b0ed73a7d134f174a01410e50c", "0x88975e1b1af678d1b5179f72300a30900736af580dd748fd9461ef7afccc91ccd9bed33f9da55c8711a7635b800e831f", "0xa97486bb9047391661718a54b8dd5a5e363964e495eae6c692730264478c927cf3e66dd3602413189a3699fbeae26e15", "0xa5973c161ab38732885d1d2785fd74bf156ba34881980cba27fe239caef06b24a533ffe6dbbbeca5e6566682cc00300a", "0xa24776e9a840afda0003fa73b415d5bd6ecd9b5c2cc842b643ee51b8c6087f4eead4d0bfbd987eb174c489a7b952ff2a", "0xa8a6ee06e3af053b705a12b59777267c546f33ba8a0f49493af8e6df4e15cf8dd2d4fb4daf7e84c6b5d3a7363118ff03", "0xa28e59ce6ad02c2ce725067c0123117e12ac5a52c8f5af13eec75f4a9efc4f696777db18a374fa33bcae82e0734ebd16", "0x86dfc3b78e841c708aff677baa8ee654c808e5d257158715097c1025d46ece94993efe12c9d188252ad98a1e0e331fec", "0xa88d0275510f242eab11fdb0410ff6e1b9d7a3cbd3658333539815f1b450a84816e6613d15aa8a8eb15d87cdad4b27a2", "0x8440acea2931118a5b481268ff9f180ee4ede85d14a52c026adc882410825b8275caa44aff0b50c2b88d39f21b1a0696", "0xa7c3182eab25bd6785bacf12079d0afb0a9b165d6ed327814e2177148539f249eb9b5b2554538f54f3c882d37c0a8abe", "0x85291fbe10538d7da38efdd55a7acebf03b1848428a2f664c3ce55367aece60039f4f320b1771c9c89a35941797f717c", "0xa2c6414eeb1234728ab0de94aa98fc06433a58efa646ca3fcbd97dbfb8d98ae59f7ce6d528f669c8149e1e13266f69c9", "0x840c8462785591ee93aee2538d9f1ec44ba2ca61a569ab51d335ac873f5d48099ae8d7a7efa0725d9ff8f9475bfa4f56", "0xa7065a9d02fb3673acf7702a488fbc01aa69580964932f6f40b6c2d1c386b19e50b0e104fcac24ea26c4e723611d0238", "0xb72db6d141267438279e032c95e6106c2ccb3164b842ba857a2018f3a35f4b040da92680881eb17cd61d0920d5b8f006", "0xa8005d6c5960e090374747307ef0be2871a7a43fa4e76a16c35d2baab808e9777b496e9f57a4218b23390887c33a0b55", "0x8e152cea1e00a451ca47c20a1e8875873419700af15a5f38ee2268d3fbc974d4bd5f4be38008fa6f404dbdedd6e6e710", "0xa3391aed1fcd68761f06a7d1008ec62a09b1cb3d0203cd04e300a0c91adfed1812d8bc1e4a3fd7976dc0aae0e99f52f1", "0x967eb57bf2aa503ee0c6e67438098149eac305089c155f1762cf5e84e31f0fbf27c34a9af05621e34645c1ec96afaec8", "0x88af97ddc4937a95ec0dcd25e4173127260f91c8db2f6eac84afb789b363705fb3196235af631c70cafd09411d233589", "0xa32df75b3f2c921b8767638fd289bcfc61e08597170186637a7128ffedd52c798c434485ac2c7de07014f9e895c2c3d8", "0xb0a783832153650aa0d766a3a73ec208b6ce5caeb40b87177ffc035ab03c7705ecdd1090b6456a29f5fb7e90e2fa8930", "0xb59c8e803b4c3486777d15fc2311b97f9ded1602fa570c7b0200bada36a49ee9ef4d4c1474265af8e1c38a93eb66b18b", "0x982f2c85f83e852022998ff91bafbb6ff093ef22cf9d5063e083a48b29175ccbd51b9c6557151409e439096300981a6c", "0x939e3b5989fefebb9d272a954659a4eb125b98c9da6953f5e628d26266bd0525ec38304b8d56f08d65abc4d6da4a8dbb", "0x8898212fe05bc8de7d18503cb84a1c1337cc2c09d1eeef2b475aa79185b7322bf1f8e065f1bf871c0c927dd19faf1f6d", "0x94b0393a41cd00f724aee2d4bc72103d626a5aecb4b5486dd1ef8ac27528398edf56df9db5c3d238d8579af368afeb09", "0x96ac564450d998e7445dd2ea8e3fc7974d575508fa19e1c60c308d83b645864c029f2f6b7396d4ff4c1b24e92e3bac37", "0x8adf6638e18aff3eb3b47617da696eb6c4bdfbecbbc3c45d3d0ab0b12cbad00e462fdfbe0c35780d21aa973fc150285e", "0xb53f94612f818571b5565bbb295e74bada9b5f9794b3b91125915e44d6ddcc4da25510eab718e251a09c99534d6042d9", "0x8b96462508d77ee083c376cd90807aebad8de96bca43983c84a4a6f196d5faf6619a2351f43bfeec101864c3bf255519", "0xaeadf34657083fc71df33bd44af73bf5281c9ca6d906b9c745536e1819ea90b56107c55e2178ebad08f3ba75b3f81c86", "0x9784ba29b2f0057b5af1d3ab2796d439b8753f1f749c73e791037461bdfc3f7097394283105b8ab01788ea5255a96710", "0x8756241bda159d4a33bf74faba0d4594d963c370fb6a18431f279b4a865b070b0547a6d1613cf45b8cfb5f9236bbf831", "0xb03ebfd6b71421dfd49a30460f9f57063eebfe31b9ceaa2a05c37c61522b35bdc09d7db3ad75c76c253c00ba282d3cd2", "0xb34e7e6341fa9d854b2d3153bdda0c4ae2b2f442ab7af6f99a0975d45725aa48e36ae5f7011edd249862e91f499687d4", "0xb462ee09dc3963a14354244313e3444de5cc37ea5ccfbf14cd9aca8027b59c4cb2a949bc30474497cab8123e768460e6", "0xaea753290e51e2f6a21a9a0ee67d3a2713f95c2a5c17fe41116c87d3aa77b1683761264d704df1ac34f8b873bc88ef7b", "0x98430592afd414394f98ddfff9f280fcb1c322dbe3510f45e1e9c4bb8ee306b3e0cf0282c0ee73ebb8ba087d4d9e0858", "0xb95d3b5aaf54ffca11f4be8d57f76e14afdb20afc859dc7c7471e0b42031e8f3d461b726ecb979bdb2f353498dfe95ea", "0x984d17f9b11a683132e0b5a9ee5945e3ff7054c2d5c716be73b29078db1d36f54c6e652fd2f52a19da313112e97ade07", "0xab232f756b3fff3262be418a1af61a7e0c95ceebbc775389622a8e10610508cd6784ab7960441917a83cc191c58829ea", "0xa28f41678d6e60de76b0e36ab10e4516e53e02e9c77d2b5af3cfeee3ce94cfa30c5797bd1daab20c98e1cad83ad0f633", "0xb55395fca84dd3ccc05dd480cb9b430bf8631ff06e24cb51d54519703d667268c2f8afcde4ba4ed16bece8cc7bc8c6e0", "0x8a8a5392a0e2ea3c7a8c51328fab11156004e84a9c63483b64e8f8ebf18a58b6ffa8fe8b9d95af0a2f655f601d096396", "0xab480000fe194d23f08a7a9ec1c392334e9c687e06851f083845121ce502c06b54dda8c43092bcc1035df45cc752fe9b", "0xb265644c29f628d1c7e8e25a5e845cabb21799371814730a41a363e1bda8a7be50fee7c3996a365b7fcba4642add10db", "0xb8a915a3c685c2d4728f6931c4d29487cad764c5ce23c25e64b1a3259ac27235e41b23bfe7ae982921b4cb84463097df", "0x8efa7338442a4b6318145a5440fc213b97869647eeae41b9aa3c0a27ee51285b73e3ae3b4a9423df255e6add58864aa9", "0x9106d65444f74d217f4187dfc8fcf3810b916d1e4275f94f6a86d1c4f3565b131fd6cde1fa708bc05fe183c49f14941a", "0x948252dac8026bbbdb0a06b3c9d66ec4cf9532163bab68076fda1bd2357b69e4b514729c15aaa83b5618b1977bbc60c4", "0xae6596ccfdf5cbbc5782efe3bb0b101bb132dbe1d568854ca24cacc0b2e0e9fabcb2ca7ab42aecec412efd15cf8cb7a2", "0x84a0b6c198ff64fd7958dfd1b40eac9638e8e0b2c4cd8cf5d8cdf80419baee76a05184bce6c5b635f6bf2d30055476a7", "0x8893118be4a055c2b3da593dbca51b1ae2ea2469911acfb27ee42faf3e6c3ad0693d3914c508c0b05b36a88c8b312b76", "0xb097479e967504deb6734785db7e60d1d8034d6ca5ba9552887e937f5e17bb413fccac2c1d1082154ed76609127860ad", "0xa0294e6b9958f244d29943debf24b00b538b3da1116269b6e452bb12dc742226712fd1a15b9c88195afeb5d2415f505c", "0xb3cc15f635080bc038f61b615f62b5b5c6f2870586191f59476e8368a73641d6ac2f7d0c1f54621982defdb318020230", "0x99856f49b9fe1604d917c94d09cc0ed753d13d015d30587a94e6631ffd964b214e607deb8a69a8b5e349a7edf4309206", "0xa8571e113ea22b4b4fce41a094da8c70de37830ae32e62c65c2fa5ad06a9bc29e884b945e73d448c72b176d6ecebfb58", "0xa9e9c6e52beb0013273c29844956b3ce291023678107cdc785f7b44eff5003462841ad8780761b86aefc6b734adde7cf", "0x80a784b0b27edb51ef2bad3aee80e51778dcaa0f3f5d3dcb5dc5d4f4b2cf7ae35b08de6680ea9dac53f8438b92eb09ef", "0x827b543e609ea328e97e373f70ad72d4915a2d1daae0c60d44ac637231070e164c43a2a58db80a64df1c624a042b38f9", "0xb449c65e8195202efdcb9bdb4e869a437313b118fef8b510cbbf8b79a4e99376adb749b37e9c20b51b31ed3310169e27", "0x8ea3028f4548a79a94c717e1ed28ad4d8725b8d6ab18b021063ce46f665c79da3c49440c6577319dab2d036b7e08f387", "0x897798431cfb17fe39f08f5f854005dc37b1c1ec1edba6c24bc8acb3b88838d0534a75475325a5ea98b326ad47dbad75", "0x89cf232e6303b0751561960fd4dea5754a28c594daf930326b4541274ffb03c7dd75938e411eb9a375006a70ce38097f", "0x9727c6ae7f0840f0b6c8bfb3a1a5582ceee705e0b5c59b97def7a7a2283edd4d3f47b7971e902a3a2079e40b53ff69b8", "0xb76ed72b122c48679d221072efc0eeea063cb205cbf5f9ef0101fd10cb1075b8628166c83577cced654e1c001c7882f7", "0xae908c42d208759da5ee9b405df85a6532ea35c6f0f6a1288d22870f59d98edc896841b8ac890a538e6c8d1e8b02d359", "0x809d12fe4039a0ec80dc9be6a89acaab7797e5f7f9b163378f52f9a75a1d73b2e9ae6e3dd49e32ced439783c1cabbef5", "0xa4149530b7f85d1098ba534d69548c6c612c416e8d35992fc1f64f4deeb41e09e49c6cf7aadbed7e846b91299358fe2d", "0xa49342eacd1ec1148b8df1e253b1c015f603c39de11fa0a364ccb86ea32d69c34fd7aa6980a1fadcd8e785a57fa46f60", "0x87d43eff5a006dc4dddcf76cc96c656a1f3a68f19f124181feab86c6cc9a52cb9189cdbb423414defdd9bb0ca8ff1ddc", "0x861367e87a9aa2f0f68296ba50aa5dbc5713008d260cc2c7e62d407c2063064749324c4e8156dc21b749656cfebce26b", "0xb5303c2f72e84e170e66ae1b0fbd51b8c7a6f27476eaf5694b64e8737d5c84b51fe90100b256465a4c4156dd873cddb0", "0xb62849a4f891415d74f434cdc1d23c4a69074487659ca96e1762466b2b7a5d8525b056b891d0feea6fe6845cba8bc7fb", "0x923dd9e0d6590a9307e8c4c23f13bae3306b580e297a937711a8b13e8de85e41a61462f25b7d352b682e8437bf2b4ab3", "0x9147379860cd713cd46c94b8cdf75125d36c37517fbecf81ace9680b98ce6291cd1c3e472f84249cc3b2b445e314b1b6", "0xa808a4f17ac21e3fb5cfef404e61fae3693ca3e688d375f99b6116779696059a146c27b06de3ac36da349b0649befd56", "0x87787e9322e1b75e66c1f0d9ea0915722a232770930c2d2a95e9478c4b950d15ab767e30cea128f9ed65893bfc2d0743", "0x9036a6ee2577223be105defe1081c48ea7319e112fff9110eb9f61110c319da25a6cea0464ce65e858635b079691ef1f", "0xaf5548c7c24e1088c23b57ee14d26c12a83484c9fd9296edf1012d8dcf88243f20039b43c8c548c265ef9a1ffe9c1c88", "0xa0fff520045e14065965fb8accd17e878d3fcaf9e0af2962c8954e50be6683d31fa0bf4816ab68f08630dbac6bfce52a", "0xb4c1b249e079f6ae1781af1d97a60b15855f49864c50496c09c91fe1946266915b799f0406084d7783f5b1039116dd8b", "0x8b0ffa5e7c498cb3879dddca34743b41eee8e2dea3d4317a6e961b58adb699ef0c92400c068d5228881a2b08121226bf", "0x852ae8b19a1d80aa8ae5382e7ee5c8e7670ceb16640871c56b20b96b66b3b60e00015a3dde039446972e57b49a999ddd", "0xa49942f04234a7d8492169da232cfff8051df86e8e1ba3db46aede02422c689c87dc1d99699c25f96cb763f5ca0983e5", "0xb04b597b7760cf5dcf411ef896d1661e6d5b0db3257ac2cf64b20b60c6cc18fa10523bb958a48d010b55bac7b02ab3b1", "0xa494591b51ea8285daecc194b5e5bd45ae35767d0246ac94fae204d674ee180c8e97ff15f71f28b7aeb175b8aea59710", "0x97d2624919e78406e7460730680dea8e71c8571cf988e11441aeea54512b95bd820e78562c99372d535d96f7e200d20d", "0xac693ddb00e48f76e667243b9b6a7008424043fb779e4f2252330285232c3fccac4da25cbd6d95fe9ad959ff305a91f6", "0x8d20ca0a71a64a3f702a0825bb46bd810d03bebfb227683680d474a52f965716ff99e19a165ebaf6567987f4f9ee3c94", "0xa5c516a438f916d1d68ca76996404792e0a66e97b7f18fc54c917bf10cf3211b62387932756e39e67e47b0bd6e88385a", "0xb089614d830abc0afa435034cec7f851f2f095d479cacf1a3fb57272da826c499a52e7dcbc0eb85f4166fb94778e18e9", "0xa8dacc943765d930848288192f4c69e2461c4b9bc6e79e30eeef9a543318cf9ae9569d6986c65c5668a89d49993f8e07", "0xab5a9361fa339eec8c621bdad0a58078983abd8942d4282b22835d7a3a47e132d42414b7c359694986f7db39386c2e19", "0x94230517fb57bd8eb26c6f64129b8b2abd0282323bf7b94b8bac7fab27b4ecc2c4290c294275e1a759de19f2216134f3", "0xb8f158ea5006bc3b90b285246625faaa6ac9b5f5030dc69701b12f3b79a53ec7e92eeb5a63bbd1f9509a0a3469ff3ffc", "0x8b6944fd8cb8540957a91a142fdcda827762aa777a31e8810ca6d026e50370ee1636fc351724767e817ca38804ebe005", "0x82d1ee40fe1569c29644f79fa6c4033b7ed45cd2c3b343881f6eb0de2e79548fded4787fae19bed6ee76ed76ff9f2f11", "0xa8924c7035e99eaed244ca165607e7e568b6c8085510dcdbaf6ebdbed405af2e6c14ee27d94ffef10d30aa52a60bf66d", "0x956f82a6c2ae044635e85812581e4866c5fa2f427b01942047d81f6d79a14192f66fbbe77c9ffeaef4e6147097fdd2b5", "0xb1100255a1bcf5e05b6aff1dfeb6e1d55b5d68d43a7457ba10cc76b61885f67f4d0d5179abda786e037ae95deb8eea45", "0x99510799025e3e5e8fbf06dedb14c060c6548ba2bda824f687d3999dc395e794b1fb6514b9013f3892b6cf65cb0d65aa", "0x8f9091cebf5e9c809aab415942172258f894e66e625d7388a05289183f01b8d994d52e05a8e69f784fba41db9ea357f0", "0xa13d2eeb0776bdee9820ecb6693536720232848c51936bb4ef4fe65588d3f920d08a21907e1fdb881c1ad70b3725e726", "0xa68b8f18922d550284c5e5dc2dda771f24c21965a6a4d5e7a71678178f46df4d8a421497aad8fcb4c7e241aba26378a0", "0x8b7601f0a3c6ad27f03f2d23e785c81c1460d60100f91ea9d1cab978aa03b523150206c6d52ce7c7769c71d2c8228e9e", "0xa8e02926430813caa851bb2b46de7f0420f0a64eb5f6b805401c11c9091d3b6d67d841b5674fa2b1dce0867714124cd8", "0xb7968ecba568b8193b3058400af02c183f0a6df995a744450b3f7e0af7a772454677c3857f99c140bbdb2a09e832e8e0", "0x8f20b1e9ba87d0a3f35309b985f3c18d2e8800f1ca7f0c52cadef773f1496b6070c936eea48c4a1cae83fd2524e9d233", "0x88aef260042db0d641a51f40639dbeeefa9e9811df30bee695f3791f88a2f84d318f04e8926b7f47bf25956cb9e3754f", "0x9725345893b647e9ba4e6a29e12f96751f1ae25fcaec2173e9a259921a1a7edb7a47159b3c8767e44d9e2689f5aa0f72", "0x8c281e6f72752cb11e239e4df9341c45106eb7993c160e54423c2bffe10bc39d42624b45a1f673936ef2e1a02fc92f1a", "0x90aba2f68bddb2fcce6c51430dacdfeec43ea8dc379660c99095df11017691ccf5faa27665cf4b9f0eea7728ae53c327", "0xb7022695c16521c5704f49b7ddbdbec9b5f57ce0ceebe537bc0ebb0906d8196cc855a9afeb8950a1710f6a654464d93f", "0x8fe1b9dd3c6a258116415d36e08374e094b22f0afb104385a5da48be17123e86fb8327baacc4f0d9ebae923d55d99bb5", "0x817e85d8e3d19a4cbc1dec31597142c2daa4871bda89c2177fa719c00eda3344eb08b82eb92d4aa91a9eaacb3fc09783", "0xb59053e1081d2603f1ca0ba553804d6fa696e1fd996631db8f62087b26a40dfef02098b0326bb75f99ec83b9267ca738", "0x990a173d857d3ba81ff3789b931bfc9f5609cde0169b7f055fa3cb56451748d593d62d46ba33f80f9cafffe02b68dd14", "0xb0c538dbba4954b809ab26f9f94a3cf1dcb77ce289eaec1d19f556c0ae4be1fa03af4a9b7057837541c3cc0a80538736", "0xac3ba42f5f44f9e1fc453ce49c4ab79d0e1d5c42d3b30b1e098f3ab3f414c4c262fa12fb2be249f52d4aaf3c5224beb9", "0xaf47467eb152e59870e21f0d4da2f43e093daf40180ab01438030684b114d025326928eaab12c41b81a066d94fce8436", "0x98d1b58ba22e7289b1c45c79a24624f19b1d89e00f778eef327ec4856a9a897278e6f1a9a7e673844b31dde949153000", "0x97ccb15dfadc7c59dca08cfe0d22df2e52c684cf97de1d94bc00d7ba24e020025130b0a39c0f4d46e4fc872771ee7875", "0xb699e4ed9a000ff96ca296b2f09dce278832bc8ac96851ff3cff99ed3f6f752cfc0fea8571be28cd9b5a7ec36f1a08ee", "0xb9f49f0edb7941cc296435ff0a912e3ad16848ee8765ab5f60a050b280d6ea585e5b34051b15f6b8934ef01ceb85f648", "0xac3893df7b4ceab23c6b9054e48e8ba40d6e5beda8fbe90b814f992f52494186969b35d8c4cdc3c99890a222c9c09008", "0xa41293ad22fae81dea94467bc1488c3707f3d4765059173980be93995fa4fcc3c9340796e3eed0beeb0ba0d9bb4fa3aa", "0xa0543e77acd2aeecde13d18d258aeb2c7397b77f17c35a1992e8666ea7abcd8a38ec6c2741bd929abba2f766138618cc", "0x92e79b22bc40e69f6527c969500ca543899105837b6b1075fa1796755c723462059b3d1b028e0b3df2559fa440e09175", "0xa1fa1eac8f41a5197a6fb4aa1eae1a031c89f9c13ff9448338b222780cf9022e0b0925d930c37501a0ef7b2b00fdaf83", "0xb3cb29ff73229f0637335f28a08ad8c5f166066f27c6c175164d0f26766a927f843b987ee9b309ed71cbf0a65d483831", "0x84d4ab787f0ac00f104f4a734dc693d62d48c2aeb03913153da62c2ae2c27d11b1110dcef8980368dd84682ea2c1a308", "0xab6a8e4bbc78d4a7b291ad3e9a8fe2d65f640524ba3181123b09d2d18a9e300e2509ccf7000fe47e75b65f3e992a2e7e", "0xb7805ebe4f1a4df414003dc10bca805f2ab86ca75820012653e8f9b79c405196b0e2cab099f2ab953d67f0d60d31a0f9", "0xb12c582454148338ea605d22bd00a754109063e22617f1f8ac8ddf5502c22a181c50c216c3617b9852aa5f26af56b323", "0x86333ad9f898947e31ce747728dc8c887479e18d36ff3013f69ebef807d82c6981543b5c3788af93c4d912ba084d3cba", "0xb514efa310dc4ad1258add138891e540d8c87142a881b5f46563cc58ecd1488e6d3a2fca54c0b72a929f3364ca8c333e", "0xaa0a30f92843cf2f484066a783a1d75a7aa6f41f00b421d4baf20a6ac7886c468d0eea7ca8b17dd22f4f74631b62b640", "0xb3b7dc63baec9a752e8433c0cdee4d0f9bc41f66f2b8d132faf925eef9cf89aae756fc132c45910f057122462605dc10", "0xb9b8190dac5bfdeb59fd44f4da41a57e7f1e7d2c21faba9da91fa45cbeca06dcf299c9ae22f0c89ece11ac46352d619f", "0x89f8cf36501ad8bdfeab863752a9090e3bfda57cf8fdeca2944864dc05925f501e252c048221bcc57136ab09a64b64b2", "0xb0cbfaf317f05f97be47fc9d69eda2dd82500e00d42612f271a1fe24626408c28881f171e855bd5bd67409f9847502b4", "0xa7c21a8fcede581bfd9847b6835eda62ba250bea81f1bb17372c800a19c732abe03064e64a2f865d974fb636cab4b859", "0x95f9df524ba7a4667351696c4176b505d8ea3659f5ff2701173064acc624af69a0fad4970963736383b979830cb32260", "0x856a74fe8b37a2e3afeac858c8632200485d438422a16ae3b29f359e470e8244995c63ad79c7e007ed063f178d0306fd", "0xb37faa4d78fdc0bb9d403674dbea0176c2014a171c7be8527b54f7d1a32a76883d3422a3e7a5f5fcc5e9b31b57822eeb", "0x8d37234d8594ec3fe75670b5c9cc1ec3537564d4739b2682a75b18b08401869a4264c0f264354219d8d896cded715db4", "0xb5289ee5737f0e0bde485d32096d23387d68dab8f01f47821ab4f06cc79a967afe7355e72dc0c751d96b2747b26f6255", "0x9085e1fdf9f813e9c3b8232d3c8863cd84ab30d45e8e0d3d6a0abd9ebc6fd70cdf749ff4d04390000e14c7d8c6655fc7", "0x93a388c83630331eca4da37ea4a97b3b453238af474817cc0a0727fd3138dcb4a22de38c04783ec829c22cb459cb4e8e", "0xa5377116027c5d061dbe24c240b891c08cdd8cd3f0899e848d682c873aff5b8132c1e7cfe76d2e5ed97ee0eb1d42cb68", "0xa274c84b04338ed28d74683e2a7519c2591a3ce37c294d6f6e678f7d628be2db8eff253ede21823e2df7183e6552f622", "0x8bc201147a842453a50bec3ac97671397bc086d6dfc9377fa38c2124cdc286abda69b7324f47d64da094ae011d98d9d9", "0x9842d0c066c524592b76fbec5132bc628e5e1d21c424bec4555efca8619cc1fd8ea3161febcb8b9e8ab54702f4e815e2", "0xa19191b713a07efe85c266f839d14e25660ee74452e6c691cd9997d85ae4f732052d802d3deb018bdd847caa298a894b", "0xa24f71fc0db504da4e287dd118a4a74301cbcd16033937ba2abc8417956fcb4ae19b8e63b931795544a978137eff51cb", "0xa90eec4a6a3a4b8f9a5b93d978b5026fcf812fe65585b008d7e08c4aaf21195a1d0699f12fc16f79b6a18a369af45771", "0x8b551cf89737d7d06d9b3b9c4c1c73b41f2ea0af4540999c70b82dabff8580797cf0a3caf34c86c59a7069eb2e38f087", "0xb8d312e6c635e7a216a1cda075ae77ba3e1d2fd501dc31e83496e6e81ed5d9c7799f8e578869c2e0e256fb29f5de10a7", "0x8d144bdb8cae0b2cdb5b33d44bbc96984a5925202506a8cc65eb67ac904b466f5a7fe3e1cbf04aa785bbb7348c4bb73c", "0xa101b3d58b7a98659244b88de0b478b3fb87dc5fc6031f6e689b99edf498abd43e151fd32bd4bbd240e0b3e59c440359", "0x907453abca7d8e7151a05cc3d506c988007692fe7401395dc93177d0d07d114ab6cca0cc658eb94c0223fe8658295cad", "0x825329ffbe2147ddb68f63a0a67f32d7f309657b8e5d9ab5bb34b3730bfa2c77a23eaaadb05def7d9f94a9e08fdc1e96", "0x88ee923c95c1dac99ae7ed6067906d734d793c5dc5d26339c1bb3314abe201c5dccb33b9007351885eb2754e9a8ea06c", "0x98bc9798543f5f1adc9f2cfcfa72331989420e9c3f6598c45269f0dc9b7c8607bbeaf03faa0aea2ddde2b8f17fdceff5", "0x8ee87877702a79aef923ab970db6fa81561b3c07d5bf1a072af0a7bad765b4cbaec910afe1a91703feacc7822fa38a94", "0x8060b9584aa294fe8adc2b22f67e988bc6da768eae91e429dcc43ddc53cfcc5d6753fdc1b420b268c7eb2fb50736a970", "0xb344a5524d80a2f051870c7001f74fcf348a70fcf78dbd20c6ff9ca85d81567d2318c8b8089f2c4f195d6aec9fc15fa6", "0x8f5a5d893e1936ed062149d20eb73d98b62b7f50ab5d93a6429c03656b36688d1c80cb5010e4977491e51fa0d7dd35d5", "0x86fa32ebbf97328c5f5f15564e1238297e289ec3219b9a741724e9f3ae8d5c15277008f555863a478b247ba5dc601d44", "0x9557e55377e279f4b6b5e0ffe01eca037cc13aac242d67dfcd0374a1e775c5ed5cb30c25fe21143fee54e3302d34a3ea", "0x8cb6bcbc39372d23464a416ea7039f57ba8413cf3f00d9a7a5b356ab20dcb8ed11b3561f7bce372b8534d2870c7ee270", "0xb5d59075cb5abde5391f64b6c3b8b50adc6e1f654e2a580b6d6d6eff3f4fbdd8fffc92e06809c393f5c8eab37f774c4b", "0xafcfb6903ef13e493a1f7308675582f15af0403b6553e8c37afb8b2808ad21b88b347dc139464367dc260df075fea1ad", "0x810fbbe808375735dd22d5bc7fc3828dc49fdd22cc2d7661604e7ac9c4535c1df578780affb3b895a0831640a945bcad", "0x8056b0c678803b416f924e09a6299a33cf9ad7da6fe1ad7accefe95c179e0077da36815fde3716711c394e2c5ea7127f", "0x8b67403702d06979be19f1d6dc3ec73cc2e81254d6b7d0cc49cd4fdda8cd51ab0835c1d2d26fc0ecab5df90585c2f351", "0x87f97f9e6d4be07e8db250e5dd2bffdf1390665bc5709f2b631a6fa69a7fca958f19bd7cc617183da1f50ee63e9352b5", "0xae151310985940471e6803fcf37600d7fa98830613e381e00dab943aec32c14162d51c4598e8847148148000d6e5af5c", "0x81eb537b35b7602c45441cfc61b27fa9a30d3998fad35a064e05bc9479e9f10b62eba2b234b348219eea3cadcaac64bb", "0x8a441434934180ab6f5bc541f86ebd06eadbee01f438836d797e930fa803a51510e005c9248cecc231a775b74d12b5e9", "0x81f3c250a27ba14d8496a5092b145629eb2c2e6a5298438670375363f57e2798207832c8027c3e9238ad94ecdadfc4df", "0xa6217c311f2f3db02ceaa5b6096849fe92b6f4b6f1491535ef8525f6ccee6130bed2809e625073ecbaddd4a3eb3df186", "0x82d1c396f0388b942cf22b119d7ef1ad03d3dad49a74d9d01649ee284f377c8daddd095d596871669e16160299a210db", "0xa40ddf7043c5d72a7246bd727b07f7fff1549f0e443d611de6f9976c37448b21664c5089c57f20105102d935ab82f27b", "0xb6c03c1c97adf0c4bf4447ec71366c6c1bff401ba46236cd4a33d39291e7a1f0bb34bd078ba3a18d15c98993b153a279", "0x8a94f5f632068399c359c4b3a3653cb6df2b207379b3d0cdace51afdf70d6d5cce6b89a2b0fee66744eba86c98fb21c2", "0xb2f19e78ee85073f680c3bba1f07fd31b057c00b97040357d97855b54a0b5accb0d3b05b2a294568fcd6a4be6f266950", "0xa74632d13bbe2d64b51d7a9c3ae0a5a971c19f51cf7596a807cea053e6a0f3719700976d4e394b356c0329a2dced9aa2", "0xafef616d341a9bc94393b8dfba68ff0581436aa3a3adb7c26a1bbf2cf19fa877066191681f71f17f3cd6f9cf6bf70b5a", "0x8ce96d93ae217408acf7eb0f9cbb9563363e5c7002e19bbe1e80760bc9d449daee2118f3878b955163ed664516b97294", "0x8414f79b496176bc8b8e25f8e4cfee28f4f1c2ddab099d63d2aca1b6403d26a571152fc3edb97794767a7c4686ad557c", "0xb6c61d01fd8ce087ef9f079bf25bf10090db483dd4f88c4a786d31c1bdf52065651c1f5523f20c21e75cea17df69ab73", "0xa5790fd629be70545093631efadddc136661f63b65ec682609c38ef7d3d7fa4e56bdf94f06e263bc055b90cb1c6bcefe", "0xb515a767e95704fb7597bca9e46f1753abacdc0e56e867ee3c6f4cd382643c2a28e65312c05ad040eaa3a8cbe7217a65", "0x8135806a02ead6aa92e9adb6fefb91349837ab73105aaa7be488ef966aa8dfaafdfa64bbae30fcbfa55dd135a036a863", "0x8f22435702716d76b1369750694540742d909d5e72b54d0878245fab7c269953b1c6f2b29c66f08d5e0263ca3a731771", "0x8e0f8a8e8753e077dac95848212aeffd51c23d9b6d611df8b102f654089401954413ecbedc6367561ca599512ae5dda7", "0x815a9084e3e2345f24c5fa559deec21ee1352fb60f4025c0779be65057f2d528a3d91593bd30d3a185f5ec53a9950676", "0x967e6555ccba395b2cc1605f8484c5112c7b263f41ce8439a99fd1c71c5ed14ad02684d6f636364199ca48afbbde13be", "0x8cd0ccf17682950b34c796a41e2ea7dd5367aba5e80a907e01f4cdc611e4a411918215e5aebf4292f8b24765d73314a6", "0xa58bf1bbb377e4b3915df6f058a0f53b8fb8130fdec8c391f6bc82065694d0be59bb67ffb540e6c42cc8b380c6e36359", "0x92af3151d9e6bfb3383d85433e953c0160859f759b0988431ec5893542ba40288f65db43c78a904325ef8d324988f09d", "0x8011bbb05705167afb47d4425065630f54cb86cd462095e83b81dfebf348f846e4d8fbcf1c13208f5de1931f81da40b9", "0x81c743c104fc3cb047885c9fa0fb9705c3a83ee24f690f539f4985509c3dafd507af3f6a2128276f45d5939ef70c167f", "0xa2c9679b151c041aaf5efeac5a737a8f70d1631d931609fca16be1905682f35e291292874cb3b03f14994f98573c6f44", "0xa4949b86c4e5b1d5c82a337e5ce6b2718b1f7c215148c8bfb7e7c44ec86c5c9476048fc5c01f57cb0920876478c41ad6", "0x86c2495088bd1772152e527a1da0ef473f924ea9ab0e5b8077df859c28078f73c4e22e3a906b507fdf217c3c80808b5c", "0x892e0a910dcf162bcea379763c3e2349349e4cda9402949255ac4a78dd5a47e0bf42f5bd0913951576b1d206dc1e536a", "0xa7009b2c6b396138afe4754b7cc10dee557c51c7f1a357a11486b3253818531f781ea8107360c8d4c3b1cd96282353c0", "0x911763ef439c086065cc7b4e57484ed6d693ea44acee4b18c9fd998116da55fbe7dcb8d2a0f0f9b32132fca82d73dff6", "0xa722000b95a4a2d40bed81870793f15ba2af633f9892df507f2842e52452e02b5ea8dea6a043c2b2611d82376e33742a", "0x9387ac49477bd719c2f92240d0bdfcf9767aad247ca93dc51e56106463206bc343a8ec855eb803471629a66fffb565d6", "0x92819a1fa48ab4902939bb72a0a4e6143c058ea42b42f9bc6cea5df45f49724e2530daf3fc4f097cceefa2a8b9db0076", "0x98eac7b04537653bc0f4941aae732e4b1f84bd276c992c64a219b8715eb1fb829b5cbd997d57feb15c7694c468f95f70", "0xb275e7ba848ce21bf7996e12dbeb8dadb5d0e4f1cb5a0248a4f8f9c9fe6c74e3c93f4b61edbcb0a51af5a141e1c14bc7", "0x97243189285aba4d49c53770c242f2faf5fd3914451da4931472e3290164f7663c726cf86020f8f181e568c72fd172d1", "0x839b0b3c25dd412bee3dc24653b873cc65454f8f16186bb707bcd58259c0b6765fa4c195403209179192a4455c95f3b8", "0x8689d1a870514568a074a38232e2ceb4d7df30fabeb76cff0aed5b42bf7f02baea12c5fadf69f4713464dbd52aafa55f", "0x8958ae7b290f0b00d17c3e9fdb4dbf168432b457c7676829299dd428984aba892de1966fc106cfc58a772862ecce3976", "0xa422bc6bd68b8870cfa5bc4ce71781fd7f4368b564d7f1e0917f6013c8bbb5b240a257f89ecfdbecb40fe0f3aa31d310", "0xaa61f78130cebe09bc9a2c0a37f0dd57ed2d702962e37d38b1df7f17dc554b1d4b7a39a44182a452ce4c5eb31fa4cfcc", "0xb7918bd114f37869bf1a459023386825821bfadce545201929d13ac3256d92a431e34f690a55d944f77d0b652cefeffc", "0x819bba35fb6ace1510920d4dcff30aa682a3c9af9022e287751a6a6649b00c5402f14b6309f0aeef8fce312a0402915e", "0x8b7c9ad446c6f63c11e1c24e24014bd570862b65d53684e107ba9ad381e81a2eaa96731b4b33536efd55e0f055071274", "0x8fe79b53f06d33386c0ec7d6d521183c13199498594a46d44a8a716932c3ec480c60be398650bbfa044fa791c4e99b65", "0x9558e10fb81250b9844c99648cf38fa05ec1e65d0ccbb18aa17f2d1f503144baf59d802c25be8cc0879fff82ed5034ad", "0xb538a7b97fbd702ba84645ca0a63725be1e2891c784b1d599e54e3480e4670d0025526674ef5cf2f87dddf2290ba09f0", "0x92eafe2e869a3dd8519bbbceb630585c6eb21712b2f31e1b63067c0acb5f9bdbbcbdb612db4ea7f9cc4e7be83d31973f", "0xb40d21390bb813ab7b70a010dff64c57178418c62685761784e37d327ba3cb9ef62df87ecb84277c325a637fe3709732", "0xb349e6fbf778c4af35fbed33130bd8a7216ed3ba0a79163ebb556e8eb8e1a7dad3456ddd700dad9d08d202491c51b939", "0xa8fdaedecb251f892b66c669e34137f2650509ade5d38fbe8a05d9b9184bb3b2d416186a3640429bd1f3e4b903c159dd", "0xac6167ebfee1dbab338eff7642f5e785fc21ef0b4ddd6660333fe398068cbd6c42585f62e81e4edbb72161ce852a1a4f", "0x874b1fbf2ebe140c683bd7e4e0ab017afa5d4ad38055aaa83ee6bbef77dbc88a6ce8eb0dcc48f0155244af6f86f34c2d", "0x903c58e57ddd9c446afab8256a6bb6c911121e6ccfb4f9b4ed3e2ed922a0e500a5cb7fa379d5285bc16e11dac90d1fda", "0x8dae7a0cffa2fd166859cd1bf10ff82dd1932e488af377366b7efc0d5dec85f85fe5e8150ff86a79a39cefc29631733a", "0xaa047857a47cc4dfc08585f28640420fcf105b881fd59a6cf7890a36516af0644d143b73f3515ab48faaa621168f8c31", "0x864508f7077c266cc0cb3f7f001cb6e27125ebfe79ab57a123a8195f2e27d3799ff98413e8483c533b46a816a3557f1f", "0x8bcd45ab1f9cbab36937a27e724af819838f66dfeb15923f8113654ff877bd8667c54f6307aaf0c35027ca11b6229bfd", "0xb21aa34da9ab0a48fcfdd291df224697ce0c1ebc0e9b022fdee8750a1a4b5ba421c419541ed5c98b461eecf363047471", "0xa9a18a2ab2fae14542dc336269fe612e9c1af6cf0c9ac933679a2f2cb77d3c304114f4d219ca66fe288adde30716775b", "0xb5205989b92c58bdda71817f9a897e84100b5c4e708de1fced5c286f7a6f01ae96b1c8d845f3a320d77c8e2703c0e8b1", "0xa364059412bbcc17b8907d43ac8e5df90bc87fd1724b5f99832d0d24559fae6fa76a74cff1d1eac8cbac6ec80b44af20", "0xae709f2c339886b31450834cf29a38b26eb3b0779bd77c9ac269a8a925d1d78ea3837876c654b61a8fe834b3b6940808", "0x8802581bba66e1952ac4dab36af371f66778958f4612901d95e5cac17f59165e6064371d02de8fb6fccf89c6dc8bd118", "0xa313252df653e29c672cbcfd2d4f775089cb77be1077381cf4dc9533790e88af6cedc8a119158e7da5bf6806ad9b91a1", "0x992a065b4152c7ef11515cd54ba9d191fda44032a01aed954acff3443377ee16680c7248d530b746b8c6dee2d634e68c", "0xb627b683ee2b32c1ab4ccd27b9f6cce2fe097d96386fa0e5c182ad997c4c422ab8dfc03870cd830b8c774feb66537282", "0xb823cf8a9aee03dadd013eb9efe40a201b4b57ef67efaae9f99683005f5d1bf55e950bf4af0774f50859d743642d3fea", "0xb8a7449ffac0a3f206677097baf7ce00ca07a4d2bd9b5356fbcb83f3649b0fda07cfebad220c1066afba89e5a52abf4b", "0xb2dd1a2f986395bb4e3e960fbbe823dbb154f823284ebc9068502c19a7609790ec0073d08bfa63f71e30c7161b6ef966", "0x98e5236de4281245234f5d40a25b503505af140b503a035fc25a26159a9074ec81512b28f324c56ea2c9a5aa7ce90805", "0x89070847dc8bbf5bc4ed073aa2e2a1f699cf0c2ca226f185a0671cecc54e7d3e14cd475c7752314a7a8e7476829da4bc", "0xa9402dc9117fdb39c4734c0688254f23aed3dce94f5f53f5b7ef2b4bf1b71a67f85ab1a38ec224a59691f3bee050aeb3", "0x957288f9866a4bf56a4204218ccc583f717d7ce45c01ea27142a7e245ad04a07f289cc044f8cf1f21d35e67e39299e9c", "0xb2fb31ccb4e69113763d7247d0fc8edaae69b550c5c56aecacfd780c7217dc672f9fb7496edf4aba65dacf3361268e5b", "0xb44a4526b2f1d6eb2aa8dba23bfa385ff7634572ab2afddd0546c3beb630fbfe85a32f42dd287a7fec069041411537f7", "0x8db5a6660c3ac7fd7a093573940f068ee79a82bc17312af900b51c8c439336bc86ca646c6b7ab13aaaa008a24ca508ab", "0x8f9899a6d7e8eb4367beb5c060a1f8e94d8a21099033ae582118477265155ba9e72176a67f7f25d7bad75a152b56e21a", "0xa67de0e91ade8d69a0e00c9ff33ee2909b8a609357095fa12319e6158570c232e5b6f4647522efb7345ce0052aa9d489", "0x82eb2414898e9c3023d57907a2b17de8e7eea5269029d05a94bfd7bf5685ac4a799110fbb375eb5e0e2bd16acf6458ae", "0x94451fc7fea3c5a89ba701004a9693bab555cb622caf0896b678faba040409fdfd14a978979038b2a81e8f0abc4994d2", "0xac879a5bb433998e289809a4a966bd02b4bf6a9c1cc276454e39c886efcf4fc68baebed575826bde577ab5aa71d735a9", "0x880c0f8f49c875dfd62b4ddedde0f5c8b19f5687e693717f7e5c031bc580e58e13ab497d48b4874130a18743c59fdce3", "0xb582af8d8ff0bf76f0a3934775e0b54c0e8fed893245d7d89cae65b03c8125b7237edc29dc45b4fe1a3fe6db45d280ee", "0x89f337882ed3ae060aaee98efa20d79b6822bde9708c1c5fcee365d0ec9297f694cae37d38fd8e3d49717c1e86f078e7", "0x826d2c1faea54061848b484e288a5f4de0d221258178cf87f72e14baaa4acc21322f8c9eab5dde612ef497f2d2e1d60b", "0xa5333d4f227543e9cd741ccf3b81db79f2f03ca9e649e40d6a6e8ff9073e06da83683566d3b3c8d7b258c62970fb24d1", "0xa28f08c473db06aaf4c043a2fae82b3c8cfaa160bce793a4c208e4e168fb1c65115ff8139dea06453c5963d95e922b94", "0x8162546135cc5e124e9683bdfaa45833c18553ff06a0861c887dc84a5b12ae8cd4697f6794c7ef6230492c32faba7014", "0xb23f0d05b74c08d6a7df1760792be83a761b36e3f8ae360f3c363fb196e2a9dd2de2e492e49d36561366e14daa77155c", "0xb6f70d6c546722d3907c708d630dbe289771d2c8bf059c2e32b77f224696d750b4dda9b3a014debda38e7d02c9a77585", "0x83bf4c4a9f3ca022c631017e7a30ea205ba97f7f5927cba8fc8489a4646eac6712cb821c5668c9ffe94d69d524374a27", "0xb0371475425a8076d0dd5f733f55aabbe42d20a7c8ea7da352e736d4d35a327b2beb370dfcb05284e22cfd69c5f6c4cc", "0xa0031ba7522c79211416c2cca3aa5450f96f8fee711552a30889910970ba13608646538781a2c08b834b140aadd7166f", "0x99d273c80c7f2dc6045d4ed355d9fc6f74e93549d961f4a3b73cd38683f905934d359058cd1fc4da8083c7d75070487f", "0xb0e4b0efa3237793e9dcce86d75aafe9879c5fa23f0d628649aef2130454dcf72578f9bf227b9d2b9e05617468e82588", "0xa5ab076fa2e1c5c51f3ae101afdd596ad9d106bba7882b359c43d8548b64f528af19afa76cd6f40da1e6c5fca4def3fa", "0x8ce2299e570331d60f6a6eff1b271097cd5f1c0e1113fc69b89c6a0f685dabea3e5bc2ac6bd789aa492ab189f89be494", "0x91b829068874d911a310a5f9dee001021f97471307b5a3de9ec336870ec597413e1d92010ce320b619f38bed7c4f7910", "0xb14fe91f4b07bf33b046e9285b66cb07927f3a8da0af548ac2569b4c4fb1309d3ced76d733051a20814e90dd5b75ffd1", "0xabaab92ea6152d40f82940277c725aa768a631ee0b37f5961667f82fb990fc11e6d3a6a2752b0c6f94563ed9bb28265c", "0xb7fe28543eca2a716859a76ab9092f135337e28109544f6bd2727728d0a7650428af5713171ea60bfc273d1c821d992c", "0x8a4917b2ab749fc7343fc64bdf51b6c0698ff15d740cc7baf248c030475c097097d5a473bcc00d8c25817563fe0447b4", "0xaa96156d1379553256350a0a3250166add75948fb9cde62aa555a0a9dc0a9cb7f2f7b8428aff66097bf6bfedaf14bbe2", "0xae4ffeb9bdc76830d3eca2b705f30c1bdede6412fa064260a21562c8850c7fb611ec62bc68479fe48f692833e6f66d8d", "0xb96543caaba9d051600a14997765d49e4ab10b07c7a92cccf0c90b309e6da334fdd6d18c96806cbb67a7801024fbd3c7", "0x97b2b9ad76f19f500fcc94ca8e434176249f542ac66e5881a3dccd07354bdab6a2157018b19f8459437a68d8b86ba8e0", "0xa8d206f6c5a14c80005849474fde44b1e7bcf0b2d52068f5f97504c3c035b09e65e56d1cf4b5322791ae2c2fdbd61859", "0x936bad397ad577a70cf99bf9056584a61bd7f02d2d5a6cf219c05d770ae30a5cd902ba38366ce636067fc1dd10108d31", "0xa77e30195ee402b84f3882e2286bf5380c0ed374a112dbd11e16cef6b6b61ab209d4635e6f35cdaaa72c1a1981d5dabe", "0xa46ba4d3947188590a43c180757886a453a0503f79cc435322d92490446f37419c7b999fdf868a023601078070e03346", "0x80d8d4c5542f223d48240b445d4d8cf6a75d120b060bc08c45e99a13028b809d910b534d2ac47fb7068930c54efd8da9", "0x803be9c68c91b42b68e1f55e58917a477a9a6265e679ca44ee30d3eb92453f8c89c64eafc04c970d6831edd33d066902", "0xb14b2b3d0dfe2bb57cee4cd72765b60ac33c1056580950be005790176543826c1d4fbd737f6cfeada6c735543244ab57", "0xa9e480188bba1b8fb7105ff12215706665fd35bf1117bacfb6ab6985f4dbc181229873b82e5e18323c2b8f5de03258e0", "0xa66a0f0779436a9a3999996d1e6d3000f22c2cac8e0b29cddef9636393c7f1457fb188a293b6c875b05d68d138a7cc4a", "0x848397366300ab40c52d0dbbdafbafef6cd3dadf1503bb14b430f52bb9724188928ac26f6292a2412bc7d7aa620763c8", "0x95466cc1a78c9f33a9aaa3829a4c8a690af074916b56f43ae46a67a12bb537a5ac6dbe61590344a25b44e8512355a4a7", "0x8b5f7a959f818e3baf0887f140f4575cac093d0aece27e23b823cf421f34d6e4ff4bb8384426e33e8ec7b5eed51f6b5c", "0x8d5e1368ec7e3c65640d216bcc5d076f3d9845924c734a34f3558ac0f16e40597c1a775a25bf38b187213fbdba17c93b", "0xb4647c1b823516880f60d20c5cc38c7f80b363c19d191e8992226799718ee26b522a12ecb66556ed3d483aa4824f3326", "0xac3abaea9cd283eb347efda4ed9086ea3acf495043e08d0d19945876329e8675224b685612a6badf8fd72fb6274902b1", "0x8eae1ce292d317aaa71bcf6e77e654914edd5090e2e1ebab78b18bb41b9b1bc2e697439f54a44c0c8aa0d436ebe6e1a9", "0x94dc7d1aec2c28eb43d93b111fa59aaa0d77d5a09501220bd411768c3e52208806abf973c6a452fd8292ff6490e0c9e2", "0x8fd8967f8e506fef27d17b435d6b86b232ec71c1036351f12e6fb8a2e12daf01d0ee04451fb944d0f1bf7fd20e714d02", "0x824e6865be55d43032f0fec65b3480ea89b0a2bf860872237a19a54bc186a85d2f8f9989cc837fbb325b7c72d9babe2c", "0x8bd361f5adb27fd6f4e3f5de866e2befda6a8454efeb704aacc606f528c03f0faae888f60310e49440496abd84083ce2", "0xb098a3c49f2aaa28b6b3e85bc40ce6a9cdd02134ee522ae73771e667ad7629c8d82c393fba9f27f5416986af4c261438", "0xb385f5ca285ff2cfe64dcaa32dcde869c28996ed091542600a0b46f65f3f5a38428cca46029ede72b6cf43e12279e3d3", "0x8196b03d011e5be5288196ef7d47137d6f9237a635ab913acdf9c595fa521d9e2df722090ec7eb0203544ee88178fc5f", "0x8ed1270211ef928db18e502271b7edf24d0bbd11d97f2786aee772d70c2029e28095cf8f650b0328cc8a4c38d045316d", "0xa52ab60e28d69b333d597a445884d44fd2a7e1923dd60f763951e1e45f83e27a4dac745f3b9eff75977b3280e132c15d", "0x91e9fe78cdac578f4a4687f71b800b35da54b824b1886dafec073a3c977ce7a25038a2f3a5b1e35c2c8c9d1a7312417c", "0xa42832173f9d9491c7bd93b21497fbfa4121687cd4d2ab572e80753d7edcbb42cfa49f460026fbde52f420786751a138", "0x97b947126d84dcc70c97be3c04b3de3f239b1c4914342fa643b1a4bb8c4fe45c0fcb585700d13a7ed50784790c54bef9", "0x860e407d353eac070e2418ef6cb80b96fc5f6661d6333e634f6f306779651588037be4c2419562c89c61f9aa2c4947f5", "0xb2c9d93c3ba4e511b0560b55d3501bf28a510745fd666b3cb532db051e6a8617841ea2f071dda6c9f15619c7bfd2737f", "0x8596f4d239aeeac78311207904d1bd863ef68e769629cc379db60e019aaf05a9d5cd31dc8e630b31e106a3a93e47cbc5", "0x8b26e14e2e136b65c5e9e5c2022cee8c255834ea427552f780a6ca130a6446102f2a6f334c3f9a0308c53df09e3dba7e", "0xb54724354eb515a3c8bed0d0677ff1db94ac0a07043459b4358cb90e3e1aa38ac23f2caa3072cf9647275d7cd61d0e80", "0xb7ce9fe0e515e7a6b2d7ddcb92bc0196416ff04199326aea57996eef8c5b1548bd8569012210da317f7c0074691d01b7", "0xa1a13549c82c877253ddefa36a29ea6a23695ee401fdd48e65f6f61e5ebd956d5e0edeff99484e9075cb35071fec41e2", "0x838ba0c1e5bd1a6da05611ff1822b8622457ebd019cb065ece36a2d176bd2d889511328120b8a357e44569e7f640c1e6", "0xb916eccff2a95519400bbf76b5f576cbe53cf200410370a19d77734dc04c05b585cfe382e8864e67142d548cd3c4c2f4", "0xa610447cb7ca6eea53a6ff1f5fe562377dcb7f4aaa7300f755a4f5e8eba61e863c51dc2aa9a29b35525b550fbc32a0fe", "0x9620e8f0f0ee9a4719aa9685eeb1049c5c77659ba6149ec4c158f999cfd09514794b23388879931fe26fea03fa471fd3", "0xa9dcf8b679e276583cf5b9360702a185470d09aea463dc474ee9c8aee91ef089dacb073e334e47fbc78ec5417c90465c", "0x8c9adee8410bdd99e5b285744cee61e2593b6300ff31a8a83b0ec28da59475a5c6fb9346fe43aadea2e6c3dad2a8e30a", "0x97d5afe9b3897d7b8bb628b7220cf02d8ee4e9d0b78f5000d500aaf4c1df9251aaaabfd1601626519f9d66f00a821d4e", "0x8a382418157b601ce4c3501d3b8409ca98136a4ef6abcbf62885e16e215b76b035c94d149cc41ff92e42ccd7c43b9b3d", "0xb64b8d11fb3b01abb2646ac99fdb9c02b804ce15d98f9fe0fbf1c9df8440c71417487feb6cdf51e3e81d37104b19e012", "0x849d7d044f9d8f0aab346a9374f0b3a5d14a9d1faa83dbacccbdc629ad1ef903a990940255564770537f8567521d17f0", "0x829dbb0c76b996c2a91b4cbbe93ba455ca0d5729755e5f0c92aaee37dff7f36fcdc06f33aca41f1b609c784127b67d88", "0x85a7c0069047b978422d264d831ab816435f63938015d2e977222b6b5746066c0071b7f89267027f8a975206ed25c1b0", "0x84b9fbc1cfb302df1acdcf3dc5d66fd1edfe7839f7a3b2fb3a0d5548656249dd556104d7c32b73967bccf0f5bdcf9e3b", "0x972220ac5b807f53eac37dccfc2ad355d8b21ea6a9c9b011c09fe440ddcdf7513e0b43d7692c09ded80d7040e26aa28f", "0x855885ed0b21350baeca890811f344c553cf9c21024649c722453138ba29193c6b02c4b4994cd414035486f923472e28", "0x841874783ae6d9d0e59daea03e96a01cbbe4ecaced91ae4f2c8386e0d87b3128e6d893c98d17c59e4de1098e1ad519dd", "0x827e50fc9ce56f97a4c3f2f4cbaf0b22f1c3ce6f844ff0ef93a9c57a09b8bf91ebfbd2ba9c7f83c442920bffdaf288cc", "0xa441f9136c7aa4c08d5b3534921b730e41ee91ab506313e1ba5f7c6f19fd2d2e1594e88c219834e92e6fb95356385aa7", "0x97d75b144471bf580099dd6842b823ec0e6c1fb86dd0da0db195e65524129ea8b6fd4a7a9bbf37146269e938a6956596", "0xa4b6fa87f09d5a29252efb2b3aaab6b3b6ea9fab343132a651630206254a25378e3e9d6c96c3d14c150d01817d375a8e", "0xa31a671876d5d1e95fe2b8858dc69967231190880529d57d3cab7f9f4a2b9b458ac9ee5bdaa3289158141bf18f559efb", "0x90bee6fff4338ba825974021b3b2a84e36d617e53857321f13d2b3d4a28954e6de3b3c0e629d61823d18a9763313b3bf", "0x96b622a63153f393bb419bfcf88272ea8b3560dbd46b0aa07ada3a6223990d0abdd6c2adb356ef4be5641688c8d83941", "0x84c202adeaff9293698022bc0381adba2cd959f9a35a4e8472288fd68f96f6de8be9da314c526d88e291c96b1f3d6db9", "0x8ca01a143b8d13809e5a8024d03e6bc9492e22226073ef6e327edf1328ef4aff82d0bcccee92cb8e212831fa35fe1204", "0xb2f970dbad15bfbefb38903c9bcc043d1367055c55dc1100a850f5eb816a4252c8c194b3132c929105511e14ea10a67d", "0xa5e36556472a95ad57eb90c3b6623671b03eafd842238f01a081997ffc6e2401f76e781d049bb4aa94d899313577a9cf", "0x8d1057071051772f7c8bedce53a862af6fd530dd56ae6321eaf2b9fc6a68beff5ed745e1c429ad09d5a118650bfd420a", "0x8aadc4f70ace4fcb8d93a78610779748dcffc36182d45b932c226dc90e48238ea5daa91f137c65ed532352c4c4d57416", "0xa2ea05ae37e673b4343232ae685ee14e6b88b867aef6dfac35db3589cbcd76f99540fed5c2641d5bb5a4a9f808e9bf0d", "0x947f1abad982d65648ae4978e094332b4ecb90f482c9be5741d5d1cf5a28acf4680f1977bf6e49dd2174c37f11e01296", "0xa27b144f1565e4047ba0e3f4840ef19b5095d1e281eaa463c5358f932114cbd018aa6dcf97546465cf2946d014d8e6d6", "0x8574e1fc3acade47cd4539df578ce9205e745e161b91e59e4d088711a7ab5aa3b410d517d7304b92109924d9e2af8895", "0xa48ee6b86b88015d6f0d282c1ae01d2a5b9e8c7aa3d0c18b35943dceb1af580d08a65f54dc6903cde82fd0d73ce94722", "0x8875650cec543a7bf02ea4f2848a61d167a66c91ffaefe31a9e38dc8511c6a25bde431007eefe27a62af3655aca208dc", "0x999b0a6e040372e61937bf0d68374e230346b654b5a0f591a59d33a4f95bdb2f3581db7c7ccb420cd7699ed709c50713", "0x878c9e56c7100c5e47bbe77dc8da5c5fe706cec94d37fa729633bca63cace7c40102eee780fcdabb655f5fa47a99600e", "0x865006fb5b475ada5e935f27b96f9425fc2d5449a3c106aa366e55ebed3b4ee42adc3c3f0ac19fd129b40bc7d6bc4f63", "0xb7a7da847f1202e7bc1672553e68904715e84fd897d529243e3ecda59faa4e17ba99c649a802d53f6b8dfdd51f01fb74", "0x8b2fb4432c05653303d8c8436473682933a5cb604da10c118ecfcd2c8a0e3132e125afef562bdbcc3df936164e5ce4f2", "0x808d95762d33ddfa5d0ee3d7d9f327de21a994d681a5f372e2e3632963ea974da7f1f9e5bac8ccce24293509d1f54d27", "0x932946532e3c397990a1df0e94c90e1e45133e347a39b6714c695be21aeb2d309504cb6b1dde7228ff6f6353f73e1ca2", "0x9705e7c93f0cdfaa3fa96821f830fe53402ad0806036cd1b48adc2f022d8e781c1fbdab60215ce85c653203d98426da3", "0xaa180819531c3ec1feb829d789cb2092964c069974ae4faad60e04a6afcce5c3a59aec9f11291e6d110a788d22532bc6", "0x88f755097f7e25cb7dd3c449520c89b83ae9e119778efabb54fbd5c5714b6f37c5f9e0346c58c6ab09c1aef2483f895d", "0x99fc03ab7810e94104c494f7e40b900f475fde65bdec853e60807ffd3f531d74de43335c3b2646b5b8c26804a7448898", "0xaf2dea9683086bed1a179110efb227c9c00e76cd00a2015b089ccbcee46d1134aa18bda5d6cab6f82ae4c5cd2461ac21", "0xa500f87ba9744787fdbb8e750702a3fd229de6b8817594348dec9a723b3c4240ddfa066262d002844b9e38240ce55658", "0x924d0e45c780f5bc1c1f35d15dfc3da28036bdb59e4c5440606750ecc991b85be18bc9a240b6c983bc5430baa4c68287", "0x865b11e0157b8bf4c5f336024b016a0162fc093069d44ac494723f56648bc4ded13dfb3896e924959ea11c96321afefc", "0x93672d8607d4143a8f7894f1dcca83fb84906dc8d6dd7dd063bb0049cfc20c1efd933e06ca7bd03ea4cb5a5037990bfe", "0x826891efbdff0360446825a61cd1fa04326dd90dae8c33dfb1ed97b045e165766dd070bd7105560994d0b2044bdea418", "0x93c4a4a8bcbc8b190485cc3bc04175b7c0ed002c28c98a540919effd6ed908e540e6594f6db95cd65823017258fb3b1c", "0xaeb2a0af2d2239fda9aa6b8234b019708e8f792834ff0dd9c487fa09d29800ddceddd6d7929faa9a3edcb9e1b3aa0d6b", "0x87f11de7236d387863ec660d2b04db9ac08143a9a2c4dfff87727c95b4b1477e3bc473a91e5797313c58754905079643", "0x80dc1db20067a844fe8baceca77f80db171a5ca967acb24e2d480eae9ceb91a3343c31ad1c95b721f390829084f0eae6", "0x9825c31f1c18da0de3fa84399c8b40f8002c3cae211fb6a0623c76b097b4d39f5c50058f57a16362f7a575909d0a44a2", "0xa99fc8de0c38dbf7b9e946de83943a6b46a762167bafe2a603fb9b86f094da30d6de7ed55d639aafc91936923ee414b3", "0xad594678b407db5d6ea2e90528121f84f2b96a4113a252a30d359a721429857c204c1c1c4ff71d8bb5768c833f82e80e", "0xb33d985e847b54510b9b007e31053732c8a495e43be158bd2ffcea25c6765bcbc7ca815f7c60b36ad088b955dd6e9350", "0x815f8dfc6f90b3342ca3fbd968c67f324dae8f74245cbf8bc3bef10e9440c65d3a2151f951e8d18959ba01c1b50b0ec1", "0x94c608a362dd732a1abc56e338637c900d59013db8668e49398b3c7a0cae3f7e2f1d1bf94c0299eeafe6af7f76c88618", "0x8ebd8446b23e5adfcc393adc5c52fe172f030a73e63cd2d515245ca0dd02782ceed5bcdd9ccd9c1b4c5953dfac9c340c", "0x820437f3f6f9ad0f5d7502815b221b83755eb8dc56cd92c29e9535eb0b48fb8d08c9e4fcc26945f9c8cca60d89c44710", "0x8910e4e8a56bf4be9cc3bbf0bf6b1182a2f48837a2ed3c2aaec7099bfd7f0c83e14e608876b17893a98021ff4ab2f20d", "0x9633918fde348573eec15ce0ad53ac7e1823aac86429710a376ad661002ae6d049ded879383faaa139435122f64047c6", "0xa1f5e3fa558a9e89318ca87978492f0fb4f6e54a9735c1b8d2ecfb1d1c57194ded6e0dd82d077b2d54251f3bee1279e1", "0xb208e22d04896abfd515a95c429ff318e87ff81a5d534c8ac2c33c052d6ffb73ef1dccd39c0bbe0734b596c384014766", "0x986d5d7d2b5bde6d16336f378bd13d0e671ad23a8ec8a10b3fc09036faeeb069f60662138d7a6df3dfb8e0d36180f770", "0xa2d4e6c5f5569e9cef1cddb569515d4b6ace38c8aed594f06da7434ba6b24477392cc67ba867c2b079545ca0c625c457", "0xb5ac32b1d231957d91c8b7fc43115ce3c5c0d8c13ca633374402fa8000b6d9fb19499f9181844f0c10b47357f3f757ce", "0x96b8bf2504b4d28fa34a4ec378e0e0b684890c5f44b7a6bb6e19d7b3db2ab27b1e2686389d1de9fbd981962833a313ea", "0x953bfd7f6c3a0469ad432072b9679a25486f5f4828092401eff494cfb46656c958641a4e6d0d97d400bc59d92dba0030", "0x876ab3cea7484bbfd0db621ec085b9ac885d94ab55c4bb671168d82b92e609754b86aaf472c55df3d81421d768fd108a", "0x885ff4e67d9ece646d02dd425aa5a087e485c3f280c3471b77532b0db6145b69b0fbefb18aa2e3fa5b64928b43a94e57", "0xb91931d93f806d0b0e6cc62a53c718c099526140f50f45d94b8bbb57d71e78647e06ee7b42aa5714aed9a5c05ac8533f", "0xa0313eeadd39c720c9c27b3d671215331ab8d0a794e71e7e690f06bcd87722b531d6525060c358f35f5705dbb7109ccb", "0x874c0944b7fedc6701e53344100612ddcb495351e29305c00ec40a7276ea5455465ffb7bded898886c1853139dfb1fc7", "0x8dc31701a01ee8137059ca1874a015130d3024823c0576aa9243e6942ec99d377e7715ed1444cd9b750a64b85dcaa3e5", "0x836d2a757405e922ec9a2dfdcf489a58bd48b5f9683dd46bf6047688f778c8dee9bc456de806f70464df0b25f3f3d238", "0xb30b0a1e454a503ea3e2efdec7483eaf20b0a5c3cefc42069e891952b35d4b2c955cf615f3066285ed8fafd9fcfbb8f6", "0x8e6d4044b55ab747e83ec8762ea86845f1785cc7be0279c075dadf08aca3ccc5a096c015bb3c3f738f647a4eadea3ba5", "0xad7735d16ab03cbe09c029610aa625133a6daecfc990b297205b6da98eda8c136a7c50db90f426d35069708510d5ae9c", "0x8d62d858bbb59ec3c8cc9acda002e08addab4d3ad143b3812098f3d9087a1b4a1bb255dcb1635da2402487d8d0249161", "0x805beec33238b832e8530645a3254aeef957e8f7ea24bcfc1054f8b9c69421145ebb8f9d893237e8a001c857fedfc77e", "0xb1005644be4b085e3f5775aa9bd3e09a283e87ddada3082c04e7a62d303dcef3b8cf8f92944c200c7ae6bb6bdf63f832", "0xb4ba0e0790dc29063e577474ffe3b61f5ea2508169f5adc1e394934ebb473e356239413a17962bc3e5d3762d72cce8c2", "0xa157ba9169c9e3e6748d9f1dd67fbe08b9114ade4c5d8fc475f87a764fb7e6f1d21f66d7905cd730f28a1c2d8378682a", "0x913e52b5c93989b5d15e0d91aa0f19f78d592bc28bcfdfddc885a9980c732b1f4debb8166a7c4083c42aeda93a702898", "0x90fbfc1567e7cd4e096a38433704d3f96a2de2f6ed3371515ccc30bc4dd0721a704487d25a97f3c3d7e4344472702d8d", "0x89646043028ffee4b69d346907586fd12c2c0730f024acb1481abea478e61031966e72072ff1d5e65cb8c64a69ad4eb1", "0xb125a45e86117ee11d2fb42f680ab4a7894edd67ff927ae2c808920c66c3e55f6a9d4588eee906f33a05d592e5ec3c04", "0xaad47f5b41eae9be55fb4f67674ff1e4ae2482897676f964a4d2dcb6982252ee4ff56aac49578b23f72d1fced707525e", "0xb9ddff8986145e33851b4de54d3e81faa3352e8385895f357734085a1616ef61c692d925fe62a5ed3be8ca49f5d66306", "0xb3cb0963387ed28c0c0adf7fe645f02606e6e1780a24d6cecef5b7c642499109974c81a7c2a198b19862eedcea2c2d8c", "0xac9c53c885457aaf5cb36c717a6f4077af701e0098eebd7aa600f5e4b14e6c1067255b3a0bc40e4a552025231be7de60", "0x8e1a8d823c4603f6648ec21d064101094f2a762a4ed37dd2f0a2d9aa97b2d850ce1e76f4a4b8cae58819b058180f7031", "0xb268b73bf7a179b6d22bd37e5e8cb514e9f5f8968c78e14e4f6d5700ca0d0ca5081d0344bb73b028970eebde3cb4124e", "0xa7f57d71940f0edbd29ed8473d0149cae71d921dd15d1ff589774003e816b54b24de2620871108cec1ab9fa956ad6ce6", "0x8053e6416c8b120e2b999cc2fc420a6a55094c61ac7f2a6c6f0a2c108a320890e389af96cbe378936132363c0d551277", "0xb3823f4511125e5aa0f4269e991b435a0d6ceb523ebd91c04d7add5534e3df5fc951c504b4fd412a309fd3726b7f940b", "0xae6eb04674d04e982ca9a6add30370ab90e303c71486f43ed3efbe431af1b0e43e9d06c11c3412651f304c473e7dbf39", "0x96ab55e641ed2e677591f7379a3cd126449614181fce403e93e89b1645d82c4af524381ff986cae7f9cebe676878646d", "0xb52423b4a8c37d3c3e2eca8f0ddbf7abe0938855f33a0af50f117fab26415fb0a3da5405908ec5fdc22a2c1f2ca64892", "0x82a69ce1ee92a09cc709d0e3cd22116c9f69d28ea507fe5901f5676000b5179b9abe4c1875d052b0dd42d39925e186bb", "0xa84c8cb84b9d5cfb69a5414f0a5283a5f2e90739e9362a1e8c784b96381b59ac6c18723a4aa45988ee8ef5c1f45cc97d", "0xafd7efce6b36813082eb98257aae22a4c1ae97d51cac7ea9c852d4a66d05ef2732116137d8432e3f117119725a817d24", "0xa0f5fe25af3ce021b706fcff05f3d825384a272284d04735574ce5fb256bf27100fad0b1f1ba0e54ae9dcbb9570ecad3", "0x8751786cb80e2e1ff819fc7fa31c2833d25086534eb12b373d31f826382430acfd87023d2a688c65b5e983927e146336", "0x8cf5c4b17fa4f3d35c78ce41e1dc86988fd1135cd5e6b2bb0c108ee13538d0d09ae7102609c6070f39f937b439b31e33", "0xa9108967a2fedd7c322711eca8159c533dd561bedcb181b646de98bf5c3079449478eab579731bee8d215ae8852c7e21", "0xb54c5171704f42a6f0f4e70767cdb3d96ffc4888c842eece343a01557da405961d53ffdc34d2f902ea25d3e1ed867cad", "0xae8d4b764a7a25330ba205bf77e9f46182cd60f94a336bbd96773cf8064e3d39caf04c310680943dc89ed1fbad2c6e0d", "0xaa5150e911a8e1346868e1b71c5a01e2a4bb8632c195861fb6c3038a0e9b85f0e09b3822e9283654a4d7bb17db2fc5f4", "0x9685d3756ce9069bf8bb716cf7d5063ebfafe37e15b137fc8c3159633c4e006ff4887ddd0ae90360767a25c3f90cba7f", "0x82155fd70f107ab3c8e414eadf226c797e07b65911508c76c554445422325e71af8c9a8e77fd52d94412a6fc29417cd3", "0xabfae52f53a4b6e00760468d973a267f29321997c3dbb5aee36dc1f20619551229c0c45b9d9749f410e7f531b73378e8", "0x81a76d921f8ef88e774fd985e786a4a330d779b93fad7def718c014685ca0247379e2e2a007ad63ee7f729cd9ed6ce1b", "0x81947c84bc5e28e26e2e533af5ae8fe10407a7b77436dbf8f1d5b0bbe86fc659eae10f974659dc7c826c6dabd03e3a4b", "0x92b8c07050d635b8dd4fd09df9054efe4edae6b86a63c292e73cc819a12a21dd7d104ce51fa56af6539dedf6dbe6f7b6", "0xb44c579e3881f32b32d20c82c207307eca08e44995dd2aac3b2692d2c8eb2a325626c80ac81c26eeb38c4137ff95add5", "0x97efab8941c90c30860926dea69a841f2dcd02980bf5413b9fd78d85904588bf0c1021798dbc16c8bbb32cce66c82621", "0x913363012528b50698e904de0588bf55c8ec5cf6f0367cfd42095c4468fcc64954fbf784508073e542fee242d0743867", "0x8ed203cf215148296454012bd10fddaf119203db1919a7b3d2cdc9f80e66729464fdfae42f1f2fc5af1ed53a42b40024", "0xab84312db7b87d711e9a60824f4fe50e7a6190bf92e1628688dfcb38930fe87b2d53f9e14dd4de509b2216856d8d9188", "0x880726def069c160278b12d2258eac8fa63f729cd351a710d28b7e601c6712903c3ac1e7bbd0d21e4a15f13ca49db5aa", "0x980699cd51bac6283959765f5174e543ed1e5f5584b5127980cbc2ef18d984ecabba45042c6773b447b8e694db066028", "0xaeb019cb80dc4cb4207430d0f2cd24c9888998b6f21d9bf286cc638449668d2eec0018a4cf3fe6448673cd6729335e2b", "0xb29852f6aa6c60effdffe96ae88590c88abae732561d35cc19e82d3a51e26cb35ea00986193e07f90060756240f5346e", "0xa0fa855adc5ba469f35800c48414b8921455950a5c0a49945d1ef6e8f2a1881f2e2dfae47de6417270a6bf49deeb091d", "0xb6c7332e3b14813641e7272d4f69ecc7e09081df0037d6dab97ce13a9e58510f5c930d300633f208181d9205c5534001", "0x85a6c050f42fce560b5a8d54a11c3bbb8407abbadd859647a7b0c21c4b579ec65671098b74f10a16245dc779dff7838e", "0x8f3eb34bb68759d53c6677de4de78a6c24dd32c8962a7fb355ed362572ef8253733e6b52bc21c9f92ecd875020a9b8de", "0xa17dd44181e5dab4dbc128e1af93ec22624b57a448ca65d2d9e246797e4af7d079e09c6e0dfb62db3a9957ce92f098d5", "0xa56a1b854c3183082543a8685bb34cae1289f86cfa8123a579049dbd059e77982886bfeb61bf6e05b4b1fe4e620932e7", "0xaedae3033cb2fb7628cb4803435bdd7757370a86f808ae4cecb9a268ad0e875f308c048c80cbcac523de16b609683887", "0x9344905376aa3982b1179497fac5a1d74b14b7038fd15e3b002db4c11c8bfc7c39430db492cdaf58b9c47996c9901f28", "0xa3bfafdae011a19f030c749c3b071f83580dee97dd6f949e790366f95618ca9f828f1daaeabad6dcd664fcef81b6556d", "0x81c03d8429129e7e04434dee2c529194ddb01b414feda3adee2271eb680f6c85ec872a55c9fa9d2096f517e13ed5abcc", "0x98205ef3a72dff54c5a9c82d293c3e45d908946fa74bb749c3aabe1ab994ea93c269bcce1a266d2fe67a8f02133c5985", "0x85a70aeed09fda24412fadbafbbbf5ba1e00ac92885df329e147bfafa97b57629a3582115b780d8549d07d19b7867715", "0xb0fbe81c719f89a57d9ea3397705f898175808c5f75f8eb81c2193a0b555869ba7bd2e6bc54ee8a60cea11735e21c68c", "0xb03a0bd160495ee626ff3a5c7d95bc79d7da7e5a96f6d10116600c8fa20bedd1132f5170f25a22371a34a2d763f2d6d0", "0xa90ab04091fbca9f433b885e6c1d60ab45f6f1daf4b35ec22b09909d493a6aab65ce41a6f30c98239cbca27022f61a8b", "0xb66f92aa3bf2549f9b60b86f99a0bd19cbdd97036d4ae71ca4b83d669607f275260a497208f6476cde1931d9712c2402", "0xb08e1fdf20e6a9b0b4942f14fa339551c3175c1ffc5d0ab5b226b6e6a322e9eb0ba96adc5c8d59ca4259e2bdd04a7eb0", "0xa2812231e92c1ce74d4f5ac3ab6698520288db6a38398bb38a914ac9326519580af17ae3e27cde26607e698294022c81", "0xabfcbbcf1d3b9e84c02499003e490a1d5d9a2841a9e50c7babbef0b2dd20d7483371d4dc629ba07faf46db659459d296", "0xb0fe9f98c3da70927c23f2975a9dc4789194d81932d2ad0f3b00843dd9cbd7fb60747a1da8fe5a79f136a601becf279d", "0xb130a6dba7645165348cb90f023713bed0eefbd90a976b313521c60a36d34f02032e69a2bdcf5361e343ed46911297ec", "0x862f0cffe3020cea7a5fd4703353aa1eb1be335e3b712b29d079ff9f7090d1d8b12013011e1bdcbaa80c44641fd37c9f", "0x8c6f11123b26633e1abb9ed857e0bce845b2b3df91cc7b013b2fc77b477eee445da0285fc6fc793e29d5912977f40916", "0x91381846126ea819d40f84d3005e9fb233dc80071d1f9bb07f102bf015f813f61e5884ffffb4f5cd333c1b1e38a05a58", "0x8add7d908de6e1775adbd39c29a391f06692b936518db1f8fde74eb4f533fc510673a59afb86e3a9b52ade96e3004c57", "0x8780e086a244a092206edcde625cafb87c9ab1f89cc3e0d378bc9ee776313836160960a82ec397bc3800c0a0ec3da283", "0xa6cb4cd9481e22870fdd757fae0785edf4635e7aacb18072fe8dc5876d0bab53fb99ce40964a7d3e8bcfff6f0ab1332f", "0xaf30ff47ecc5b543efba1ba4706921066ca8bb625f40e530fb668aea0551c7647a9d126e8aba282fbcce168c3e7e0130", "0x91b0bcf408ce3c11555dcb80c4410b5bc2386d3c05caec0b653352377efdcb6bab4827f2018671fc8e4a0e90d772acc1", "0xa9430b975ef138b6b2944c7baded8fe102d31da4cfe3bd3d8778bda79189c99d38176a19c848a19e2d1ee0bddd9a13c1", "0xaa5a4eef849d7c9d2f4b018bd01271c1dd83f771de860c4261f385d3bdcc130218495860a1de298f14b703ec32fa235f", "0xb0ce79e7f9ae57abe4ff366146c3b9bfb38b0dee09c28c28f5981a5d234c6810ad4d582751948affb480d6ae1c8c31c4", "0xb75122748560f73d15c01a8907d36d06dc068e82ce22b84b322ac1f727034493572f7907dec34ebc3ddcc976f2f89ed7", "0xb0fc7836369a3e4411d34792d6bd5617c14f61d9bba023dda64e89dc5fb0f423244e9b48ee64869258931daa9753a56f", "0x8956d7455ae9009d70c6e4a0bcd7610e55f37494cf9897a8f9e1b904cc8febc3fd2d642ebd09025cfff4609ad7e3bc52", "0xad741efe9e472026aa49ae3d9914cb9c1a6f37a54f1a6fe6419bebd8c7d68dca105a751c7859f4389505ede40a0de786", "0xb52f418797d719f0d0d0ffb0846788b5cba5d0454a69a2925de4b0b80fa4dd7e8c445e5eac40afd92897ed28ca650566", "0xa0ab65fb9d42dd966cd93b1de01d7c822694669dd2b7a0c04d99cd0f3c3de795f387b9c92da11353412f33af5c950e9a", "0xa0052f44a31e5741a331f7cac515a08b3325666d388880162d9a7b97598fde8b61f9ff35ff220df224eb5c4e40ef0567", "0xa0101cfdc94e42b2b976c0d89612a720e55d145a5ef6ef6f1f78cf6de084a49973d9b5d45915349c34ce712512191e3c", "0xa0dd99fcf3f5cead5aaf08e82212df3a8bb543c407a4d6fab88dc5130c1769df3f147e934a46f291d6c1a55d92b86917", "0xa5939153f0d1931bbda5cf6bdf20562519ea55fbfa978d6dbc6828d298260c0da7a50c37c34f386e59431301a96c2232", "0x9568269f3f5257200f9ca44afe1174a5d3cf92950a7f553e50e279c239e156a9faaa2a67f288e3d5100b4142efe64856", "0xb746b0832866c23288e07f24991bbf687cad794e7b794d3d3b79367566ca617d38af586cdc8d6f4a85a34835be41d54f", "0xa871ce28e39ab467706e32fec1669fda5a4abba2f8c209c6745df9f7a0fa36bbf1919cf14cb89ea26fa214c4c907ae03", "0xa08dacdd758e523cb8484f6bd070642c0c20e184abdf8e2a601f61507e93952d5b8b0c723c34fcbdd70a8485eec29db2", "0x85bdb78d501382bb95f1166b8d032941005661aefd17a5ac32df9a3a18e9df2fc5dc2c1f07075f9641af10353cecc0c9", "0x98d730c28f6fa692a389e97e368b58f4d95382fad8f0baa58e71a3d7baaea1988ead47b13742ce587456f083636fa98e", "0xa557198c6f3d5382be9fb363feb02e2e243b0c3c61337b3f1801c4a0943f18e38ce1a1c36b5c289c8fa2aa9d58742bab", "0x89174f79201742220ac689c403fc7b243eed4f8e3f2f8aba0bf183e6f5d4907cb55ade3e238e3623d9885f03155c4d2b", "0xb891d600132a86709e06f3381158db300975f73ea4c1f7c100358e14e98c5fbe792a9af666b85c4e402707c3f2db321e", "0xb9e5b2529ef1043278c939373fc0dbafe446def52ddd0a8edecd3e4b736de87e63e187df853c54c28d865de18a358bb6", "0x8589b2e9770340c64679062c5badb7bbef68f55476289b19511a158a9a721f197da03ece3309e059fc4468b15ac33aa3", "0xaad8c6cd01d785a881b446f06f1e9cd71bca74ba98674c2dcddc8af01c40aa7a6d469037498b5602e76e9c91a58d3dbd", "0xabaccb1bd918a8465f1bf8dbe2c9ad4775c620b055550b949a399f30cf0d9eb909f3851f5b55e38f9e461e762f88f499", "0xae62339d26db46e85f157c0151bd29916d5cc619bd4b832814b3fd2f00af8f38e7f0f09932ffe5bba692005dab2d9a74", "0x93a6ff30a5c0edf8058c89aba8c3259e0f1b1be1b80e67682de651e5346f7e1b4b4ac3d87cbaebf198cf779524aff6bf", "0x8980a2b1d8f574af45b459193c952400b10a86122b71fca2acb75ee0dbd492e7e1ef5b959baf609a5172115e371f3177", "0x8c2f49f3666faee6940c75e8c7f6f8edc3f704cca7a858bbb7ee5e96bba3b0cf0993996f781ba6be3b0821ef4cb75039", "0xb14b9e348215b278696018330f63c38db100b0542cfc5be11dc33046e3bca6a13034c4ae40d9cef9ea8b34fef0910c4e", "0xb59bc3d0a30d66c16e6a411cb641f348cb1135186d5f69fda8b0a0934a5a2e7f6199095ba319ec87d3fe8f1ec4a06368", "0x8874aca2a3767aa198e4c3fec2d9c62d496bc41ff71ce242e9e082b7f38cdf356089295f80a301a3cf1182bde5308c97", "0xb1820ebd61376d91232423fc20bf008b2ba37e761199f4ef0648ea2bd70282766799b4de814846d2f4d516d525c8daa7", "0xa6b202e5dedc16a4073e04a11af3a8509b23dfe5a1952f899adeb240e75c3f5bde0c424f811a81ea48d343591faffe46", "0xa69becee9c93734805523b92150a59a62eed4934f66056b645728740d42223f2925a1ad38359ba644da24d9414f4cdda", "0xad72f0f1305e37c7e6b48c272323ee883320994cb2e0d850905d6655fafc9f361389bcb9c66b3ff8d2051dbb58c8aa96", "0xb563600bd56fad7c8853af21c6a02a16ed9d8a8bbeea2c31731d63b976d83cb05b9779372d898233e8fd597a75424797", "0xb0abb78ce465bf7051f563c62e8be9c57a2cc997f47c82819300f36e301fefd908894bb2053a9d27ce2d0f8c46d88b5b", "0xa071a85fb8274bac2202e0cb8e0e2028a5e138a82d6e0374d39ca1884a549c7c401312f00071b91f455c3a2afcfe0cda", "0xb931c271513a0f267b9f41444a5650b1918100b8f1a64959c552aff4e2193cc1b9927906c6fa7b8a8c68ef13d79aaa52", "0xa6a1bb9c7d32cb0ca44d8b75af7e40479fbce67d216b48a2bb680d3f3a772003a49d3cd675fc64e9e0f8fabeb86d6d61", "0xb98d609858671543e1c3b8564162ad828808bb50ded261a9f8690ded5b665ed8368c58f947365ed6e84e5a12e27b423d", "0xb3dca58cd69ec855e2701a1d66cad86717ff103ef862c490399c771ad28f675680f9500cb97be48de34bcdc1e4503ffd", "0xb34867c6735d3c49865e246ddf6c3b33baf8e6f164db3406a64ebce4768cb46b0309635e11be985fee09ab7a31d81402", "0xacb966c554188c5b266624208f31fab250b3aa197adbdd14aee5ab27d7fb886eb4350985c553b20fdf66d5d332bfd3fe", "0x943c36a18223d6c870d54c3b051ef08d802b85e9dd6de37a51c932f90191890656c06adfa883c87b906557ae32d09da0", "0x81bca7954d0b9b6c3d4528aadf83e4bc2ef9ea143d6209bc45ae9e7ae9787dbcd8333c41f12c0b6deee8dcb6805e826a", "0xaba176b92256efb68f574e543479e5cf0376889fb48e3db4ebfb7cba91e4d9bcf19dcfec444c6622d9398f06de29e2b9", "0xb9f743691448053216f6ece7cd699871fff4217a1409ceb8ab7bdf3312d11696d62c74b0664ba0a631b1e0237a8a0361", "0xa383c2b6276fa9af346b21609326b53fb14fdf6f61676683076e80f375b603645f2051985706d0401e6fbed7eb0666b6", "0xa9ef2f63ec6d9beb8f3d04e36807d84bda87bdd6b351a3e4a9bf7edcb5618c46c1f58cfbf89e64b40f550915c6988447", "0xa141b2d7a82f5005eaea7ae7d112c6788b9b95121e5b70b7168d971812f3381de8b0082ac1f0a82c7d365922ebd2d26a", "0xb1b76ef8120e66e1535c17038b75255a07849935d3128e3e99e56567b842fb1e8d56ef932d508d2fb18b82f7868fe1a9", "0x8e2e234684c81f21099f5c54f6bbe2dd01e3b172623836c77668a0c49ce1fe218786c3827e4d9ae2ea25c50a8924fb3c", "0xa5caf5ff948bfd3c4ca3ffbdfcd91eec83214a6c6017235f309a0bbf7061d3b0b466307c00b44a1009cf575163898b43", "0x986415a82ca16ebb107b4c50b0c023c28714281db0bcdab589f6cb13d80e473a3034b7081b3c358e725833f6d845cb14", "0xb94836bf406ac2cbacb10e6df5bcdfcc9d9124ae1062767ca4e322d287fd5e353fdcebd0e52407cb3cd68571258a8900", "0x83c6d70a640b33087454a4788dfd9ef3ed00272da084a8d36be817296f71c086b23b576f98178ab8ca6a74f04524b46b", "0xad4115182ad784cfe11bcfc5ce21fd56229cc2ce77ac82746e91a2f0aa53ca6593a22efd2dc4ed8d00f84542643d9c58", "0xab1434c5e5065da826d10c2a2dba0facccab0e52b506ce0ce42fbe47ced5a741797151d9ecc99dc7d6373cfa1779bbf6", "0x8a8b591d82358d55e6938f67ea87a89097ab5f5496f7260adb9f649abb289da12b498c5b2539c2f9614fb4e21b1f66b0", "0x964f355d603264bc1f44c64d6d64debca66f37dff39c971d9fc924f2bc68e6c187b48564a6dc82660a98b035f8addb5d", "0xb66235eaaf47456bc1dc4bde454a028e2ce494ece6b713a94cd6bf27cf18c717fd0c57a5681caaa2ad73a473593cdd7a", "0x9103e3bb74304186fa4e3e355a02da77da4aca9b7e702982fc2082af67127ebb23a455098313c88465bc9b7d26820dd5", "0xb6a42ff407c9dd132670cdb83cbad4b20871716e44133b59a932cd1c3f97c7ac8ff7f61acfaf8628372508d8dc8cad7c", "0x883a9c21c16a167a4171b0f084565c13b6f28ba7c4977a0de69f0a25911f64099e7bbb4da8858f2e93068f4155d04e18", "0x8dbb3220abc6a43220adf0331e3903d3bfd1d5213aadfbd8dfcdf4b2864ce2e96a71f35ecfb7a07c3bbabf0372b50271", "0xb4ad08aee48e176bda390b7d9acf2f8d5eb008f30d20994707b757dc6a3974b2902d29cd9b4d85e032810ad25ac49e97", "0x865bb0f33f7636ec501bb634e5b65751c8a230ae1fa807a961a8289bbf9c7fe8c59e01fbc4c04f8d59b7f539cf79ddd5", "0x86a54d4c12ad1e3605b9f93d4a37082fd26e888d2329847d89afa7802e815f33f38185c5b7292293d788ad7d7da1df97", "0xb26c8615c5e47691c9ff3deca3021714662d236c4d8401c5d27b50152ce7e566266b9d512d14eb63e65bc1d38a16f914", "0x827639d5ce7db43ba40152c8a0eaad443af21dc92636cc8cc2b35f10647da7d475a1e408901cd220552fddad79db74df", "0xa2b79a582191a85dbe22dc384c9ca3de345e69f6aa370aa6d3ff1e1c3de513e30b72df9555b15a46586bd27ea2854d9d", "0xae0d74644aba9a49521d3e9553813bcb9e18f0b43515e4c74366e503c52f47236be92dfbd99c7285b3248c267b1de5a0", "0x80fb0c116e0fd6822a04b9c25f456bdca704e2be7bdc5d141dbf5d1c5eeb0a2c4f5d80db583b03ef3e47517e4f9a1b10", "0xac3a1fa3b4a2f30ea7e0a114cdc479eb51773573804c2a158d603ad9902ae8e39ffe95df09c0d871725a5d7f9ba71a57", "0xb56b2b0d601cba7f817fa76102c68c2e518c6f20ff693aad3ff2e07d6c4c76203753f7f91686b1801e8c4659e4d45c48", "0x89d50c1fc56e656fb9d3915964ebce703cb723fe411ab3c9eaa88ccc5d2b155a9b2e515363d9c600d3c0cee782c43f41", "0xb24207e61462f6230f3cd8ccf6828357d03e725769f7d1de35099ef9ee4dca57dbce699bb49ed994462bee17059d25ce", "0xb886f17fcbcbfcd08ac07f04bb9543ef58510189decaccea4b4158c9174a067cb67d14b6be3c934e6e2a18c77efa9c9c", "0xb9c050ad9cafd41c6e2e192b70d080076eed59ed38ea19a12bd92fa17b5d8947d58d5546aaf5e8e27e1d3b5481a6ce51", "0xaaf7a34d3267e3b1ddbc54c641e3922e89303f7c86ebebc7347ebca4cffad5b76117dac0cbae1a133053492799cd936f", "0xa9ee604ada50adef82e29e893070649d2d4b7136cc24fa20e281ce1a07bd736bf0de7c420369676bcbcecff26fb6e900", "0x9855315a12a4b4cf80ab90b8bd13003223ba25206e52fd4fe6a409232fbed938f30120a3db23eab9c53f308bd8b9db81", "0x8cd488dd7a24f548a3cf03c54dec7ff61d0685cb0f6e5c46c2d728e3500d8c7bd6bba0156f4bf600466fda53e5b20444", "0x890ad4942ebac8f5b16c777701ab80c68f56fa542002b0786f8fea0fb073154369920ac3dbfc07ea598b82f4985b8ced", "0x8de0cf9ddc84c9b92c59b9b044387597799246b30b9f4d7626fc12c51f6e423e08ee4cbfe9289984983c1f9521c3e19d", "0xb474dfb5b5f4231d7775b3c3a8744956b3f0c7a871d835d7e4fd9cc895222c7b868d6c6ce250de568a65851151fac860", "0x86433b6135d9ed9b5ee8cb7a6c40e5c9d30a68774cec04988117302b8a02a11a71a1e03fd8e0264ef6611d219f103007", "0x80b9ed4adbe9538fb1ef69dd44ec0ec5b57cbfea820054d8d445b4261962624b4c70ac330480594bc5168184378379c3", "0x8b2e83562ccd23b7ad2d17f55b1ab7ef5fbef64b3a284e6725b800f3222b8bdf49937f4a873917ada9c4ddfb090938c2", "0xabe78cebc0f5a45d754140d1f685e387489acbfa46d297a8592aaa0d676a470654f417a4f7d666fc0b2508fab37d908e", "0xa9c5f8ff1f8568e252b06d10e1558326db9901840e6b3c26bbd0cd5e850cb5fb3af3f117dbb0f282740276f6fd84126f", "0x975f8dc4fb55032a5df3b42b96c8c0ffecb75456f01d4aef66f973cb7270d4eff32c71520ceefc1adcf38d77b6b80c67", "0xb043306ed2c3d8a5b9a056565afd8b5e354c8c4569fda66b0d797a50a3ce2c08cffbae9bbe292da69f39e89d5dc7911e", "0x8d2afc36b1e44386ba350c14a6c1bb31ff6ea77128a0c5287584ac3584282d18516901ce402b4644a53db1ed8e7fa581", "0x8c294058bed53d7290325c363fe243f6ec4f4ea2343692f4bac8f0cb86f115c069ccb8334b53d2e42c067691ad110dba", "0xb92157b926751aaf7ef82c1aa8c654907dccab6376187ee8b3e8c0c82811eae01242832de953faa13ebaff7da8698b3e", "0xa780c4bdd9e4ba57254b09d745075cecab87feda78c88ffee489625c5a3cf96aa6b3c9503a374a37927d9b78de9bd22b", "0x811f548ef3a2e6a654f7dcb28ac9378de9515ed61e5a428515d9594a83e80b35c60f96a5cf743e6fab0d3cb526149f49", "0x85a4dccf6d90ee8e094731eec53bd00b3887aec6bd81a0740efddf812fd35e3e4fe4f983afb49a8588691c202dabf942", "0xb152c2da6f2e01c8913079ae2b40a09b1f361a80f5408a0237a8131b429677c3157295e11b365b1b1841924b9efb922e", "0x849b9efee8742502ffd981c4517c88ed33e4dd518a330802caff168abae3cd09956a5ee5eda15900243bc2e829016b74", "0x955a933f3c18ec0f1c0e38fa931e4427a5372c46a3906ebe95082bcf878c35246523c23f0266644ace1fa590ffa6d119", "0x911989e9f43e580c886656377c6f856cdd4ff1bd001b6db3bbd86e590a821d34a5c6688a29b8d90f28680e9fdf03ba69", "0xb73b8b4f1fd6049fb68d47cd96a18fcba3f716e0a1061aa5a2596302795354e0c39dea04d91d232aec86b0bf2ba10522", "0x90f87456d9156e6a1f029a833bf3c7dbed98ca2f2f147a8564922c25ae197a55f7ea9b2ee1f81bf7383197c4bad2e20c", "0x903cba8b1e088574cb04a05ca1899ab00d8960580c884bd3c8a4c98d680c2ad11410f2b75739d6050f91d7208cac33a5", "0x9329987d42529c261bd15ecedd360be0ea8966e7838f32896522c965adfc4febf187db392bd441fb43bbd10c38fdf68b", "0x8178ee93acf5353baa349285067b20e9bb41aa32d77b5aeb7384fe5220c1fe64a2461bd7a83142694fe673e8bbf61b7c", "0xa06a8e53abcff271b1394bcc647440f81fb1c1a5f29c27a226e08f961c3353f4891620f2d59b9d1902bf2f5cc07a4553", "0xaaf5fe493b337810889e777980e6bbea6cac39ac66bc0875c680c4208807ac866e9fda9b5952aa1d04539b9f4a4bec57", "0xaa058abb1953eceac14ccfa7c0cc482a146e1232905dcecc86dd27f75575285f06bbae16a8c9fe8e35d8713717f5f19f", "0x8f15dd732799c879ca46d2763453b359ff483ca33adb1d0e0a57262352e0476c235987dc3a8a243c74bc768f93d3014c", "0xa61cc8263e9bc03cce985f1663b8a72928a607121005a301b28a278e9654727fd1b22bc8a949af73929c56d9d3d4a273", "0x98d6dc78502d19eb9f921225475a6ebcc7b44f01a2df6f55ccf6908d65b27af1891be2a37735f0315b6e0f1576c1f8d8", "0x8bd258b883f3b3793ec5be9472ad1ff3dc4b51bc5a58e9f944acfb927349ead8231a523cc2175c1f98e7e1e2b9f363b8", "0xaeacc2ecb6e807ad09bedd99654b097a6f39840e932873ace02eabd64ccfbb475abdcb62939a698abf17572d2034c51e", "0xb8ccf78c08ccd8df59fd6eda2e01de328bc6d8a65824d6f1fc0537654e9bc6bf6f89c422dd3a295cce628749da85c864", "0x8f91fd8cb253ba2e71cc6f13da5e05f62c2c3b485c24f5d68397d04665673167fce1fc1aec6085c69e87e66ec555d3fd", "0xa254baa10cb26d04136886073bb4c159af8a8532e3fd36b1e9c3a2e41b5b2b6a86c4ebc14dbe624ee07b7ccdaf59f9ab", "0x94e3286fe5cd68c4c7b9a7d33ae3d714a7f265cf77cd0e9bc19fc51015b1d1c34ad7e3a5221c459e89f5a043ee84e3a9", "0xa279da8878af8d449a9539bec4b17cea94f0242911f66fab275b5143ab040825f78c89cb32a793930609415cfa3a1078", "0xac846ceb89c9e5d43a2991c8443079dc32298cd63e370e64149cec98cf48a6351c09c856f2632fd2f2b3d685a18bbf8b", "0xa847b27995c8a2e2454aaeb983879fb5d3a23105c33175839f7300b7e1e8ec3efd6450e9fa3f10323609dee7b98c6fd5", "0xa2f432d147d904d185ff4b2de8c6b82fbea278a2956bc406855b44c18041854c4f0ecccd472d1d0dff1d8aa8e281cb1d", "0x94a48ad40326f95bd63dff4755f863a1b79e1df771a1173b17937f9baba57b39e651e7695be9f66a472f098b339364fc", "0xa12a0ccd8f96e96e1bc6494341f7ebce959899341b3a084aa1aa87d1c0d489ac908552b7770b887bb47e7b8cbc3d8e66", "0x81a1f1681bda923bd274bfe0fbb9181d6d164fe738e54e25e8d4849193d311e2c4253614ed673c98af2c798f19a93468", "0xabf71106a05d501e84cc54610d349d7d5eae21a70bd0250f1bebbf412a130414d1c8dbe673ffdb80208fd72f1defa4d4", "0x96266dc2e0df18d8136d79f5b59e489978eee0e6b04926687fe389d4293c14f36f055c550657a8e27be4118b64254901", "0x8df5dcbefbfb4810ae3a413ca6b4bf08619ca53cd50eb1dde2a1c035efffc7b7ac7dff18d403253fd80104bd83dc029e", "0x9610b87ff02e391a43324a7122736876d5b3af2a137d749c52f75d07b17f19900b151b7f439d564f4529e77aa057ad12", "0xa90a5572198b40fe2fcf47c422274ff36c9624df7db7a89c0eb47eb48a73a03c985f4ac5016161c76ca317f64339bce1", "0x98e5e61a6ab6462ba692124dba7794b6c6bde4249ab4fcc98c9edd631592d5bc2fb5e38466691a0970a38e48d87c2e43", "0x918cefb8f292f78d4db81462c633daf73b395e772f47b3a7d2cea598025b1d8c3ec0cbff46cdb23597e74929981cde40", "0xa98918a5dc7cf610fe55f725e4fd24ce581d594cb957bb9b4e888672e9c0137003e1041f83e3f1d7b9caab06462c87d4", "0xb92b74ac015262ca66c33f2d950221e19d940ba3bf4cf17845f961dc1729ae227aa9e1f2017829f2135b489064565c29", "0xa053ee339f359665feb178b4e7ee30a85df37debd17cacc5a27d6b3369d170b0114e67ad1712ed26d828f1df641bcd99", "0x8c3c8bad510b35da5ce5bd84b35c958797fbea024ad1c97091d2ff71d9b962e9222f65a9b776e5b3cc29c36e1063d2ee", "0xaf99dc7330fe7c37e850283eb47cc3257888e7c197cb0d102edf94439e1e02267b6a56306d246c326c4c79f9dc8c6986", "0xafecb2dc34d57a725efbd7eb93d61eb29dbe8409b668ab9ea040791f5b796d9be6d4fc10d7f627bf693452f330cf0435", "0x93334fedf19a3727a81a6b6f2459db859186227b96fe7a391263f69f1a0884e4235de64d29edebc7b99c44d19e7c7d7a", "0x89579c51ac405ad7e9df13c904061670ce4b38372492764170e4d3d667ed52e5d15c7cd5c5991bbfa3a5e4e3fa16363e", "0x9778f3e8639030f7ef1c344014f124e375acb8045bd13d8e97a92c5265c52de9d1ffebaa5bc3e1ad2719da0083222991", "0x88f77f34ee92b3d36791bdf3326532524a67d544297dcf1a47ff00b47c1b8219ff11e34034eab7d23b507caa2fd3c6b9", "0xa699c1e654e7c484431d81d90657892efeb4adcf72c43618e71ca7bd7c7a7ebbb1db7e06e75b75dc4c74efd306b5df3f", "0x81d13153baebb2ef672b5bdb069d3cd669ce0be96b742c94e04038f689ff92a61376341366b286eee6bf3ae85156f694", "0x81efb17de94400fdacc1deec2550cbe3eecb27c7af99d8207e2f9be397e26be24a40446d2a09536bb5172c28959318d9", "0x989b21ebe9ceab02488992673dc071d4d5edec24bff0e17a4306c8cb4b3c83df53a2063d1827edd8ed16d6e837f0d222", "0x8d6005d6536825661b13c5fdce177cb37c04e8b109b7eb2b6d82ea1cb70efecf6a0022b64f84d753d165edc2bba784a3", "0xa32607360a71d5e34af2271211652d73d7756d393161f4cf0da000c2d66a84c6826e09e759bd787d4fd0305e2439d342", "0xaaad8d6f6e260db45d51b2da723be6fa832e76f5fbcb77a9a31e7f090dd38446d3b631b96230d78208cae408c288ac4e", "0xabcfe425255fd3c5cffd3a818af7650190c957b6b07b632443f9e33e970a8a4c3bf79ac9b71f4d45f238a04d1c049857", "0xaeabf026d4c783adc4414b5923dbd0be4b039cc7201219f7260d321f55e9a5b166d7b5875af6129c034d0108fdc5d666", "0xaf49e740c752d7b6f17048014851f437ffd17413c59797e5078eaaa36f73f0017c3e7da020310cfe7d3c85f94a99f203", "0x8854ca600d842566e3090040cd66bb0b3c46dae6962a13946f0024c4a8aca447e2ccf6f240045f1ceee799a88cb9210c", "0xb6c03b93b1ab1b88ded8edfa1b487a1ed8bdce8535244dddb558ffb78f89b1c74058f80f4db2320ad060d0c2a9c351cc", "0xb5bd7d17372faff4898a7517009b61a7c8f6f0e7ed4192c555db264618e3f6e57fb30a472d169fea01bf2bf0362a19a8", "0x96eb1d38319dc74afe7e7eb076fcd230d19983f645abd14a71e6103545c01301b31c47ae931e025f3ecc01fb3d2f31fa", "0xb55a8d30d4403067def9b65e16f867299f8f64c9b391d0846d4780bc196569622e7e5b64ce799b5aefac8f965b2a7a7b", "0x8356d199a991e5cbbff608752b6291731b6b6771aed292f8948b1f41c6543e4ab1bedc82dd26d10206c907c03508df06", "0x97f4137445c2d98b0d1d478049de952610ad698c91c9d0f0e7227d2aae690e9935e914ec4a2ea1fbf3fc1dddfeeacebb", "0xaf5621707e0938320b15ddfc87584ab325fbdfd85c30efea36f8f9bd0707d7ec12c344eff3ec21761189518d192df035", "0x8ac7817e71ea0825b292687928e349da7140285d035e1e1abff0c3704fa8453faaae343a441b7143a74ec56539687cc4", "0x8a5e0a9e4758449489df10f3386029ada828d1762e4fb0a8ffe6b79e5b6d5d713cb64ed95960e126398b0cdb89002bc9", "0x81324be4a71208bbb9bca74b77177f8f1abb9d3d5d9db195d1854651f2cf333cd618d35400da0f060f3e1b025124e4b2", "0x849971d9d095ae067525b3cbc4a7dfae81f739537ade6d6cec1b42fb692d923176197a8770907c58069754b8882822d6", "0x89f830825416802477cc81fdf11084885865ee6607aa15aa4eb28e351c569c49b8a1b9b5e95ddc04fa0ebafe20071313", "0x9240aeeaff37a91af55f860b9badd466e8243af9e8c96a7aa8cf348cd270685ab6301bc135b246dca9eda696f8b0e350", "0xacf74db78cc33138273127599eba35b0fb4e7b9a69fe02dae18fc6692d748ca332bd00b22afa8e654ed587aab11833f3", "0xb091e6d37b157b50d76bd297ad752220cd5c9390fac16dc838f8557aed6d9833fc920b61519df21265406216315e883f", "0xa6446c429ebf1c7793c622250e23594c836b2fbcaf6c5b3d0995e1595a37f50ea643f3e549b0be8bbdadd69044d72ab9", "0x93e675353bd60e996bf1c914d5267eeaa8a52fc3077987ccc796710ef9becc6b7a00e3d82671a6bdfb8145ee3c80245a", "0xa2f731e43251d04ed3364aa2f072d05355f299626f2d71a8a38b6f76cf08c544133f7d72dd0ab4162814b674b9fc7fa6", "0x97a8b791a5a8f6e1d0de192d78615d73d0c38f1e557e4e15d15adc663d649e655bc8da3bcc499ef70112eafe7fb45c7a", "0x98cd624cbbd6c53a94469be4643c13130916b91143425bcb7d7028adbbfede38eff7a21092af43b12d4fab703c116359", "0x995783ce38fd5f6f9433027f122d4cf1e1ff3caf2d196ce591877f4a544ce9113ead60de2de1827eaff4dd31a20d79a8", "0x8cf251d6f5229183b7f3fe2f607a90b4e4b6f020fb4ba2459d28eb8872426e7be8761a93d5413640a661d73e34a5b81f", "0xb9232d99620652a3aa7880cad0876f153ff881c4ed4c0c2e7b4ea81d5d42b70daf1a56b869d752c3743c6d4c947e6641", "0x849716f938f9d37250cccb1bf77f5f9fde53096cdfc6f2a25536a6187029a8f1331cdbed08909184b201f8d9f04b792f", "0x80c7c4de098cbf9c6d17b14eba1805e433b5bc905f6096f8f63d34b94734f2e4ebf4bce8a177efd1186842a61204a062", "0xb790f410cf06b9b8daadceeb4fd5ff40a2deda820c8df2537e0a7554613ae3948e149504e3e79aa84889df50c8678eeb", "0x813aab8bd000299cd37485b73cd7cba06e205f8efb87f1efc0bae8b70f6db2bc7702eb39510ad734854fb65515fe9d0f", "0x94f0ab7388ac71cdb67f6b85dfd5945748afb2e5abb622f0b5ad104be1d4d0062b651f134ba22385c9e32c2dfdcccce1", "0xab6223dca8bd6a4f969e21ccd9f8106fc5251d321f9e90cc42cea2424b3a9c4e5060a47eeef6b23c7976109b548498e8", "0x859c56b71343fce4d5c5b87814c47bf55d581c50fd1871a17e77b5e1742f5af639d0e94d19d909ec7dfe27919e954e0c", "0xaae0d632b6191b8ad71b027791735f1578e1b89890b6c22e37de0e4a6074886126988fe8319ae228ac9ef3b3bcccb730", "0x8ca9f32a27a024c3d595ecfaf96b0461de57befa3b331ab71dc110ec3be5824fed783d9516597537683e77a11d334338", "0xa061df379fb3f4b24816c9f6cd8a94ecb89b4c6dc6cd81e4b8096fa9784b7f97ab3540259d1de9c02eb91d9945af4823", "0x998603102ac63001d63eb7347a4bb2bf4cf33b28079bb48a169076a65c20d511ccd3ef696d159e54cc8e772fb5d65d50", "0x94444d96d39450872ac69e44088c252c71f46be8333a608a475147752dbb99db0e36acfc5198f158509401959c12b709", "0xac1b51b6c09fe055c1d7c9176eea9adc33f710818c83a1fbfa073c8dc3a7eb3513cbdd3f5960b7845e31e3e83181e6ba", "0x803d530523fc9e1e0f11040d2412d02baef3f07eeb9b177fa9bfa396af42eea898a4276d56e1db998dc96ae47b644cb2", "0x85a3c9fc7638f5bf2c3e15ba8c2fa1ae87eb1ceb44c6598c67a2948667a9dfa41e61f66d535b4e7fda62f013a5a8b885", "0xa961cf5654c46a1a22c29baf7a4e77837a26b7f138f410e9d1883480ed5fa42411d522aba32040b577046c11f007388e", "0xad1154142344f494e3061ef45a34fab1aaacf5fdf7d1b26adbb5fbc3d795655fa743444e39d9a4119b4a4f82a6f30441", "0xb1d6c30771130c77806e7ab893b73d4deb590b2ff8f2f8b5e54c2040c1f3e060e2bd99afc668cf706a2df666a508bbf6", "0xa00361fd440f9decabd98d96c575cd251dc94c60611025095d1201ef2dedde51cb4de7c2ece47732e5ed9b3526c2012c", "0xa85c5ab4d17d328bda5e6d839a9a6adcc92ff844ec25f84981e4f44a0e8419247c081530f8d9aa629c7eb4ca21affba6", "0xa4ddd3eab4527a2672cf9463db38bc29f61460e2a162f426b7852b7a7645fbd62084fd39a8e4d60e1958cce436dd8f57", "0x811648140080fe55b8618f4cf17f3c5a250adb0cd53d885f2ddba835d2b4433188e41fc0661faac88e4ff910b16278c0", "0xb85c7f1cfb0ed29addccf7546023a79249e8f15ac2d14a20accbfef4dd9dc11355d599815fa09d2b6b4e966e6ea8cff1", "0xa10b5d8c260b159043b020d5dd62b3467df2671afea6d480ca9087b7e60ed170c82b121819d088315902842d66c8fb45", "0x917e191df1bcf3f5715419c1e2191da6b8680543b1ba41fe84ed07ef570376e072c081beb67b375fca3565a2565bcabb", "0x881fd967407390bfd7badc9ab494e8a287559a01eb07861f527207c127eadea626e9bcc5aa9cca2c5112fbac3b3f0e9c", "0x959fd71149af82cc733619e0e5bf71760ca2650448c82984b3db74030d0e10f8ab1ce1609a6de6f470fe8b5bd90df5b3", "0xa3370898a1c5f33d15adb4238df9a6c945f18b9ada4ce2624fc32a844f9ece4c916a64e9442225b6592afa06d2e015f2", "0x817efb8a791435e4236f7d7b278181a5fa34587578c629dbc14fbf9a5c26772290611395eecd20222a4c58649fc256d8", "0xa04c9876acf2cfdc8ef96de4879742709270fa1d03fe4c8511fbef2d59eb0aaf0336fa2c7dfe41a651157377fa217813", "0x81e15875d7ea7f123e418edf14099f2e109d4f3a6ce0eb65f67fe9fb10d2f809a864a29f60ad3fc949f89e2596b21783", "0xb49f529975c09e436e6bc202fdc16e3fdcbe056db45178016ad6fdece9faad4446343e83aed096209690b21a6910724f", "0x879e8eda589e1a279f7f49f6dd0580788c040d973748ec4942dbe51ea8fbd05983cc919b78f0c6b92ef3292ae29db875", "0x81a2b74b2118923f34139a102f3d95e7eee11c4c2929c2576dee200a5abfd364606158535a6c9e4178a6a83dbb65f3c4", "0x8913f281d8927f2b45fc815d0f7104631cb7f5f7278a316f1327d670d15868daadd2a64e3eb98e1f53fe7e300338cc80", "0xa6f815fba7ef9af7fbf45f93bc952e8b351f5de6568a27c7c47a00cb39a254c6b31753794f67940fc7d2e9cc581529f4", "0xb3722a15c66a0014ce4d082de118def8d39190c15678a472b846225585f3a83756ae1b255b2e3f86a26168878e4773b2", "0x817ae61ab3d0dd5b6e24846b5a5364b1a7dc2e77432d9fed587727520ae2f307264ea0948c91ad29f0aea3a11ff38624", "0xb3db467464415fcad36dc1de2d6ba7686772a577cc2619242ac040d6734881a45d3b40ed4588db124e4289cfeec4bbf6", "0xad66a14f5a54ac69603b16e5f1529851183da77d3cc60867f10aea41339dd5e06a5257982e9e90a352cdd32750f42ee4", "0xadafa3681ef45d685555601a25a55cf23358319a17f61e2179e704f63df83a73bdd298d12cf6cef86db89bd17119e11d", "0xa379dc44cb6dd3b9d378c07b2ec654fec7ca2f272de6ba895e3d00d20c9e4c5550498a843c8ac67e4221db2115bedc1c", "0xb7bf81c267a78efc6b9e5a904574445a6487678d7ef70054e3e93ea6a23f966c2b68787f9164918e3b16d2175459ed92", "0xb41d66a13a4afafd5760062b77f79de7e6ab8ccacde9c6c5116a6d886912fb491dc027af435b1b44aacc6af7b3c887f2", "0x9904d23a7c1c1d2e4bab85d69f283eb0a8e26d46e8b7b30224438015c936729b2f0af7c7c54c03509bb0500acb42d8a4", "0xae30d65e9e20c3bfd603994ae2b175ff691d51f3e24b2d058b3b8556d12ca4c75087809062dddd4aaac81c94d15d8a17", "0x9245162fab42ac01527424f6013310c3eb462982518debef6c127f46ba8a06c705d7dc9f0a41e796ba8d35d60ae6cc64", "0x87fab853638d7a29a20f3ba2b1a7919d023e9415bfa78ebb27973d8cbc7626f584dc5665d2e7ad71f1d760eba9700d88", "0x85aac46ecd330608e5272430970e6081ff02a571e8ea444f1e11785ea798769634a22a142d0237f67b75369d3c484a8a", "0x938c85ab14894cc5dfce3d80456f189a2e98eddbc8828f4ff6b1df1dcb7b42b17ca2ff40226a8a1390a95d63dca698dd", "0xa18ce1f846e3e3c4d846822f60271eecf0f5d7d9f986385ac53c5ace9589dc7c0188910448c19b91341a1ef556652fa9", "0x8611608a9d844f0e9d7584ad6ccf62a5087a64f764caf108db648a776b5390feb51e5120f0ef0e9e11301af3987dd7dc", "0x8106333ba4b4de8d1ae43bc9735d3fea047392e88efd6a2fa6f7b924a18a7a265ca6123c3edc0f36307dd7fb7fe89257", "0xa91426fa500951ff1b051a248c050b7139ca30dde8768690432d597d2b3c4357b11a577be6b455a1c5d145264dcf81fc", "0xb7f9f90e0e450f37b081297f7f651bad0496a8b9afd2a4cf4120a2671aaaa8536dce1af301258bfbfdb122afa44c5048", "0x84126da6435699b0c09fa4032dec73d1fca21d2d19f5214e8b0bea43267e9a8dd1fc44f8132d8315e734c8e2e04d7291", "0xaff064708103884cb4f1a3c1718b3fc40a238d35cf0a7dc24bdf9823693b407c70da50df585bf5bc4e9c07d1c2d203e8", "0xa8b40fc6533752983a5329c31d376c7a5c13ce6879cc7faee648200075d9cd273537001fb4c86e8576350eaac6ba60c2", "0xa02db682bdc117a84dcb9312eb28fcbde12d49f4ce915cc92c610bb6965ec3cc38290f8c5b5ec70afe153956692cda95", "0x86decd22b25d300508472c9ce75d3e465b737e7ce13bc0fcce32835e54646fe12322ba5bc457be18bfd926a1a6ca4a38", "0xa18666ef65b8c2904fd598791f5627207165315a85ee01d5fb0e6b2e10bdd9b00babc447da5bd63445e3337de33b9b89", "0x89bb0c06effadefdaf34ffe4b123e1678a90d4451ee856c863df1e752eef41fd984689ded8f0f878bf8916d5dd8e8024", "0x97cfcba08ebec05d0073992a66b1d7d6fb9d95871f2cdc36db301f78bf8069294d1c259efef5c93d20dc937eedae3a1a", "0xac2643b14ece79dcb2e289c96776a47e2bebd40dd6dc74fd035df5bb727b5596f40e3dd2d2202141e69b0993717ede09", "0xa5e6fd88a2f9174d9bd4c6a55d9c30974be414992f22aa852f552c7648f722ed8077acf5aba030abd47939bb451b2c60", "0x8ad40a612824a7994487731a40b311b7349038c841145865539c6ada75c56de6ac547a1c23df190e0caaafecddd80ccc", "0x953a7cea1d857e09202c438c6108060961f195f88c32f0e012236d7a4b39d840c61b162ec86436e8c38567328bea0246", "0x80d8b47a46dae1868a7b8ccfe7029445bbe1009dad4a6c31f9ef081be32e8e1ac1178c3c8fb68d3e536c84990cc035b1", "0x81ecd99f22b3766ce0aca08a0a9191793f68c754fdec78b82a4c3bdc2db122bbb9ebfd02fc2dcc6e1567a7d42d0cc16a", "0xb1dd0446bccc25846fb95d08c1c9cc52fb51c72c4c5d169ffde56ecfe800f108dc1106d65d5c5bd1087c656de3940b63", "0xb87547f0931e164e96de5c550ca5aa81273648fe34f6e193cd9d69cf729cb432e17aa02e25b1c27a8a0d20a3b795e94e", "0x820a94e69a927e077082aae66f6b292cfbe4589d932edf9e68e268c9bd3d71ef76cf7d169dd445b93967c25db11f58f1", "0xb0d07ddf2595270c39adfa0c8cf2ab1322979b0546aa4d918f641be53cd97f36c879bb75d205e457c011aca3bbd9f731", "0x8700b876b35b4b10a8a9372c5230acecd39539c1bb87515640293ad4464a9e02929d7d6a6a11112e8a29564815ac0de4", "0xa61a601c5bb27dcb97e37c8e2b9ce479c6b192a5e04d9ed5e065833c5a1017ee5f237b77d1a17be5d48f8e7cc0bcacf6", "0x92fb88fe774c1ba1d4a08cae3c0e05467ad610e7a3f1d2423fd47751759235fe0a3036db4095bd6404716aa03820f484", "0xb274f140d77a3ce0796f5e09094b516537ccaf27ae1907099bff172e6368ba85e7c3ef8ea2a07457cac48ae334da95b3", "0xb2292d9181f16581a9a9142490b2bdcdfb218ca6315d1effc8592100d792eb89d5356996c890441f04f2b4a95763503e", "0x8897e73f576d86bc354baa3bd96e553107c48cf5889dcc23c5ba68ab8bcd4e81f27767be2233fdfa13d39f885087e668", "0xa29eac6f0829791c728d71abc49569df95a4446ecbfc534b39f24f56c88fe70301838dfc1c19751e7f3c5c1b8c6af6a0", "0x9346dc3720adc5df500a8df27fd9c75ef38dc5c8f4e8ed66983304750e66d502c3c59b8e955be781b670a0afc70a2167", "0x9566d534e0e30a5c5f1428665590617e95fd05d45f573715f58157854ad596ece3a3cfec61356aee342308d623e029d5", "0xa464fb8bffe6bd65f71938c1715c6e296cc6d0311a83858e4e7eb5873b7f2cf0c584d2101e3407b85b64ca78b2ac93ce", "0xb54088f7217987c87e9498a747569ac5b2f8afd5348f9c45bf3fd9fbf713a20f495f49c8572d087efe778ac7313ad6d3", "0x91fa9f5f8000fe050f5b224d90b59fcce13c77e903cbf98ded752e5b3db16adb2bc1f8c94be48b69f65f1f1ad81d6264", "0x92d04a5b0ac5d8c8e313709b432c9434ecd3e73231f01e9b4e7952b87df60cbfa97b5dedd2200bd033b4b9ea8ba45cc1", "0xa94b90ad3c3d6c4bbe169f8661a790c40645b40f0a9d1c7220f01cf7fc176e04d80bab0ced9323fcafb93643f12b2760", "0x94d86149b9c8443b46196f7e5a3738206dd6f3be7762df488bcbb9f9ee285a64c997ed875b7b16b26604fa59020a8199", "0x82efe4ae2c50a2d7645240c173a047f238536598c04a2c0b69c96e96bd18e075a99110f1206bc213f39edca42ba00cc1", "0xab8667685f831bc14d4610f84a5da27b4ea5b133b4d991741a9e64dceb22cb64a3ce8f1b6e101d52af6296df7127c9ad", "0x83ba433661c05dcc5d562f4a9a261c8110dac44b8d833ae1514b1fc60d8b4ee395b18804baea04cb10adb428faf713c3", "0xb5748f6f660cc5277f1211d2b8649493ed8a11085b871cd33a5aea630abd960a740f08c08be5f9c21574600ac9bf5737", "0xa5c8dd12af48fb710642ad65ebb97ca489e8206741807f7acfc334f8035d3c80593b1ff2090c9bb7bd138f0c48714ca8", "0xa2b382fd5744e3babf454b1d806cc8783efeb4761bc42b6914ea48a46a2eae835efbe0a18262b6bc034379e03cf1262b", "0xb3145ffaf603f69f15a64936d32e3219eea5ed49fdfd2f5bf40ea0dfd974b36fb6ff12164d4c2282d892db4cf3ff3ce1", "0x87a316fb213f4c5e30c5e3face049db66be4f28821bd96034714ec23d3e97849d7b301930f90a4323c7ccf53de23050c", "0xb9de09a919455070fed6220fc179c8b7a4c753062bcd27acf28f5b9947a659c0b364298daf7c85c4ca6fca7f945add1f", "0x806fbd98d411b76979464c40ad88bc07a151628a27fcc1012ba1dfbaf5b5cc9d962fb9b3386008978a12515edce934bc", "0xa15268877fae0d21610ae6a31061ed7c20814723385955fac09fdc9693a94c33dea11db98bb89fdfe68f933490f5c381", "0x8d633fb0c4da86b2e0b37d8fad5972d62bff2ac663c5ec815d095cd4b7e1fe66ebef2a2590995b57eaf941983c7ad7a4", "0x8139e5dd9cf405e8ef65f11164f0440827d98389ce1b418b0c9628be983a9ddd6cf4863036ccb1483b40b8a527acd9ed", "0x88b15fa94a08eac291d2b94a2b30eb851ff24addf2cc30b678e72e32cfcb3424cf4b33aa395d741803f3e578ddf524de", "0xb5eaf0c8506e101f1646bcf049ee38d99ea1c60169730da893fd6020fd00a289eb2f415947e44677af49e43454a7b1be", "0x8489822ad0647a7e06aa2aa5595960811858ddd4542acca419dd2308a8c5477648f4dd969a6740bb78aa26db9bfcc555", "0xb1e9a7b9f3423c220330d45f69e45fa03d7671897cf077f913c252e3e99c7b1b1cf6d30caad65e4228d5d7b80eb86e5e", "0xb28fe9629592b9e6a55a1406903be76250b1c50c65296c10c5e48c64b539fb08fe11f68cf462a6edcbba71b0cee3feb2", "0xa41acf96a02c96cd8744ff6577c244fc923810d17ade133587e4c223beb7b4d99fa56eae311a500d7151979267d0895c", "0x880798938fe4ba70721be90e666dfb62fcab4f3556fdb7b0dc8ec5bc34f6b4513df965eae78527136eb391889fe2caf9", "0x98d4d89d358e0fb7e212498c73447d94a83c1b66e98fc81427ab13acddb17a20f52308983f3a5a8e0aaacec432359604", "0x81430b6d2998fc78ba937a1639c6020199c52da499f68109da227882dc26d005b73d54c5bdcac1a04e8356a8ca0f7017", "0xa8d906a4786455eb74613aba4ce1c963c60095ffb8658d368df9266fdd01e30269ce10bf984e7465f34b4fd83beba26a", "0xaf54167ac1f954d10131d44a8e0045df00d581dd9e93596a28d157543fbe5fb25d213806ed7fb3cba6b8f5b5423562db", "0x8511e373a978a12d81266b9afbd55035d7bc736835cfa921903a92969eeba3624437d1346b55382e61415726ab84a448", "0x8cf43eea93508ae586fa9a0f1354a1e16af659782479c2040874a46317f9e8d572a23238efa318fdfb87cc63932602b7", "0xb0bdd3bacff077173d302e3a9678d1d37936188c7ecc34950185af6b462b7c679815176f3cce5db19aac8b282f2d60ad", "0xa355e9b87f2f2672052f5d4d65b8c1c827d24d89b0d8594641fccfb69aef1b94009105f3242058bb31c8bf51caae5a41", "0xb8baa9e4b950b72ff6b88a6509e8ed1304bc6fd955748b2e59a523a1e0c5e99f52aec3da7fa9ff407a7adf259652466c", "0x840bc3dbb300ea6f27d1d6dd861f15680bd098be5174f45d6b75b094d0635aced539fa03ddbccb453879de77fb5d1fe9", "0xb4bc7e7e30686303856472bae07e581a0c0bfc815657c479f9f5931cff208d5c12930d2fd1ff413ebd8424bcd7a9b571", "0x89b5d514155d7999408334a50822508b9d689add55d44a240ff2bdde2eee419d117031f85e924e2a2c1ca77db9b91eea", "0xa8604b6196f87a04e1350302e8aa745bba8dc162115d22657b37a1d1a98cb14876ddf7f65840b5dbd77e80cd22b4256c", "0x83cb7acdb9e03247515bb2ce0227486ccf803426717a14510f0d59d45e998b245797d356f10abca94f7a14e1a2f0d552", "0xaeb3266a9f16649210ab2df0e1908ac259f34ce1f01162c22b56cf1019096ee4ea5854c36e30bb2feb06c21a71e8a45c", "0x89e72e86edf2aa032a0fc9acf4d876a40865fbb2c8f87cb7e4d88856295c4ac14583e874142fd0c314a49aba68c0aa3c", "0x8c3576eba0583c2a7884976b4ed11fe1fda4f6c32f6385d96c47b0e776afa287503b397fa516a455b4b8c3afeedc76db", "0xa31e5b633bda9ffa174654fee98b5d5930a691c3c42fcf55673d927dbc8d91c58c4e42e615353145431baa646e8bbb30", "0x89f2f3f7a8da1544f24682f41c68114a8f78c86bd36b066e27da13acb70f18d9f548773a16bd8e24789420e17183f137", "0xada27fa4e90a086240c9164544d2528621a415a5497badb79f8019dc3dce4d12eb6b599597e47ec6ac39c81efda43520", "0x90dc1eb21bf21c0187f359566fc4bf5386abea52799306a0e5a1151c0817c5f5bc60c86e76b1929c092c0f3ff48cedd2", "0xb702a53ebcc17ae35d2e735a347d2c700e9cbef8eadbece33cac83df483b2054c126593e1f462cfc00a3ce9d737e2af5", "0x9891b06455ec925a6f8eafffba05af6a38cc5e193acaaf74ffbf199df912c5197106c5e06d72942bbb032ce277b6417f", "0x8c0ee71eb01197b019275bcf96cae94e81d2cdc3115dbf2d8e3080074260318bc9303597e8f72b18f965ad601d31ec43", "0x8aaf580aaf75c1b7a5f99ccf60503506e62058ef43b28b02f79b8536a96be3f019c9f71caf327b4e6730134730d1bef5", "0xae6f9fc21dd7dfa672b25a87eb0a41644f7609fab5026d5cedb6e43a06dbbfd6d6e30322a2598c8dedde88c52eaed626", "0x8159b953ffece5693edadb2e906ebf76ff080ee1ad22698950d2d3bfc36ac5ea78f58284b2ca180664452d55bd54716c", "0xab7647c32ca5e9856ac283a2f86768d68de75ceeba9e58b74c5324f8298319e52183739aba4340be901699d66ac9eb3f", "0xa4d85a5701d89bcfaf1572db83258d86a1a0717603d6f24ac2963ffcf80f1265e5ab376a4529ca504f4396498791253c", "0x816080c0cdbfe61b4d726c305747a9eb58ac26d9a35f501dd32ba43c098082d20faf3ccd41aad24600aa73bfa453dfac", "0x84f3afac024f576b0fd9acc6f2349c2fcefc3f77dbe5a2d4964d14b861b88e9b1810334b908cf3427d9b67a8aee74b18", "0x94b390655557b1a09110018e9b5a14490681ade275bdc83510b6465a1218465260d9a7e2a6e4ec700f58c31dc3659962", "0xa8c66826b1c04a2dd4c682543242e7a57acae37278bd09888a3d17747c5b5fec43548101e6f46d703638337e2fd3277b", "0x86e6f4608a00007fa533c36a5b054c5768ccafe41ad52521d772dcae4c8a4bcaff8f7609be30d8fab62c5988cbbb6830", "0x837da4cf09ae8aa0bceb16f8b3bfcc3b3367aecac9eed6b4b56d7b65f55981ef066490764fb4c108792623ecf8cad383", "0x941ff3011462f9b5bf97d8cbdb0b6f5d37a1b1295b622f5485b7d69f2cb2bcabc83630dae427f0259d0d9539a77d8424", "0xb99e5d6d82aa9cf7d5970e7f710f4039ac32c2077530e4c2779250c6b9b373bc380adb0a03b892b652f649720672fc8c", "0xa791c78464b2d65a15440b699e1e30ebd08501d6f2720adbc8255d989a82fcded2f79819b5f8f201bed84a255211b141", "0x84af7ad4a0e31fcbb3276ab1ad6171429cf39adcf78dc03750dc5deaa46536d15591e26d53e953dfb31e1622bc0743ab", "0xa833e62fe97e1086fae1d4917fbaf09c345feb6bf1975b5cb863d8b66e8d621c7989ab3dbecda36bc9eaffc5eaa6fa66", "0xb4ef79a46a2126f53e2ebe62770feb57fd94600be29459d70a77c5e9cc260fa892be06cd60f886bf48459e48eb50d063", "0xb43b8f61919ea380bf151c294e54d3a3ff98e20d1ee5efbfe38aa2b66fafbc6a49739793bd5cb1c809f8b30466277c3a", "0xab37735af2412d2550e62df9d8b3b5e6f467f20de3890bf56faf1abf2bf3bd1d98dc3fa0ad5e7ab3fce0fa20409eb392", "0x82416b74b1551d484250d85bb151fabb67e29cce93d516125533df585bc80779ab057ea6992801a3d7d5c6dcff87a018", "0x8145d0787f0e3b5325190ae10c1d6bee713e6765fb6a0e9214132c6f78f4582bb2771aaeae40d3dad4bafb56bf7e36d8", "0xb6935886349ecbdd5774e12196f4275c97ec8279fdf28ccf940f6a022ebb6de8e97d6d2173c3fe402cbe9643bed3883b", "0x87ef9b4d3dc71ac86369f8ed17e0dd3b91d16d14ae694bc21a35b5ae37211b043d0e36d8ff07dcc513fb9e6481a1f37f", "0xae1d0ded32f7e6f1dc8fef495879c1d9e01826f449f903c1e5034aeeabc5479a9e323b162b688317d46d35a42d570d86", "0xa40d16497004db4104c6794e2f4428d75bdf70352685944f3fbe17526df333e46a4ca6de55a4a48c02ecf0bde8ba03c0", "0x8d45121efba8cc308a498e8ee39ea6fa5cae9fb2e4aab1c2ff9d448aa8494ccbec9a078f978a86fcd97b5d5e7be7522a", "0xa8173865c64634ba4ac2fa432740f5c05056a9deaf6427cb9b4b8da94ca5ddbc8c0c5d3185a89b8b28878194de9cdfcd", "0xb6ec06a74d690f6545f0f0efba236e63d1fdfba54639ca2617408e185177ece28901c457d02b849fd00f1a53ae319d0a", "0xb69a12df293c014a40070e3e760169b6f3c627caf9e50b35a93f11ecf8df98b2bc481b410eecb7ab210bf213bbe944de", "0x97e7dc121795a533d4224803e591eef3e9008bab16f12472210b73aaf77890cf6e3877e0139403a0d3003c12c8f45636", "0xacdfa6fdd4a5acb7738cc8768f7cba84dbb95c639399b291ae8e4e63df37d2d4096900a84d2f0606bf534a9ccaa4993f", "0x86ee253f3a9446a33e4d1169719b7d513c6b50730988415382faaf751988c10a421020609f7bcdef91be136704b906e2", "0xaac9438382a856caf84c5a8a234282f71b5fc5f65219103b147e7e6cf565522285fbfd7417b513bdad8277a00f652ca1", "0x83f3799d8e5772527930f5dc071a2e0a65471618993ec8990a96ccdeee65270e490bda9d26bb877612475268711ffd80", "0x93f28a81ac8c0ec9450b9d762fae9c7f8feaace87a6ee6bd141ef1d2d0697ef1bbd159fe6e1de640dbdab2b0361fca8a", "0xa0825c95ba69999b90eac3a31a3fd830ea4f4b2b7409bde5f202b61d741d6326852ce790f41de5cb0eccec7af4db30c1", "0x83924b0e66233edd603c3b813d698daa05751fc34367120e3cf384ea7432e256ccee4d4daf13858950549d75a377107d", "0x956fd9fa58345277e06ba2ec72f49ed230b8d3d4ff658555c52d6cddeb84dd4e36f1a614f5242d5ca0192e8daf0543c2", "0x944869912476baae0b114cced4ff65c0e4c90136f73ece5656460626599051b78802df67d7201c55d52725a97f5f29fe", "0x865cb25b64b4531fb6fe4814d7c8cd26b017a6c6b72232ff53defc18a80fe3b39511b23f9e4c6c7249d06e03b2282ed2", "0x81e09ff55214960775e1e7f2758b9a6c4e4cd39edf7ec1adfaad51c52141182b79fe2176b23ddc7df9fd153e5f82d668", "0xb31006896f02bc90641121083f43c3172b1039334501fbaf1672f7bf5d174ddd185f945adf1a9c6cf77be34c5501483d", "0x88b92f6f42ae45e9f05b16e52852826e933efd0c68b0f2418ac90957fd018df661bc47c8d43c2a7d7bfcf669dab98c3c", "0x92fc68f595853ee8683930751789b799f397135d002eda244fe63ecef2754e15849edde3ba2f0cc8b865c9777230b712", "0x99ca06a49c5cd0bb097c447793fcdd809869b216a34c66c78c7e41e8c22f05d09168d46b8b1f3390db9452d91bc96dea", "0xb48b9490a5d65296802431852d548d81047bbefc74fa7dc1d4e2a2878faacdfcb365ae59209cb0ade01901a283cbd15d", "0xaff0fdbef7c188b120a02bc9085d7b808e88f73973773fef54707bf2cd772cd066740b1b6f4127b5c349f657bd97e738", "0x966fd4463b4f43dd8ccba7ad50baa42292f9f8b2e70da23bb6780e14155d9346e275ef03ddaf79e47020dcf43f3738bd", "0x9330c3e1fadd9e08ac85f4839121ae20bbeb0a5103d84fa5aadbd1213805bdcda67bf2fb75fc301349cbc851b5559d20", "0x993bb99867bd9041a71a55ad5d397755cfa7ab6a4618fc526179bfc10b7dc8b26e4372fe9a9b4a15d64f2b63c1052dda", "0xa29b59bcfab51f9b3c490a3b96f0bf1934265c315349b236012adbd64a56d7f6941b2c8cc272b412044bc7731f71e1dc", "0xa65c9cefe1fc35d089fe8580c2e7671ebefdb43014ac291528ff4deefd4883fd4df274af83711dad610dad0d615f9d65", "0x944c78c56fb227ae632805d448ca3884cd3d2a89181cead3d2b7835e63297e6d740aa79a112edb1d4727824991636df5", "0xa73d782da1db7e4e65d7b26717a76e16dd9fab4df65063310b8e917dc0bc24e0d6755df5546c58504d04d9e68c3b474a", "0xaf80f0b87811ae3124f68108b4ca1937009403f87928bbc53480e7c5408d072053ace5eeaf5a5aba814dab8a45502085", "0x88aaf1acfc6e2e19b8387c97da707cb171c69812fefdd4650468e9b2c627bd5ccfb459f4d8e56bdfd84b09ddf87e128f", "0x92c97276ff6f72bab6e9423d02ad6dc127962dbce15a0dd1e4a393b4510c555df6aa27be0f697c0d847033a9ca8b8dfd", "0xa0e07d43d96e2d85b6276b3c60aadb48f0aedf2de8c415756dc597249ea64d2093731d8735231dadc961e5682ac59479", "0xadc9e6718a8f9298957d1da3842a7751c5399bbdf56f8de6c1c4bc39428f4aee6f1ba6613d37bf46b9403345e9d6fc81", "0x951da434da4b20d949b509ceeba02e24da7ed2da964c2fcdf426ec787779c696b385822c7dbea4df3e4a35921f1e912c", "0xa04cbce0d2b2e87bbf038c798a12ec828423ca6aca08dc8d481cf6466e3c9c73d4d4a7fa47df9a7e2e15aae9e9f67208", "0x8f855cca2e440d248121c0469de1f94c2a71b8ee2682bbad3a78243a9e03da31d1925e6760dbc48a1957e040fae9abe8", "0xb642e5b17c1df4a4e101772d73851180b3a92e9e8b26c918050f51e6dd3592f102d20b0a1e96f0e25752c292f4c903ff", "0xa92454c300781f8ae1766dbbb50a96192da7d48ef4cbdd72dd8cbb44c6eb5913c112cc38e9144615fdc03684deb99420", "0x8b74f7e6c2304f8e780df4649ef8221795dfe85fdbdaa477a1542d135b75c8be45bf89adbbb6f3ddf54ca40f02e733e9", "0x85cf66292cbb30cec5fd835ab10c9fcb3aea95e093aebf123e9a83c26f322d76ebc89c4e914524f6c5f6ee7d74fc917d", "0xae0bfe0cdc97c09542a7431820015f2d16067b30dca56288013876025e81daa8c519e5e347268e19aa1a85fa1dc28793", "0x921322fc6a47dc091afa0ad6df18ed14cde38e48c6e71550aa513918b056044983aee402de21051235eecf4ce8040fbe", "0x96c030381e97050a45a318d307dcb3c8377b79b4dd5daf6337cded114de26eb725c14171b9b8e1b3c08fe1f5ea6b49e0", "0x90c23b86b6111818c8baaf53a13eaee1c89203b50e7f9a994bf0edf851919b48edbac7ceef14ac9414cf70c486174a77", "0x8bf6c301240d2d1c8d84c71d33a6dfc6d9e8f1cfae66d4d0f7a256d98ae12b0bcebfa94a667735ee89f810bcd7170cff", "0xa41a4ffbbea0e36874d65c009ee4c3feffff322f6fc0e30d26ee4dbc1f46040d05e25d9d0ecb378cef0d24a7c2c4b850", "0xa8d4cdd423986bb392a0a92c12a8bd4da3437eec6ef6af34cf5310944899287452a2eb92eb5386086d5063381189d10e", "0xa81dd26ec057c4032a4ed7ad54d926165273ed51d09a1267b2e477535cf6966835a257c209e4e92d165d74fa75695fa3", "0x8d7f708c3ee8449515d94fc26b547303b53d8dd55f177bc3b25d3da2768accd9bc8e9f09546090ebb7f15c66e6c9c723", "0x839ba65cffcd24cfffa7ab3b21faabe3c66d4c06324f07b2729c92f15cad34e474b0f0ddb16cd652870b26a756b731d3", "0x87f1a3968afec354d92d77e2726b702847c6afcabb8438634f9c6f7766de4c1504317dc4fa9a4a735acdbf985e119564", "0x91a8a7fd6542f3e0673f07f510d850864b34ac087eb7eef8845a1d14b2b1b651cbdc27fa4049bdbf3fea54221c5c8549", "0xaef3cf5f5e3a2385ead115728d7059e622146c3457d266c612e778324b6e06fbfb8f98e076624d2f3ce1035d65389a07", "0x819915d6232e95ccd7693fdd78d00492299b1983bc8f96a08dcb50f9c0a813ed93ae53c0238345d5bea0beda2855a913", "0x8e9ba68ded0e94935131b392b28218315a185f63bf5e3c1a9a9dd470944509ca0ba8f6122265f8da851b5cc2abce68f1", "0xb28468e9b04ee9d69003399a3cf4457c9bf9d59f36ab6ceeb8e964672433d06b58beeea198fedc7edbaa1948577e9fa2", "0xa633005e2c9f2fd94c8bce2dd5bb708fe946b25f1ec561ae65e54e15cdd88dc339f1a083e01f0d39610c8fe24151aaf0", "0x841d0031e22723f9328dd993805abd13e0c99b0f59435d2426246996b08d00ce73ab906f66c4eab423473b409e972ce0", "0x85758d1b084263992070ec8943f33073a2d9b86a8606672550c17545507a5b3c88d87382b41916a87ee96ff55a7aa535", "0x8581b06b0fc41466ef94a76a1d9fb8ae0edca6d018063acf6a8ca5f4b02d76021902feba58972415691b4bdbc33ae3b4", "0x83539597ff5e327357ee62bc6bf8c0bcaec2f227c55c7c385a4806f0d37fb461f1690bad5066b8a5370950af32fafbef", "0xaee3557290d2dc10827e4791d00e0259006911f3f3fce4179ed3c514b779160613eca70f720bff7804752715a1266ffa", "0xb48d2f0c4e90fc307d5995464e3f611a9b0ef5fe426a289071f4168ed5cc4f8770c9332960c2ca5c8c427f40e6bb389f", "0x847af8973b4e300bb06be69b71b96183fd1a0b9d51b91701bef6fcfde465068f1eb2b1503b07afda380f18d69de5c9e1", "0xa70a6a80ce407f07804c0051ac21dc24d794b387be94eb24e1db94b58a78e1bcfb48cd0006db8fc1f9bedaece7a44fbe", "0xb40e942b8fa5336910ff0098347df716bff9d1fa236a1950c16eeb966b3bc1a50b8f7b0980469d42e75ae13ced53cead", "0xb208fabaa742d7db3148515330eb7a3577487845abdb7bd9ed169d0e081db0a5816595c33d375e56aeac5b51e60e49d3", "0xb7c8194b30d3d6ef5ab66ec88ad7ebbc732a3b8a41731b153e6f63759a93f3f4a537eab9ad369705bd730184bdbbdc34", "0x9280096445fe7394d04aa1bc4620c8f9296e991cc4d6c131bd703cb1cc317510e6e5855ac763f4d958c5edfe7eebeed7", "0xabc2aa4616a521400af1a12440dc544e3c821313d0ab936c86af28468ef8bbe534837e364598396a81cf8d06274ed5a6", "0xb18ca8a3325adb0c8c18a666d4859535397a1c3fe08f95eebfac916a7a99bbd40b3c37b919e8a8ae91da38bc00fa56c0", "0x8a40c33109ecea2a8b3558565877082f79121a432c45ec2c5a5e0ec4d1c203a6788e6b69cb37f1fd5b8c9a661bc5476d", "0x88c47301dd30998e903c84e0b0f2c9af2e1ce6b9f187dab03528d44f834dc991e4c86d0c474a2c63468cf4020a1e24a0", "0x920c832853e6ab4c851eecfa9c11d3acc7da37c823be7aa1ab15e14dfd8beb5d0b91d62a30cec94763bd8e4594b66600", "0x98e1addbe2a6b8edc7f12ecb9be81c3250aeeca54a1c6a7225772ca66549827c15f3950d01b8eb44aecb56fe0fff901a", "0x8cfb0fa1068be0ec088402f5950c4679a2eb9218c729da67050b0d1b2d7079f3ddf4bf0f57d95fe2a8db04bc6bcdb20c", "0xb70f381aafe336b024120453813aeab70baac85b9c4c0f86918797b6aee206e6ed93244a49950f3d8ec9f81f4ac15808", "0xa4c8edf4aa33b709a91e1062939512419711c1757084e46f8f4b7ed64f8e682f4e78b7135920c12f0eb0422fe9f87a6a", "0xb4817e85fd0752d7ebb662d3a51a03367a84bac74ebddfba0e5af5e636a979500f72b148052d333b3dedf9edd2b4031b", "0xa87430169c6195f5d3e314ff2d1c2f050e766fd5d2de88f5207d72dba4a7745bb86d0baca6e9ae156582d0d89e5838c7", "0x991b00f8b104566b63a12af4826b61ce7aa40f4e5b8fff3085e7a99815bdb4471b6214da1e480214fac83f86a0b93cc5", "0xb39966e3076482079de0678477df98578377a094054960ee518ef99504d6851f8bcd3203e8da5e1d4f6f96776e1fe6eb", "0xa448846d9dc2ab7a0995fa44b8527e27f6b3b74c6e03e95edb64e6baa4f1b866103f0addb97c84bef1d72487b2e21796", "0x894bec21a453ae84b592286e696c35bc30e820e9c2fd3e63dd4fbe629e07df16439c891056070faa490155f255bf7187", "0xa9ec652a491b11f6a692064e955f3f3287e7d2764527e58938571469a1e29b5225b9415bd602a45074dfbfe9c131d6ca", "0xb39d37822e6cbe28244b5f42ce467c65a23765bd16eb6447c5b3e942278069793763483dafd8c4dd864f8917aad357fe", "0x88dba51133f2019cb266641c56101e3e5987d3b77647a2e608b5ff9113dfc5f85e2b7c365118723131fbc0c9ca833c9c", "0xb566579d904b54ecf798018efcb824dccbebfc6753a0fd2128ac3b4bd3b038c2284a7c782b5ca6f310eb7ea4d26a3f0a", "0xa97a55c0a492e53c047e7d6f9d5f3e86fb96f3dddc68389c0561515343b66b4bc02a9c0d5722dff1e3445308240b27f7", "0xa044028ab4bcb9e1a2b9b4ca4efbf04c5da9e4bf2fff0e8bd57aa1fc12a71e897999c25d9117413faf2f45395dee0f13", "0xa78dc461decbeaeed8ebd0909369b491a5e764d6a5645a7dac61d3140d7dc0062526f777b0eb866bff27608429ebbdde", "0xb2c2a8991f94c39ca35fea59f01a92cb3393e0eccb2476dfbf57261d406a68bd34a6cff33ed80209991688c183609ef4", "0x84189eefb521aff730a4fd3fd5b10ddfd29f0d365664caef63bb015d07e689989e54c33c2141dd64427805d37a7e546e", "0x85ac80bd734a52235da288ff042dea9a62e085928954e8eacd2c751013f61904ed110e5b3afe1ab770a7e6485efb7b5e", "0x9183a560393dcb22d0d5063e71182020d0fbabb39e32493eeffeb808df084aa243eb397027f150b55a247d1ed0c8513e", "0x81c940944df7ecc58d3c43c34996852c3c7915ed185d7654627f7af62abae7e0048dd444a6c09961756455000bd96d09", "0xaa8c34e164019743fd8284b84f06c3b449aae7996e892f419ee55d82ad548cb300fd651de329da0384243954c0ef6a60", "0x89a7b7bdfc7e300d06a14d463e573d6296d8e66197491900cc9ae49504c4809ff6e61b758579e9091c61085ba1237b83", "0x878d21809ba540f50bd11f4c4d9590fb6f3ab9de5692606e6e2ef4ed9d18520119e385be5e1f4b3f2e2b09c319f0e8fc", "0x8eb248390193189cf0355365e630b782cd15751e672dc478b39d75dc681234dcd9309df0d11f4610dbb249c1e6be7ef9", "0xa1d7fb3aecb896df3a52d6bd0943838b13f1bd039c936d76d03de2044c371d48865694b6f532393b27fd10a4cf642061", "0xa34bca58a24979be442238cbb5ece5bee51ae8c0794dd3efb3983d4db713bc6f28a96e976ac3bd9a551d3ed9ba6b3e22", "0x817c608fc8cacdd178665320b5a7587ca21df8bdd761833c3018b967575d25e3951cf3d498a63619a3cd2ad4406f5f28", "0x86c95707db0495689afd0c2e39e97f445f7ca0edffad5c8b4cacd1421f2f3cc55049dfd504f728f91534e20383955582", "0x99c3b0bb15942c301137765d4e19502f65806f3b126dc01a5b7820c87e8979bce6a37289a8f6a4c1e4637227ad5bf3bf", "0x8aa1518a80ea8b074505a9b3f96829f5d4afa55a30efe7b4de4e5dbf666897fdd2cf31728ca45921e21a78a80f0e0f10", "0x8d74f46361c79e15128ac399e958a91067ef4cec8983408775a87eca1eed5b7dcbf0ddf30e66f51780457413496c7f07", "0xa41cde4a786b55387458a1db95171aca4fd146507b81c4da1e6d6e495527c3ec83fc42fad1dfe3d92744084a664fd431", "0x8c352852c906fae99413a84ad11701f93f292fbf7bd14738814f4c4ceab32db02feb5eb70bc73898b0bc724a39d5d017", "0xa5993046e8f23b71ba87b7caa7ace2d9023fb48ce4c51838813174880d918e9b4d2b0dc21a2b9c6f612338c31a289df8", "0x83576d3324bf2d8afbfb6eaecdc5d767c8e22e7d25160414924f0645491df60541948a05e1f4202e612368e78675de8a", "0xb43749b8df4b15bc9a3697e0f1c518e6b04114171739ef1a0c9c65185d8ec18e40e6954d125cbc14ebc652cf41ad3109", "0xb4eebd5d80a7327a040cafb9ccdb12b2dfe1aa86e6bc6d3ac8a57fadfb95a5b1a7332c66318ff72ba459f525668af056", "0x9198be7f1d413c5029b0e1c617bcbc082d21abe2c60ec8ce9b54ca1a85d3dba637b72fda39dae0c0ae40d047eab9f55a", "0x8d96a0232832e24d45092653e781e7a9c9520766c3989e67bbe86b3a820c4bf621ea911e7cd5270a4bfea78b618411f6", "0x8d7160d0ea98161a2d14d46ef01dff72d566c330cd4fabd27654d300e1bc7644c68dc8eabf2a20a59bfe7ba276545f9b", "0xabb60fce29dec7ba37e3056e412e0ec3e05538a1fc0e2c68877378c867605966108bc5742585ab6a405ce0c962b285b6", "0x8fabffa3ed792f05e414f5839386f6449fd9f7b41a47595c5d71074bd1bb3784cc7a1a7e1ad6b041b455035957e5b2dc", "0x90ff017b4804c2d0533b72461436b10603ab13a55f86fd4ec11b06a70ef8166f958c110519ca1b4cc7beba440729fe2d", "0xb340cfd120f6a4623e3a74cf8c32bfd7cd61a280b59dfd17b15ca8fae4d82f64a6f15fbde4c02f424debc72b7db5fe67", "0x871311c9c7220c932e738d59f0ecc67a34356d1429fe570ca503d340c9996cb5ee2cd188fad0e3bd16e4c468ec1dbebd", "0xa772470262186e7b94239ba921b29f2412c148d6f97c4412e96d21e55f3be73f992f1ad53c71008f0558ec3f84e2b5a7", "0xb2a897dcb7ffd6257f3f2947ec966f2077d57d5191a88840b1d4f67effebe8c436641be85524d0a21be734c63ab5965d", "0xa044f6eacc48a4a061fa149500d96b48cbf14853469aa4d045faf3dca973be1bd4b4ce01646d83e2f24f7c486d03205d", "0x981af5dc2daa73f7fa9eae35a93d81eb6edba4a7f673b55d41f6ecd87a37685d31bb40ef4f1c469b3d72f2f18b925a17", "0x912d2597a07864de9020ac77083eff2f15ceb07600f15755aba61251e8ce3c905a758453b417f04d9c38db040954eb65", "0x9642b7f6f09394ba5e0805734ef6702c3eddf9eea187ba98c676d5bbaec0e360e3e51dc58433aaa1e2da6060c8659cb7", "0x8ab3836e0a8ac492d5e707d056310c4c8e0489ca85eb771bff35ba1d658360084e836a6f51bb990f9e3d2d9aeb18fbb5", "0x879e058e72b73bb1f4642c21ffdb90544b846868139c6511f299aafe59c2d0f0b944dffc7990491b7c4edcd6a9889250", "0xb9e60b737023f61479a4a8fd253ed0d2a944ea6ba0439bbc0a0d3abf09b0ad1f18d75555e4a50405470ae4990626f390", "0xb9c2535d362796dcd673640a9fa2ebdaec274e6f8b850b023153b0a7a30fffc87f96e0b72696f647ebe7ab63099a6963", "0x94aeff145386a087b0e91e68a84a5ede01f978f9dd9fe7bebca78941938469495dc30a96bba9508c0d017873aeea9610", "0x98b179f8a3d9f0d0a983c30682dd425a2ddc7803be59bd626c623c8951a5179117d1d2a68254c95c9952989877d0ee55", "0x889ecf5f0ee56938273f74eb3e9ecfb5617f04fb58e83fe4c0e4aef51615cf345bc56f3f61b17f6eed3249d4afd54451", "0xa0f2b2c39bcea4b50883e2587d16559e246248a66ecb4a4b7d9ab3b51fb39fe98d83765e087eee37a0f86b0ba4144c02", "0xb2a61e247ed595e8a3830f7973b07079cbda510f28ad8c78c220b26cb6acde4fbb5ee90c14a665f329168ee951b08cf0", "0x95bd0fcfb42f0d6d8a8e73d7458498a85bcddd2fb132fd7989265648d82ac2707d6d203fac045504977af4f0a2aca4b7", "0x843e5a537c298666e6cf50fcc044f13506499ef83c802e719ff2c90e85003c132024e04711be7234c04d4b0125512d5d", "0xa46d1797c5959dcd3a5cfc857488f4d96f74277c3d13b98b133620192f79944abcb3a361d939a100187f1b0856eae875", "0xa1c7786736d6707a48515c38660615fcec67eb8a2598f46657855215f804fd72ab122d17f94fcffad8893f3be658dca7", "0xb23dc9e610abc7d8bd21d147e22509a0fa49db5be6ea7057b51aae38e31654b3aa044df05b94b718153361371ba2f622", "0xb00cc8f257d659c22d30e6d641f79166b1e752ea8606f558e4cad6fc01532e8319ea4ee12265ba4140ac45aa4613c004", "0xac7019af65221b0cc736287b32d7f1a3561405715ba9a6a122342e04e51637ba911c41573de53e4781f2230fdcb2475f", "0x81a630bc41b3da8b3eb4bf56cba10cd9f93153c3667f009dc332287baeb707d505fb537e6233c8e53d299ec0f013290c", "0xa6b7aea5c545bb76df0f230548539db92bc26642572cb7dd3d5a30edca2b4c386f44fc8466f056b42de2a452b81aff5b", "0x8271624ff736b7b238e43943c81de80a1612207d32036d820c11fc830c737972ccc9c60d3c2359922b06652311e3c994", "0x8a684106458cb6f4db478170b9ad595d4b54c18bf63b9058f095a2fa1b928c15101472c70c648873d5887880059ed402", "0xa5cc3c35228122f410184e4326cf61a37637206e589fcd245cb5d0cec91031f8f7586b80503070840fdfd8ce75d3c88b", "0x9443fc631aed8866a7ed220890911057a1f56b0afe0ba15f0a0e295ab97f604b134b1ed9a4245e46ee5f9a93aa74f731", "0x984b6f7d79835dffde9558c6bb912d992ca1180a2361757bdba4a7b69dc74b056e303adc69fe67414495dd9c2dd91e64", "0xb15a5c8cba5de080224c274d31c68ed72d2a7126d347796569aef0c4e97ed084afe3da4d4b590b9dda1a07f0c2ff3dfb", "0x991708fe9650a1f9a4e43938b91d45dc68c230e05ee999c95dbff3bf79b1c1b2bb0e7977de454237c355a73b8438b1d9", "0xb4f7edc7468b176a4a7c0273700c444fa95c726af6697028bed4f77eee887e3400f9c42ee15b782c0ca861c4c3b8c98a", "0x8c60dcc16c51087eb477c13e837031d6c6a3dc2b8bf8cb43c23f48006bc7173151807e866ead2234b460c2de93b31956", "0x83ad63e9c910d1fc44bc114accfb0d4d333b7ebe032f73f62d25d3e172c029d5e34a1c9d547273bf6c0fead5c8801007", "0x85de73213cc236f00777560756bdbf2b16841ba4b55902cf2cad9742ecaf5d28209b012ceb41f337456dfeca93010cd7", "0xa7561f8827ccd75b6686ba5398bb8fc3083351c55a589b18984e186820af7e275af04bcd4c28e1dc11be1e8617a0610b", "0x88c0a4febd4068850557f497ea888035c7fc9f404f6cc7794e7cc8722f048ad2f249e7dc62743e7a339eb7473ad3b0cd", "0x932b22b1d3e6d5a6409c34980d176feb85ada1bf94332ef5c9fc4d42b907dabea608ceef9b5595ef3feee195151f18d8", "0xa2867bb3f5ab88fbdae3a16c9143ab8a8f4f476a2643c505bb9f37e5b1fd34d216cab2204c9a017a5a67b7ad2dda10e8", "0xb573d5f38e4e9e8a3a6fd82f0880dc049efa492a946d00283019bf1d5e5516464cf87039e80aef667cb86fdea5075904", "0xb948f1b5ab755f3f5f36af27d94f503b070696d793b1240c1bdfd2e8e56890d69e6904688b5f8ff5a4bdf5a6abfe195f", "0x917eae95ebc4109a2e99ddd8fec7881d2f7aaa0e25fda44dec7ce37458c2ee832f1829db7d2dcfa4ca0f06381c7fe91d", "0x95751d17ed00a3030bce909333799bb7f4ab641acf585807f355b51d6976dceee410798026a1a004ef4dcdff7ec0f5b8", "0xb9b7bd266f449a79bbfe075e429613e76c5a42ac61f01c8f0bbbd34669650682efe01ff9dbbc400a1e995616af6aa278", "0xac1722d097ce9cd7617161f8ec8c23d68f1fb1c9ca533e2a8b4f78516c2fd8fb38f23f834e2b9a03bb06a9d655693ca9", "0xa7ad9e96ffd98db2ecdb6340c5d592614f3c159abfd832fe27ee9293519d213a578e6246aae51672ee353e3296858873", "0x989b8814d5de7937c4acafd000eec2b4cd58ba395d7b25f98cafd021e8efa37029b29ad8303a1f6867923f5852a220eb", "0xa5bfe6282c771bc9e453e964042d44eff4098decacb89aecd3be662ea5b74506e1357ab26f3527110ba377711f3c9f41", "0x8900a7470b656639721d2abbb7b06af0ac4222ab85a1976386e2a62eb4b88bfb5b72cf7921ddb3cf3a395d7eeb192a2e", "0x95a71b55cd1f35a438cf5e75f8ff11c5ec6a2ebf2e4dba172f50bfad7d6d5dca5de1b1afc541662c81c858f7604c1163", "0x82b5d62fea8db8d85c5bc3a76d68dedd25794cf14d4a7bc368938ffca9e09f7e598fdad2a5aac614e0e52f8112ae62b9", "0x997173f07c729202afcde3028fa7f52cefc90fda2d0c8ac2b58154a5073140683e54c49ed1f254481070d119ce0ce02a", "0xaeffb91ccc7a72bbd6ffe0f9b99c9e66e67d59cec2e02440465e9636a613ab3017278cfa72ea8bc4aba9a8dc728cb367", "0x952743b06e8645894aeb6440fc7a5f62dd3acf96dab70a51e20176762c9751ea5f2ba0b9497ccf0114dc4892dc606031", "0x874c63baeddc56fbbca2ff6031f8634b745f6e34ea6791d7c439201aee8f08ef5ee75f7778700a647f3b21068513fce6", "0x85128fec9c750c1071edfb15586435cc2f317e3e9a175bb8a9697bcda1eb9375478cf25d01e7fed113483b28f625122d", "0x85522c9576fd9763e32af8495ae3928ed7116fb70d4378448926bc9790e8a8d08f98cf47648d7da1b6e40d6a210c7924", "0x97d0f37a13cfb723b848099ca1c14d83e9aaf2f7aeb71829180e664b7968632a08f6a85f557d74b55afe6242f2a36e7c", "0xabaa472d6ad61a5fccd1a57c01aa1bc081253f95abbcba7f73923f1f11c4e79b904263890eeb66926de3e2652f5d1c70", "0xb3c04945ba727a141e5e8aec2bf9aa3772b64d8fd0e2a2b07f3a91106a95cbcb249adcd074cbe498caf76fffac20d4ef", "0x82c46781a3d730d9931bcabd7434a9171372dde57171b6180e5516d4e68db8b23495c8ac3ab96994c17ddb1cf249b9fb", "0xa202d8b65613c42d01738ccd68ed8c2dbc021631f602d53f751966e04182743ebc8e0747d600b8a8676b1da9ae7f11ab", "0xae73e7256e9459db04667a899e0d3ea5255211fb486d084e6550b6dd64ca44af6c6b2d59d7aa152de9f96ce9b58d940d", "0xb67d87b176a9722945ec7593777ee461809861c6cfd1b945dde9ee4ff009ca4f19cf88f4bbb5c80c9cbab2fe25b23ac8", "0x8f0b7a317a076758b0dac79959ee4a06c08b07d0f10538a4b53d3da2eda16e2af26922feb32c090330dc4d969cf69bd3", "0x90b36bf56adbd8c4b6cb32febc3a8d5f714370c2ac3305c10fa6d168dffb2a026804517215f9a2d4ec8310cdb6bb459b", "0xaa80c19b0682ead69934bf18cf476291a0beddd8ef4ed75975d0a472e2ab5c70f119722a8574ae4973aceb733d312e57", "0xa3fc9abb12574e5c28dcb51750b4339b794b8e558675eef7d26126edf1de920c35e992333bcbffcbf6a5f5c0d383ce62", "0xa1573ff23ab972acdcd08818853b111fc757fdd35aa070186d3e11e56b172fb49d840bf297ac0dd222e072fc09f26a81", "0x98306f2be4caa92c2b4392212d0cbf430b409b19ff7d5b899986613bd0e762c909fc01999aa94be3bd529d67f0113d7f", "0x8c1fc42482a0819074241746d17dc89c0304a2acdae8ed91b5009e9e3e70ff725ba063b4a3e68fdce05b74f5180c545e", "0xa6c6113ebf72d8cf3163b2b8d7f3fa24303b13f55752522c660a98cd834d85d8c79214d900fa649499365e2e7641f77a", "0xab95eea424f8a2cfd9fb1c78bb724e5b1d71a0d0d1e4217c5d0f98b0d8bbd3f8400a2002abc0a0e4576d1f93f46fefad", "0x823c5a4fd8cf4a75fdc71d5f2dd511b6c0f189b82affeacd2b7cfcad8ad1a5551227dcc9bfdb2e34b2097eaa00efbb51", "0xb97314dfff36d80c46b53d87a61b0e124dc94018a0bb680c32765b9a2d457f833a7c42bbc90b3b1520c33a182580398d", "0xb17566ee3dcc6bb3b004afe4c0136dfe7dd27df9045ae896dca49fb36987501ae069eb745af81ba3fc19ff037e7b1406", "0xb0bdc0f55cfd98d331e3a0c4fbb776a131936c3c47c6bffdc3aaf7d8c9fa6803fbc122c2fefbb532e634228687d52174", "0xaa5d9e60cc9f0598559c28bb9bdd52aa46605ab4ffe3d192ba982398e72cec9a2a44c0d0d938ce69935693cabc0887ea", "0x802b6459d2354fa1d56c592ac1346c428dadea6b6c0a87bf7d309bab55c94e1cf31dd98a7a86bd92a840dd51f218b91b", "0xa526914efdc190381bf1a73dd33f392ecf01350b9d3f4ae96b1b1c3d1d064721c7d6eec5788162c933245a3943f5ee51", "0xb3b8fcf637d8d6628620a1a99dbe619eabb3e5c7ce930d6efd2197e261bf394b74d4e5c26b96c4b8009c7e523ccfd082", "0x8f7510c732502a93e095aba744535f3928f893f188adc5b16008385fb9e80f695d0435bfc5b91cdad4537e87e9d2551c", "0x97b90beaa56aa936c3ca45698f79273a68dd3ccd0076eab48d2a4db01782665e63f33c25751c1f2e070f4d1a8525bf96", "0xb9fb798324b1d1283fdc3e48288e3861a5449b2ab5e884b34ebb8f740225324af86e4711da6b5cc8361c1db15466602f", "0xb6d52b53cea98f1d1d4c9a759c25bf9d8a50b604b144e4912acbdbdc32aab8b9dbb10d64a29aa33a4f502121a6fb481c", "0x9174ffff0f2930fc228f0e539f5cfd82c9368d26b074467f39c07a774367ff6cccb5039ac63f107677d77706cd431680", "0xa33b6250d4ac9e66ec51c063d1a6a31f253eb29bbaed12a0d67e2eccfffb0f3a52750fbf52a1c2aaba8c7692346426e7", "0xa97025fd5cbcebe8ef865afc39cd3ea707b89d4e765ec817fd021d6438e02fa51e3544b1fd45470c58007a08efac6edd", "0xb32a78480edd9ff6ba2f1eec4088db5d6ceb2d62d7e59e904ecaef7bb4a2e983a4588e51692b3be76e6ffbc0b5f911a5", "0xb5ab590ef0bb77191f00495b33d11c53c65a819f7d0c1f9dc4a2caa147a69c77a4fff7366a602d743ee1f395ce934c1e", "0xb3fb0842f9441fb1d0ee0293b6efbc70a8f58d12d6f769b12872db726b19e16f0f65efbc891cf27a28a248b0ef9c7e75", "0x9372ad12856fefb928ccb0d34e198df99e2f8973b07e9d417a3134d5f69e12e79ff572c4e03ccd65415d70639bc7c73e", "0xaa8d6e83d09ce216bfe2009a6b07d0110d98cf305364d5529c170a23e693aabb768b2016befb5ada8dabdd92b4d012bb", "0xa954a75791eeb0ce41c85200c3763a508ed8214b5945a42c79bfdcfb1ec4f86ad1dd7b2862474a368d4ac31911a2b718", "0x8e2081cfd1d062fe3ab4dab01f68062bac802795545fede9a188f6c9f802cb5f884e60dbe866710baadbf55dc77c11a4", "0xa2f06003b9713e7dd5929501ed485436b49d43de80ea5b15170763fd6346badf8da6de8261828913ee0dacd8ff23c0e1", "0x98eecc34b838e6ffd1931ca65eec27bcdb2fdcb61f33e7e5673a93028c5865e0d1bf6d3bec040c5e96f9bd08089a53a4", "0x88cc16019741b341060b95498747db4377100d2a5bf0a5f516f7dec71b62bcb6e779de2c269c946d39040e03b3ae12b7", "0xad1135ccbc3019d5b2faf59a688eef2500697642be8cfbdf211a1ab59abcc1f24483e50d653b55ff1834675ac7b4978f", "0xa946f05ed9972f71dfde0020bbb086020fa35b482cce8a4cc36dd94355b2d10497d7f2580541bb3e81b71ac8bba3c49f", "0xa83aeed488f9a19d8cfd743aa9aa1982ab3723560b1cd337fc2f91ad82f07afa412b3993afb845f68d47e91ba4869840", "0x95eebe006bfc316810cb71da919e5d62c2cebb4ac99d8e8ef67be420302320465f8b69873470982de13a7c2e23516be9", "0xa55f8961295a11e91d1e5deadc0c06c15dacbfc67f04ccba1d069cba89d72aa3b3d64045579c3ea8991b150ac29366ae", "0xb321991d12f6ac07a5de3c492841d1a27b0d3446082fbce93e7e1f9e8d8fe3b45d41253556261c21b70f5e189e1a7a6f", "0xa0b0822f15f652ce7962a4f130104b97bf9529797c13d6bd8e24701c213cc37f18157bd07f3d0f3eae6b7cd1cb40401f", "0x96e2fa4da378aa782cc2d5e6e465fc9e49b5c805ed01d560e9b98abb5c0de8b74a2e7bec3aa5e2887d25cccb12c66f0c", "0x97e4ab610d414f9210ed6f35300285eb3ccff5b0b6a95ed33425100d7725e159708ea78704497624ca0a2dcabce3a2f9", "0x960a375b17bdb325761e01e88a3ea57026b2393e1d887b34b8fa5d2532928079ce88dc9fd06a728b26d2bb41b12b9032", "0x8328a1647398e832aadc05bd717487a2b6fcdaa0d4850d2c4da230c6a2ed44c3e78ec4837b6094f3813f1ee99414713f", "0xaa283834ebd18e6c99229ce4b401eda83f01d904f250fedd4e24f1006f8fa0712a6a89a7296a9bf2ce8de30e28d1408e", "0xb29e097f2caadae3e0f0ae3473c072b0cd0206cf6d2e9b22c1a5ad3e07d433e32bd09ed1f4e4276a2da4268633357b7f", "0x9539c5cbba14538b2fe077ecf67694ef240da5249950baaabea0340718b882a966f66d97f08556b08a4320ceb2cc2629", "0xb4529f25e9b42ae8cf8338d2eface6ba5cd4b4d8da73af502d081388135c654c0b3afb3aa779ffc80b8c4c8f4425dd2b", "0x95be0739c4330619fbe7ee2249c133c91d6c07eab846c18c5d6c85fc21ac5528c5d56dcb0145af68ed0c6a79f68f2ccd", "0xac0c83ea802227bfc23814a24655c9ff13f729619bcffdb487ccbbf029b8eaee709f8bddb98232ef33cd70e30e45ca47", "0xb503becb90acc93b1901e939059f93e671900ca52c6f64ae701d11ac891d3a050b505d89324ce267bc43ab8275da6ffe", "0x98e3811b55b1bacb70aa409100abb1b870f67e6d059475d9f278c751b6e1e2e2d6f2e586c81a9fb6597fda06e7923274", "0xb0b0f61a44053fa6c715dbb0731e35d48dba257d134f851ee1b81fd49a5c51a90ebf5459ec6e489fce25da4f184fbdb1", "0xb1d2117fe811720bb997c7c93fe9e4260dc50fca8881b245b5e34f724aaf37ed970cdad4e8fcb68e05ac8cf55a274a53", "0xa10f502051968f14b02895393271776dee7a06db9de14effa0b3471825ba94c3f805302bdddac4d397d08456f620999d", "0xa3dbad2ef060ae0bb7b02eaa4a13594f3f900450faa1854fc09620b01ac94ab896321dfb1157cf2374c27e5718e8026a", "0xb550fdec503195ecb9e079dcdf0cad559d64d3c30818ef369b4907e813e689da316a74ad2422e391b4a8c2a2bef25fc0", "0xa25ba865e2ac8f28186cea497294c8649a201732ecb4620c4e77b8e887403119910423df061117e5f03fc5ba39042db1", "0xb3f88174e03fdb443dd6addd01303cf88a4369352520187c739fc5ae6b22fa99629c63c985b4383219dab6acc5f6f532", "0x97a7503248e31e81b10eb621ba8f5210c537ad11b539c96dfb7cf72b846c7fe81bd7532c5136095652a9618000b7f8d3", "0xa8bcdc1ce5aa8bfa683a2fc65c1e79de8ff5446695dcb8620f7350c26d2972a23da22889f9e2b1cacb3f688c6a2953dc", "0x8458c111df2a37f5dd91a9bee6c6f4b79f4f161c93fe78075b24a35f9817da8dde71763218d627917a9f1f0c4709c1ed", "0xac5f061a0541152b876cbc10640f26f1cc923c9d4ae1b6621e4bb3bf2cec59bbf87363a4eb72fb0e5b6d4e1c269b52d5", "0xa9a25ca87006e8a9203cbb78a93f50a36694aa4aad468b8d80d3feff9194455ca559fcc63838128a0ab75ad78c07c13a", "0xa450b85f5dfffa8b34dfd8bc985f921318efacf8857cf7948f93884ba09fb831482ee90a44224b1a41e859e19b74962f", "0x8ed91e7f92f5c6d7a71708b6132f157ac226ecaf8662af7d7468a4fa25627302efe31e4620ad28719318923e3a59bf82", "0xab524165fd4c71b1fd395467a14272bd2b568592deafa039d8492e9ef36c6d3f96927c95c72d410a768dc0b6d1fbbc9b", "0xb662144505aa8432c75ffb8d10318526b6d5777ac7af9ebfad87d9b0866c364f7905a6352743bd8fd79ffd9d5dd4f3e6", "0xa48f1677550a5cd40663bb3ba8f84caaf8454f332d0ceb1d94dbea52d0412fe69c94997f7749929712fd3995298572f7", "0x8391cd6e2f6b0c242de1117a612be99776c3dc95cb800b187685ea5bf7e2722275eddb79fd7dfc8be8e389c4524cdf70", "0x875d3acb9af47833b72900bc0a2448999d638f153c5e97e8a14ec02d0c76f6264353a7e275e1f1a5855daced523d243b", "0x91f1823657d30b59b2f627880a9a9cb530f5aca28a9fd217fe6f2f5133690dfe7ad5a897872e400512db2e788b3f7628", "0xad3564332aa56cea84123fc7ca79ea70bb4fef2009fa131cb44e4b15e8613bd11ca1d83b9d9bf456e4b7fee9f2e8b017", "0x8c530b84001936d5ab366c84c0b105241a26d1fb163669f17c8f2e94776895c2870edf3e1bc8ccd04d5e65531471f695", "0x932d01fa174fdb0c366f1230cffde2571cc47485f37f23ba5a1825532190cc3b722aeb1f15aed62cf83ccae9403ba713", "0x88b28c20585aca50d10752e84b901b5c2d58efef5131479fbbe53de7bce2029e1423a494c0298e1497669bd55be97a5d", "0xb914148ca717721144ebb3d3bf3fcea2cd44c30c5f7051b89d8001502f3856fef30ec167174d5b76265b55d70f8716b5", "0x81d0173821c6ddd2a068d70766d9103d1ee961c475156e0cbd67d54e668a796310474ef698c7ab55abe6f2cf76c14679", "0x8f28e8d78e2fe7fa66340c53718e0db4b84823c8cfb159c76eac032a62fb53da0a5d7e24ca656cf9d2a890cb2a216542", "0x8a26360335c73d1ab51cec3166c3cf23b9ea51e44a0ad631b0b0329ef55aaae555420348a544e18d5760969281759b61", "0x94f326a32ed287545b0515be9e08149eb0a565025074796d72387cc3a237e87979776410d78339e23ef3172ca43b2544", "0xa785d2961a2fa5e70bffa137858a92c48fe749fee91b02599a252b0cd50d311991a08efd7fa5e96b78d07e6e66ffe746", "0x94af9030b5ac792dd1ce517eaadcec1482206848bea4e09e55cc7f40fd64d4c2b3e9197027c5636b70d6122c51d2235d", "0x9722869f7d1a3992850fe7be405ec93aa17dc4d35e9e257d2e469f46d2c5a59dbd504056c85ab83d541ad8c13e8bcd54", "0xb13c4088b61a06e2c03ac9813a75ff1f68ffdfee9df6a8f65095179a475e29cc49119cad2ce05862c3b1ac217f3aace9", "0x8c64d51774753623666b10ca1b0fe63ae42f82ed6aa26b81dc1d48c86937c5772eb1402624c52a154b86031854e1fb9f", "0xb47e4df18002b7dac3fee945bf9c0503159e1b8aafcce2138818e140753011b6d09ef1b20894e08ba3006b093559061b", "0x93cb5970076522c5a0483693f6a35ffd4ea2aa7aaf3730c4eccd6af6d1bebfc1122fc4c67d53898ae13eb6db647be7e2", "0xa68873ef80986795ea5ed1a597d1cd99ed978ec25e0abb57fdcc96e89ef0f50aeb779ff46e3dce21dc83ada3157a8498", "0x8cab67f50949cc8eee6710e27358aea373aae3c92849f8f0b5531c080a6300cdf2c2094fe6fecfef6148de0d28446919", "0x993e932bcb616dbaa7ad18a4439e0565211d31071ef1b85a0627db74a05d978c60d507695eaeea5c7bd9868a21d06923", "0xacdadff26e3132d9478a818ef770e9fa0d2b56c6f5f48bd3bd674436ccce9bdfc34db884a73a30c04c5f5e9764cb2218", "0xa0d3e64c9c71f84c0eef9d7a9cb4fa184224b969db5514d678e93e00f98b41595588ca802643ea225512a4a272f5f534", "0x91c9140c9e1ba6e330cb08f6b2ce4809cd0d5a0f0516f70032bf30e912b0ed684d07b413b326ab531ee7e5b4668c799b", "0x87bc2ee7a0c21ba8334cd098e35cb703f9af57f35e091b8151b9b63c3a5b0f89bd7701dbd44f644ea475901fa6d9ef08", "0x9325ccbf64bf5d71b303e31ee85d486298f9802c5e55b2c3d75427097bf8f60fa2ab4fcaffa9b60bf922c3e24fbd4b19", "0x95d0506e898318f3dc8d28d16dfd9f0038b54798838b3c9be2a2ae3c2bf204eb496166353fc042220b0bd4f6673b9285", "0x811de529416331fe9c416726d45df9434c29dcd7e949045eb15740f47e97dde8f31489242200e19922cac2a8b7c6fd1f", "0xade632d04a4c8bbab6ca7df370b2213cb9225023e7973f0e29f4f5e52e8aeaabc65171306bbdd12a67b195dfbb96d48f", "0x88b7f029e079b6ae956042c0ea75d53088c5d0efd750dd018adaeacf46be21bf990897c58578c491f41afd3978d08073", "0x91f477802de507ffd2be3f4319903119225b277ad24f74eb50f28b66c14d32fae53c7edb8c7590704741af7f7f3e3654", "0x809838b32bb4f4d0237e98108320d4b079ee16ed80c567e7548bd37e4d7915b1192880f4812ac0e00476d246aec1dbc8", "0x84183b5fc4a7997a8ae5afedb4d21dce69c480d5966b5cbdafd6dd10d29a9a6377f3b90ce44da0eb8b176ac3af0253bb", "0x8508abbf6d3739a16b9165caf0f95afb3b3ac1b8c38d6d374cf0c91296e2c1809a99772492b539cda184510bce8a0271", "0x8722054e59bab2062e6419a6e45fc803af77fde912ef2cd23055ad0484963de65a816a2debe1693d93c18218d2b8e81a", "0x8e895f80e485a7c4f56827bf53d34b956281cdc74856c21eb3b51f6288c01cc3d08565a11cc6f3e2604775885490e8c5", "0xafc92714771b7aa6e60f3aee12efd9c2595e9659797452f0c1e99519f67c8bc3ac567119c1ddfe82a3e961ee9defea9a", "0x818ff0fd9cefd32db87b259e5fa32967201016fc02ef44116cdca3c63ce5e637756f60477a408709928444a8ad69c471", "0x8251e29af4c61ae806fc5d032347fb332a94d472038149225298389495139ce5678fae739d02dfe53a231598a992e728", "0xa0ea39574b26643f6f1f48f99f276a8a64b5481989cfb2936f9432a3f8ef5075abfe5c067dc5512143ce8bf933984097", "0xaf67a73911b372bf04e57e21f289fc6c3dfac366c6a01409b6e76fea4769bdb07a6940e52e8d7d3078f235c6d2f632c6", "0xb5291484ef336024dd2b9b4cf4d3a6b751133a40656d0a0825bcc6d41c21b1c79cb50b0e8f4693f90c29c8f4358641f9", "0x8bc0d9754d70f2cb9c63f991902165a87c6535a763d5eece43143b5064ae0bcdce7c7a8f398f2c1c29167b2d5a3e6867", "0x8d7faff53579ec8f6c92f661c399614cc35276971752ce0623270f88be937c414eddcb0997e14724a783905a026c8883", "0x9310b5f6e675fdf60796f814dbaa5a6e7e9029a61c395761e330d9348a7efab992e4e115c8be3a43d08e90d21290c892", "0xb5eb4f3eb646038ad2a020f0a42202532d4932e766da82b2c1002bf9c9c2e5336b54c8c0ffcc0e02d19dde2e6a35b6cc", "0x91dabfd30a66710f1f37a891136c9be1e23af4abf8cb751f512a40c022a35f8e0a4fb05b17ec36d4208de02d56f0d53a", "0xb3ded14e82d62ac7a5a036122a62f00ff8308498f3feae57d861babaff5a6628d43f0a0c5fc903f10936bcf4e2758ceb", "0xa88e8348fed2b26acca6784d19ef27c75963450d99651d11a950ea81d4b93acd2c43e0ecce100eaf7e78508263d5baf3", "0xb1f5bbf7c4756877b87bb42163ac570e08c6667c4528bf68b5976680e19beeff7c5effd17009b0718797077e2955457a", "0xad2e7b516243f915d4d1415326e98b1a7390ae88897d0b03b66c2d9bd8c3fba283d7e8fe44ed3333296a736454cef6d8", "0x8f82eae096d5b11f995de6724a9af895f5e1c58d593845ad16ce8fcae8507e0d8e2b2348a0f50a1f66a17fd6fac51a5c", "0x890e4404d0657c6c1ee14e1aac132ecf7a568bb3e04137b85ac0f84f1d333bd94993e8750f88eee033a33fb00f85dcc7", "0x82ac7d3385e035115f1d39a99fc73e5919de44f5e6424579776d118d711c8120b8e5916372c6f27bed4cc64cac170b6c", "0x85ee16d8901c272cfbbe966e724b7a891c1bd5e68efd5d863043ad8520fc409080af61fd726adc680b3f1186fe0ac8b8", "0x86dc564c9b545567483b43a38f24c41c6551a49cabeebb58ce86404662a12dbfafd0778d30d26e1c93ce222e547e3898", "0xa29f5b4522db26d88f5f95f18d459f8feefab02e380c2edb65aa0617a82a3c1a89474727a951cef5f15050bcf7b380fb", "0xa1ce039c8f6cac53352899edb0e3a72c76da143564ad1a44858bd7ee88552e2fe6858d1593bbd74aeee5a6f8034b9b9d", "0x97f10d77983f088286bd7ef3e7fdd8fa275a56bec19919adf33cf939a90c8f2967d2b1b6fc51195cb45ad561202a3ed7", "0xa25e2772e8c911aaf8712bdac1dd40ee061c84d3d224c466cfaae8e5c99604053f940cde259bd1c3b8b69595781dbfec", "0xb31bb95a0388595149409c48781174c340960d59032ab2b47689911d03c68f77a2273576fbe0c2bf4553e330656058c7", "0xb8b2e9287ad803fb185a13f0d7456b397d4e3c8ad5078f57f49e8beb2e85f661356a3392dbd7bcf6a900baa5582b86a1", "0xa3d0893923455eb6e96cc414341cac33d2dbc88fba821ac672708cce131761d85a0e08286663a32828244febfcae6451", "0x82310cb42f647d99a136014a9f881eb0b9791efd2e01fc1841907ad3fc8a9654d3d1dab6689c3607214b4dc2aca01cee", "0x874022d99c16f60c22de1b094532a0bc6d4de700ad01a31798fac1d5088b9a42ad02bef8a7339af7ed9c0d4f16b186ee", "0x94981369e120265aed40910eebc37eded481e90f4596b8d57c3bec790ab7f929784bd33ddd05b7870aad6c02e869603b", "0xa4f1f50e1e2a73f07095e0dd31cb45154f24968dae967e38962341c1241bcd473102fff1ff668b20c6547e9732d11701", "0xae2328f3b0ad79fcda807e69a1b5278145225083f150f67511dafc97e079f860c3392675f1752ae7e864c056e592205b", "0x875d8c971e593ca79552c43d55c8c73b17cd20c81ff2c2fed1eb19b1b91e4a3a83d32df150dbfd5db1092d0aebde1e1f", "0xadd2e80aa46aae95da73a11f130f4bda339db028e24c9b11e5316e75ba5e63bc991d2a1da172c7c8e8fee038baae3433", "0xb46dbe1cb3424002aa7de51e82f600852248e251465c440695d52538d3f36828ff46c90ed77fc1d11534fe3c487df8ef", "0xa5e5045d28b4e83d0055863c30c056628c58d4657e6176fd0536f5933f723d60e851bb726d5bf3c546b8ce4ac4a57ef8", "0x91fec01e86dd1537e498fff7536ea3ca012058b145f29d9ada49370cd7b7193ac380e116989515df1b94b74a55c45df3", "0xa7428176d6918cd916a310bdc75483c72de660df48cac4e6e7478eef03205f1827ea55afc0df5d5fa7567d14bbea7fc9", "0x851d89bef45d9761fe5fdb62972209335193610015e16a675149519f9911373bac0919add226ef118d9f3669cfdf4734", "0xb74acf5c149d0042021cb2422ea022be4c4f72a77855f42393e71ffd12ebb3eec16bdf16f812159b67b79a9706e7156d", "0x99f35dce64ec99aa595e7894b55ce7b5a435851b396e79036ffb249c28206087db4c85379df666c4d95857db02e21ff9", "0xb6b9a384f70db9e298415b8ab394ee625dafff04be2886476e59df8d052ca832d11ac68a9b93fba7ab055b7bc36948a4", "0x898ee4aefa923ffec9e79f2219c7389663eb11eb5b49014e04ed4a336399f6ea1691051d86991f4c46ca65bcd4fdf359", "0xb0f948217b0d65df7599a0ba4654a5e43c84db477936276e6f11c8981efc6eaf14c90d3650107ed4c09af4cc8ec11137", "0xaa6286e27ac54f73e63dbf6f41865dd94d24bc0cf732262fcaff67319d162bb43af909f6f8ee27b1971939cfbba08141", "0x8bca7cdf730cf56c7b2c8a2c4879d61361a6e1dba5a3681a1a16c17a56e168ace0e99cf0d15826a1f5e67e6b8a8a049a", "0xa746d876e8b1ce225fcafca603b099b36504846961526589af977a88c60d31ba2cc56e66a3dec8a77b3f3531bf7524c9", "0xa11e2e1927e6704cdb8874c75e4f1842cef84d7d43d7a38e339e61dc8ba90e61bbb20dd3c12e0b11d2471d58eed245be", "0xa36395e22bc1d1ba8b0459a235203177737397da5643ce54ded3459d0869ff6d8d89f50c73cb62394bf66a959cde9b90", "0x8b49f12ba2fdf9aca7e5f81d45c07d47f9302a2655610e7634d1e4bd16048381a45ef2c95a8dd5b0715e4b7cf42273af", "0x91cffa2a17e64eb7f76bccbe4e87280ee1dd244e04a3c9eac12e15d2d04845d876eb24fe2ec6d6d266cce9efb281077f", "0xa6b8afabf65f2dee01788114e33a2f3ce25376fb47a50b74da7c3c25ff1fdc8aa9f41307534abbf48acb6f7466068f69", "0x8d13db896ccfea403bd6441191995c1a65365cab7d0b97fbe9526da3f45a877bd1f4ef2edef160e8a56838cd1586330e", "0x98c717de9e01bef8842c162a5e757fe8552d53269c84862f4d451e7c656ae6f2ae473767b04290b134773f63be6fdb9d", "0x8c2036ace1920bd13cf018e82848c49eb511fad65fd0ff51f4e4b50cf3bfc294afb63cba682c16f52fb595a98fa84970", "0xa3520fdff05dbad9e12551b0896922e375f9e5589368bcb2cc303bde252743b74460cb5caf99629325d3620f13adc796", "0x8d4f83a5bfec05caf5910e0ce538ee9816ee18d0bd44c1d0da2a87715a23cd2733ad4d47552c6dc0eb397687d611dd19", "0xa7b39a0a6a02823452d376533f39d35029867b3c9a6ad6bca181f18c54132d675613a700f9db2440fb1b4fa13c8bf18a", "0x80bcb114b2544b80f404a200fc36860ed5e1ad31fe551acd4661d09730c452831751baa9b19d7d311600d267086a70bc", "0x90dcce03c6f88fc2b08f2b42771eedde90cc5330fe0336e46c1a7d1b5a6c1641e5fcc4e7b3d5db00bd8afca9ec66ed81", "0xaec15f40805065c98e2965b1ae12a6c9020cfdb094c2d0549acfc7ea2401a5fb48d3ea7d41133cf37c4e096e7ff53eb9", "0x80e129b735dba49fa627a615d6c273119acec8e219b2f2c4373a332b5f98d66cbbdd688dfbe72a8f8bfefaccc02c50c1", "0xa9b596da3bdfe23e6799ece5f7975bf7a1979a75f4f546deeaf8b34dfe3e0d623217cb4cf4ccd504cfa3625b88cd53f1", "0xabcbbb70b16f6e517c0ab4363ab76b46e4ff58576b5f8340e5c0e8cc0e02621b6e23d742d73b015822a238b17cfd7665", "0xa046937cc6ea6a2e1adae543353a9fe929c1ae4ad655be1cc051378482cf88b041e28b1e9a577e6ccff2d3570f55e200", "0x831279437282f315e65a60184ef158f0a3dddc15a648dc552bdc88b3e6fe8288d3cfe9f0031846d81350f5e7874b4b33", "0x993d7916fa213c6d66e7c4cafafc1eaec9a2a86981f91c31eb8a69c5df076c789cbf498a24c84e0ee77af95b42145026", "0x823907a3b6719f8d49b3a4b7c181bd9bb29fcf842d7c70660c4f351852a1e197ca46cf5e879b47fa55f616fa2b87ce5e", "0x8d228244e26132b234930ee14c75d88df0943cdb9c276a8faf167d259b7efc1beec2a87c112a6c608ad1600a239e9aae", "0xab6e55766e5bfb0cf0764ed909a8473ab5047d3388b4f46faeba2d1425c4754c55c6daf6ad4751e634c618b53e549529", "0xab0cab6860e55a84c5ad2948a7e0989e2b4b1fd637605634b118361497332df32d9549cb854b2327ca54f2bcb85eed8f", "0xb086b349ae03ef34f4b25a57bcaa5d1b29bd94f9ebf87e22be475adfe475c51a1230c1ebe13506cb72c4186192451658", "0x8a0b49d8a254ca6d91500f449cbbfbb69bb516c6948ac06808c65595e46773e346f97a5ce0ef7e5a5e0de278af22709c", "0xac49de11edaaf04302c73c578cc0824bdd165c0d6321be1c421c1950e68e4f3589aa3995448c9699e93c6ebae8803e27", "0x884f02d841cb5d8f4c60d1402469216b114ab4e93550b5bc1431756e365c4f870a9853449285384a6fa49e12ce6dc654", "0xb75f3a28fa2cc8d36b49130cb7448a23d73a7311d0185ba803ad55c8219741d451c110f48b786e96c728bc525903a54f", "0x80ae04dbd41f4a35e33f9de413b6ad518af0919e5a30cb0fa1b061b260420780bb674f828d37fd3b52b5a31673cbd803", "0xb9a8011eb5fcea766907029bf743b45262db3e49d24f84503687e838651ed11cb64c66281e20a0ae9f6aa51acc552263", "0x90bfdd75e2dc9cf013e22a5d55d2d2b8a754c96103a17524488e01206e67f8b6d52b1be8c4e3d5307d4fe06d0e51f54c", "0xb4af353a19b06203a815ec43e79a88578cc678c46f5a954b85bc5c53b84059dddba731f3d463c23bfd5273885c7c56a4", "0xaa125e96d4553b64f7140e5453ff5d2330318b69d74d37d283e84c26ad672fa00e3f71e530eb7e28be1e94afb9c4612e", "0xa18e060aee3d49cde2389b10888696436bb7949a79ca7d728be6456a356ea5541b55492b2138da90108bd1ce0e6f5524", "0x93e55f92bdbccc2de655d14b1526836ea2e52dba65eb3f87823dd458a4cb5079bf22ce6ef625cb6d6bfdd0995ab9a874", "0x89f5a683526b90c1c3ceebbb8dc824b21cff851ce3531b164f6626e326d98b27d3e1d50982e507d84a99b1e04e86a915", "0x83d1c38800361633a3f742b1cb2bfc528129496e80232611682ddbe403e92c2ac5373aea0bca93ecb5128b0b2b7a719e", "0x8ecba560ac94905e19ce8d9c7af217bf0a145d8c8bd38e2db82f5e94cc3f2f26f55819176376b51f154b4aab22056059", "0xa7e2a4a002b60291924850642e703232994acb4cfb90f07c94d1e0ecd2257bb583443283c20fc6017c37e6bfe85b7366", "0x93ed7316fa50b528f1636fc6507683a672f4f4403e55e94663f91221cc198199595bd02eef43d609f451acc9d9b36a24", "0xa1220a8ebc5c50ceed76a74bc3b7e0aa77f6884c71b64b67c4310ac29ce5526cb8992d6abc13ef6c8413ce62486a6795", "0xb2f6eac5c869ad7f4a25161d3347093e2f70e66cd925032747e901189355022fab3038bca4d610d2f68feb7e719c110b", "0xb703fa11a4d511ca01c7462979a94acb40b5d933759199af42670eb48f83df202fa0c943f6ab3b4e1cc54673ea3aab1e", "0xb5422912afbfcb901f84791b04f1ddb3c3fbdc76d961ee2a00c5c320e06d3cc5b5909c3bb805df66c5f10c47a292b13d", "0xad0934368da823302e1ac08e3ede74b05dfdbfffca203e97ffb0282c226814b65c142e6e15ec1e754518f221f01b30f7", "0xa1dd302a02e37df15bf2f1147efe0e3c06933a5a767d2d030e1132f5c3ce6b98e216b6145eb39e1e2f74e76a83165b8d", "0xa346aab07564432f802ae44738049a36f7ca4056df2d8f110dbe7fef4a3e047684dea609b2d03dc6bf917c9c2a47608f", "0xb96c5f682a5f5d02123568e50f5d0d186e4b2c4c9b956ec7aabac1b3e4a766d78d19bd111adb5176b898e916e49be2aa", "0x8a96676d56876fc85538db2e806e1cba20fd01aeb9fa3cb43ca6ca94a2c102639f65660db330e5d74a029bb72d6a0b39", "0xab0048336bd5c3def1a4064eadd49e66480c1f2abb4df46e03afbd8a3342c2c9d74ee35d79f08f4768c1646681440984", "0x888427bdf76caec90814c57ee1c3210a97d107dd88f7256f14f883ad0f392334b82be11e36dd8bfec2b37935177c7831", "0xb622b282becf0094a1916fa658429a5292ba30fb48a4c8066ce1ddcefb71037948262a01c95bab6929ed3a76ba5db9fe", "0xb5b9e005c1f456b6a368a3097634fb455723abe95433a186e8278dceb79d4ca2fbe21f8002e80027b3c531e5bf494629", "0xa3c6707117a1e48697ed41062897f55d8119403eea6c2ee88f60180f6526f45172664bfee96bf61d6ec0b7fbae6aa058", "0xb02a9567386a4fbbdb772d8a27057b0be210447348efe6feb935ceec81f361ed2c0c211e54787dc617cdffed6b4a6652", "0xa9b8364e40ef15c3b5902e5534998997b8493064fa2bea99600def58279bb0f64574c09ba11e9f6f669a8354dd79dc85", "0x9998a2e553a9aa9a206518fae2bc8b90329ee59ab23005b10972712389f2ec0ee746033c733092ffe43d73d33abbb8ef", "0x843a4b34d9039bf79df96d79f2d15e8d755affb4d83d61872daf540b68c0a3888cf8fc00d5b8b247b38524bcb3b5a856", "0x84f7128920c1b0bb40eee95701d30e6fc3a83b7bb3709f16d97e72acbb6057004ee7ac8e8f575936ca9dcb7866ab45f7", "0x918d3e2222e10e05edb34728162a899ad5ada0aaa491aeb7c81572a9c0d506e31d5390e1803a91ff3bd8e2bb15d47f31", "0x9442d18e2489613a7d47bb1cb803c8d6f3259d088cd079460976d87f7905ee07dea8f371b2537f6e1d792d36d7e42723", "0xb491976970fe091995b2ed86d629126523ccf3e9daf8145302faca71b5a71a5da92e0e05b62d7139d3efac5c4e367584", "0xaa628006235dc77c14cef4c04a308d66b07ac92d377df3de1a2e6ecfe3144f2219ad6d7795e671e1cb37a3641910b940", "0x99d386adaea5d4981d7306feecac9a555b74ffdc218c907c5aa7ac04abaead0ec2a8237300d42a3fbc464673e417ceed", "0x8f78e8b1556f9d739648ea3cab9606f8328b52877fe72f9305545a73b74d49884044ba9c1f1c6db7d9b7c7b7c661caba", "0x8fb357ae49932d0babdf74fc7aa7464a65d3b6a2b3acf4f550b99601d3c0215900cfd67f2b6651ef94cfc323bac79fae", "0x9906f2fa25c0290775aa001fb6198113d53804262454ae8b83ef371b5271bde189c0460a645829cb6c59f9ee3a55ce4d", "0x8f4379b3ebb50e052325b27655ca6a82e6f00b87bf0d2b680d205dd2c7afdc9ff32a9047ae71a1cdf0d0ce6b9474d878", "0xa85534e88c2bd43c043792eaa75e50914b21741a566635e0e107ae857aed0412035f7576cf04488ade16fd3f35fdbb87", "0xb4ce93199966d3c23251ca7f28ec5af7efea1763d376b0385352ffb2e0a462ef95c69940950278cf0e3dafd638b7bd36", "0xb10cb3d0317dd570aa73129f4acf63c256816f007607c19b423fb42f65133ce21f2f517e0afb41a5378cccf893ae14d0", "0xa9b231c9f739f7f914e5d943ed9bff7eba9e2c333fbd7c34eb1648a362ee01a01af6e2f7c35c9fe962b11152cddf35de", "0x99ff6a899e156732937fb81c0cced80ae13d2d44c40ba99ac183aa246103b31ec084594b1b7feb96da58f4be2dd5c0ed", "0x8748d15d18b75ff2596f50d6a9c4ce82f61ecbcee123a6ceae0e43cab3012a29b6f83cf67b48c22f6f9d757c6caf76b2", "0xb88ab05e4248b7fb634cf640a4e6a945d13e331237410f7217d3d17e3e384ddd48897e7a91e4516f1b9cbd30f35f238b", "0x8d826deaeeb84a3b2d2c04c2300ca592501f992810582d6ae993e0d52f6283a839dba66c6c72278cff5871802b71173b", "0xb36fed027c2f05a5ef625ca00b0364b930901e9e4420975b111858d0941f60e205546474bb25d6bfa6928d37305ae95f", "0xaf2fcfc6b87967567e8b8a13a4ed914478185705724e56ce68fb2df6d1576a0cf34a61e880997a0d35dc2c3276ff7501", "0xac351b919cd1fbf106feb8af2c67692bfcddc84762d18cea681cfa7470a5644839caace27efee5f38c87d3df306f4211", "0x8d6665fb1d4d8d1fa23bd9b8a86e043b8555663519caac214d1e3e3effbc6bee7f2bcf21e645f77de0ced279d69a8a8b", "0xa9fc1c2061756b2a1a169c1b149f212ff7f0d2488acd1c5a0197eba793cffa593fc6d1d1b40718aa75ca3ec77eff10e1", "0xaff64f0fa009c7a6cf0b8d7a22ddb2c8170c3cb3eec082e60d5aadb00b0040443be8936d728d99581e33c22178c41c87", "0x82e0b181adc5e3b1c87ff8598447260e839d53debfae941ebea38265575546c3a74a14b4325a030833a62ff6c52d9365", "0xb7ad43cbb22f6f892c2a1548a41dc120ab1f4e1b8dea0cb6272dd9cb02054c542ecabc582f7e16de709d48f5166cae86", "0x985e0c61094281532c4afb788ecb2dfcba998e974b5d4257a22040a161883908cdd068fe80f8eb49b8953cfd11acf43a", "0xae46895c6d67ea6d469b6c9c07b9e5d295d9ae73b22e30da4ba2c973ba83a130d7eef39717ec9d0f36e81d56bf742671", "0x8600177ea1f7e7ef90514b38b219a37dedfc39cb83297e4c7a5b479817ef56479d48cf6314820960c751183f6edf8b0e", "0xb9208ec1c1d7a1e99b59c62d3e4e61dfb706b0e940d09d3abfc3454c19749083260614d89cfd7e822596c3cdbcc6bb95", "0xa1e94042c796c2b48bc724352d2e9f3a22291d9a34705993357ddb6adabd76da6fc25dac200a8cb0b5bbd99ecddb7af6", "0xb29c3adedd0bcad8a930625bc4dfdc3552a9afd5ca6dd9c0d758f978068c7982b50b711aa0eb5b97f2b84ee784637835", "0xaf0632a238bb1f413c7ea8e9b4c3d68f2827bd2e38cd56024391fba6446ac5d19a780d0cfd4a78fe497d537b766a591a", "0xaaf6e7f7d54f8ef5e2e45dd59774ecbeecf8683aa70483b2a75be6a6071b5981bbaf1627512a65d212817acdfab2e428", "0x8c751496065da2e927cf492aa5ca9013b24f861d5e6c24b30bbf52ec5aaf1905f40f9a28175faef283dd4ed4f2182a09", "0x8952377d8e80a85cf67d6b45499f3bad5fd452ea7bcd99efc1b066c4720d8e5bff1214cea90fd1f972a7f0baac3d29be", "0xa1946ee543d1a6e21f380453be4d446e4130950c5fc3d075794eb8260f6f52d0a795c1ff91d028a648dc1ce7d9ab6b47", "0x89f3fefe37af31e0c17533d2ca1ce0884cc1dc97c15cbfab9c331b8debd94781c9396abef4bb2f163d09277a08d6adf0", "0xa2753f1e6e1a154fb117100a5bd9052137add85961f8158830ac20541ab12227d83887d10acf7fd36dcaf7c2596d8d23", "0x814955b4198933ee11c3883863b06ff98c7eceb21fc3e09df5f916107827ccf3323141983e74b025f46ae00284c9513b", "0x8cc5c6bb429073bfef47cae7b3bfccb0ffa076514d91a1862c6bda4d581e0df87db53cc6c130bf8a7826304960f5a34e", "0x909f22c1f1cdc87f7be7439c831a73484a49acbf8f23d47087d7cf867c64ef61da3bde85dc57d705682b4c3fc710d36e", "0x8048fee7f276fcd504aed91284f28e73693615e0eb3858fa44bcf79d7285a9001c373b3ef71d9a3054817ba293ebe28c", "0x94400e5cf5d2700ca608c5fe35ce14623f71cc24959f2bc27ca3684092850f76b67fb1f07ca9e5b2ca3062cf8ad17bd4", "0x81c2ae7d4d1b17f8b6de6a0430acc0d58260993980fe48dc2129c4948269cdc74f9dbfbf9c26b19360823fd913083d48", "0x8c41fe765128e63f6889d6a979f6a4342300327c8b245a8cfe3ecfbcac1e09c3da30e2a1045b24b78efc6d6d50c8c6ac", "0xa5dd4ae51ae48c8be4b218c312ade226cffce671cf121cb77810f6c0990768d6dd767badecb5c69921d5574d5e8433d3", "0xb7642e325f4ba97ae2a39c1c9d97b35aafd49d53dba36aed3f3cb0ca816480b3394079f46a48252d46596559c90f4d58", "0xae87375b40f35519e7bd4b1b2f73cd0b329b0c2cb9d616629342a71c6c304338445eda069b78ea0fbe44087f3de91e09", "0xb08918cb6f736855e11d3daca1ddfbdd61c9589b203b5493143227bf48e2c77c2e8c94b0d1aa2fab2226e0eae83f2681", "0xac36b84a4ac2ebd4d6591923a449c564e3be8a664c46092c09e875c2998eba16b5d32bfd0882fd3851762868e669f0b1", "0xa44800a3bb192066fa17a3f29029a23697240467053b5aa49b9839fb9b9b8b12bcdcbfc557f024b61f4f51a9aacdefcb", "0x9064c688fec23441a274cdf2075e5a449caf5c7363cc5e8a5dc9747183d2e00a0c69f2e6b3f6a7057079c46014c93b3b", "0xaa367b021469af9f5b764a79bb3afbe2d87fe1e51862221672d1a66f954b165778b7c27a705e0f93841fab4c8468344d", "0xa1a8bfc593d4ab71f91640bc824de5c1380ab2591cfdafcbc78a14b32de3c0e15f9d1b461d85c504baa3d4232c16bb53", "0x97df48da1799430f528184d30b6baa90c2a2f88f34cdfb342d715339c5ebd6d019aa693cea7c4993daafc9849063a3aa", "0xabd923831fbb427e06e0dd335253178a9e5791395c84d0ab1433c07c53c1209161097e9582fb8736f8a60bde62d8693e", "0x84cd1a43f1a438b43dc60ffc775f646937c4f6871438163905a3cebf1115f814ccd38a6ccb134130bff226306e412f32", "0x91426065996b0743c5f689eb3ca68a9f7b9e4d01f6c5a2652b57fa9a03d8dc7cd4bdbdab0ca5a891fee1e97a7f00cf02", "0xa4bee50249db3df7fd75162b28f04e57c678ba142ce4d3def2bc17bcb29e4670284a45f218dad3969af466c62a903757", "0x83141ebcc94d4681404e8b67a12a46374fded6df92b506aff3490d875919631408b369823a08b271d006d5b93136f317", "0xa0ea1c8883d58d5a784da3d8c8a880061adea796d7505c1f903d07c287c5467f71e4563fc0faafbc15b5a5538b0a7559", "0x89d9d480574f201a87269d26fb114278ed2c446328df431dc3556e3500e80e4cd01fcac196a2459d8646361ebda840df", "0x8bf302978973632dd464bec819bdb91304712a3ec859be071e662040620422c6e75eba6f864f764cffa2799272efec39", "0x922f666bc0fd58b6d7d815c0ae4f66d193d32fc8382c631037f59eeaeae9a8ca6c72d08e72944cf9e800b8d639094e77", "0x81ad8714f491cdff7fe4399f2eb20e32650cff2999dd45b9b3d996d54a4aba24cc6c451212e78c9e5550368a1a38fb3f", "0xb58fcf4659d73edb73175bd9139d18254e94c3e32031b5d4b026f2ed37aa19dca17ec2eb54c14340231615277a9d347e", "0xb365ac9c2bfe409b710928c646ea2fb15b28557e0f089d39878e365589b9d1c34baf5566d20bb28b33bb60fa133f6eff", "0x8fcae1d75b53ab470be805f39630d204853ca1629a14158bac2f52632277d77458dec204ff84b7b2d77e641c2045be65", "0xa03efa6bebe84f4f958a56e2d76b5ba4f95dd9ed7eb479edc7cc5e646c8d4792e5b0dfc66cc86aa4b4afe2f7a4850760", "0xaf1c823930a3638975fb0cc5c59651771b2719119c3cd08404fbd4ce77a74d708cefbe3c56ea08c48f5f10e6907f338f", "0x8260c8299b17898032c761c325ac9cabb4c5b7e735de81eacf244f647a45fb385012f4f8df743128888c29aefcaaad16", "0xab2f37a573c82e96a8d46198691cd694dfa860615625f477e41f91b879bc58a745784fccd8ffa13065834ffd150d881d", "0x986c746c9b4249352d8e5c629e8d7d05e716b3c7aab5e529ca969dd1e984a14b5be41528baef4c85d2369a42d7209216", "0xb25e32da1a8adddf2a6080725818b75bc67240728ad1853d90738485d8924ea1e202df0a3034a60ffae6f965ec55cf63", "0xa266e627afcebcefea6b6b44cbc50f5c508f7187e87d047b0450871c2a030042c9e376f3ede0afcf9d1952f089582f71", "0x86c3bbca4c0300606071c0a80dbdec21ce1dd4d8d4309648151c420854032dff1241a1677d1cd5de4e4de4385efda986", "0xb9a21a1fe2d1f3273a8e4a9185abf2ff86448cc98bfa435e3d68306a2b8b4a6a3ea33a155be3cb62a2170a86f77679a5", "0xb117b1ea381adce87d8b342cba3a15d492ff2d644afa28f22424cb9cbc820d4f7693dfc1a4d1b3697046c300e1c9b4c8", "0x9004c425a2e68870d6c69b658c344e3aa3a86a8914ee08d72b2f95c2e2d8a4c7bb0c6e7e271460c0e637cec11117bf8e", "0x86a18aa4783b9ebd9131580c8b17994825f27f4ac427b0929a1e0236907732a1c8139e98112c605488ee95f48bbefbfc", "0x84042243b955286482ab6f0b5df4c2d73571ada00716d2f737ca05a0d2e88c6349e8ee9e67934cfee4a1775dbf7f4800", "0x92c2153a4733a62e4e1d5b60369f3c26777c7d01cd3c8679212660d572bd3bac9b8a8a64e1f10f7dbf5eaa7579c4e423", "0x918454b6bb8e44a2afa144695ba8d48ae08d0cdfef4ad078f67709eddf3bb31191e8b006f04e82ea45a54715ef4d5817", "0xacf0b54f6bf34cf6ed6c2b39cf43194a40d68de6bcf1e4b82c34c15a1343e9ac3737885e1a30b78d01fa3a5125463db8", "0xa7d60dbe4b6a7b054f7afe9ee5cbbfeca0d05dc619e6041fa2296b549322529faddb8a11e949562309aecefb842ac380", "0x91ffb53e6d7e5f11159eaf13e783d6dbdfdb1698ed1e6dbf3413c6ea23492bbb9e0932230a9e2caac8fe899a17682795", "0xb6e8d7be5076ee3565d5765a710c5ecf17921dd3cf555c375d01e958a365ae087d4a88da492a5fb81838b7b92bf01143", "0xa8c6b763de2d4b2ed42102ef64eccfef31e2fb2a8a2776241c82912fa50fc9f77f175b6d109a97ede331307c016a4b1a", "0x99839f86cb700c297c58bc33e28d46b92931961548deac29ba8df91d3e11721b10ea956c8e16984f9e4acf1298a79b37", "0x8c2e2c338f25ea5c25756b7131cde0d9a2b35abf5d90781180a00fe4b8e64e62590dc63fe10a57fba3a31c76d784eb01", "0x9687d7df2f41319ca5469d91978fed0565a5f11f829ebadaa83db92b221755f76c6eacd7700735e75c91e257087512e3", "0x8795fdfb7ff8439c58b9bf58ed53873d2780d3939b902b9ddaaa4c99447224ced9206c3039a23c2c44bcc461e2bb637f", "0xa803697b744d2d087f4e2307218d48fa88620cf25529db9ce71e2e3bbcc65bac5e8bb9be04777ef7bfb5ed1a5b8e6170", "0x80f3d3efbbb9346ddd413f0a8e36b269eb5d7ff6809d5525ff9a47c4bcab2c01b70018b117f6fe05253775612ff70c6b", "0x9050e0e45bcc83930d4c505af35e5e4d7ca01cd8681cba92eb55821aececcebe32bb692ebe1a4daac4e7472975671067", "0x8d206812aac42742dbaf233e0c080b3d1b30943b54b60283515da005de05ea5caa90f91fedcfcba72e922f64d7040189", "0xa2d44faaeb2eff7915c83f32b13ca6f31a6847b1c1ce114ea240bac3595eded89f09b2313b7915ad882292e2b586d5b4", "0x961776c8576030c39f214ea6e0a3e8b3d32f023d2600958c098c95c8a4e374deeb2b9dc522adfbd6bda5949bdc09e2a2", "0x993fa7d8447407af0fbcd9e6d77f815fa5233ab00674efbcf74a1f51c37481445ae291cc7b76db7c178f9cb0e570e0fc", "0xabd5b1c78e05f9d7c8cc99bdaef8b0b6a57f2daf0f02bf492bec48ea4a27a8f1e38b5854da96efff11973326ff980f92", "0x8f15af4764bc275e6ccb892b3a4362cacb4e175b1526a9a99944e692fe6ccb1b4fc19abf312bb2a089cb1f344d91a779", "0xa09b27ccd71855512aba1d0c30a79ffbe7f6707a55978f3ced50e674b511a79a446dbc6d7946add421ce111135a460af", "0x94b2f98ce86a9271fbd4153e1fc37de48421fe3490fb3840c00f2d5a4d0ba8810c6a32880b002f6374b59e0a7952518b", "0x8650ac644f93bbcb88a6a0f49fee2663297fd4bc6fd47b6a89b9d8038d32370438ab3a4775ec9b58cb10aea8a95ef7b6", "0x95e5c2f2e84eed88c6980bbba5a1c0bb375d5a628bff006f7516d45bb7d723da676add4fdd45956f312e7bab0f052644", "0xb3278a3fa377ac93af7cfc9453f8cb594aae04269bbc99d2e0e45472ff4b6a2f97a26c4c57bf675b9d86f5e77a5d55d1", "0xb4bcbe6eb666a206e2ea2f877912c1d3b5bdbd08a989fc4490eb06013e1a69ad1ba08bcdac048bf29192312be399077b", "0xa76d70b78c99fffcbf9bb9886eab40f1ea4f99a309710b660b64cbf86057cbcb644d243f6e341711bb7ef0fedf0435a7", "0xb2093c1ee945dca7ac76ad5aed08eae23af31dd5a77c903fd7b6f051f4ab84425d33a03c3d45bf2907bc93c02d1f3ad8", "0x904b1f7534e053a265b22d20be859912b9c9ccb303af9a8d6f1d8f6ccdc5c53eb4a45a1762b880d8444d9be0cd55e7f9", "0x8f664a965d65bc730c9ef1ec7467be984d4b8eb46bd9b0d64e38e48f94e6e55dda19aeac82cbcf4e1473440e64c4ca18", "0x8bcee65c4cc7a7799353d07b114c718a2aae0cd10a3f22b7eead5185d159dafd64852cb63924bf87627d176228878bce", "0x8c78f2e3675096fef7ebaa898d2615cd50d39ca3d8f02b9bdfb07e67da648ae4be3da64838dffc5935fd72962c4b96c7", "0x8c40afd3701629421fec1df1aac4e849384ef2e80472c0e28d36cb1327acdf2826f99b357f3d7afdbc58a6347fc40b3c", "0xa197813b1c65a8ea5754ef782522a57d63433ef752215ecda1e7da76b0412ee619f58d904abd2e07e0c097048b6ae1dd", "0xa670542629e4333884ad7410f9ea3bd6f988df4a8f8a424ca74b9add2312586900cf9ae8bd50411f9146e82626b4af56", "0xa19875cc07ab84e569d98b8b67fb1dbbdfb59093c7b748fae008c8904a6fd931a63ca8d03ab5fea9bc8d263568125a9b", "0xb57e7f68e4eb1bd04aafa917b1db1bdab759a02aa8a9cdb1cba34ba8852b5890f655645c9b4e15d5f19bf37e9f2ffe9f", "0x8abe4e2a4f6462b6c64b3f10e45db2a53c2b0d3c5d5443d3f00a453e193df771eda635b098b6c8604ace3557514027af", "0x8459e4fb378189b22b870a6ef20183deb816cefbf66eca1dc7e86d36a2e011537db893729f500dc154f14ce24633ba47", "0x930851df4bc7913c0d8c0f7bd3b071a83668987ed7c397d3d042fdc0d9765945a39a3bae83da9c88cb6b686ed8aeeb26", "0x8078c9e5cd05e1a8c932f8a1d835f61a248b6e7133fcbb3de406bf4ffc0e584f6f9f95062740ba6008d98348886cf76b", "0xaddff62bb29430983fe578e3709b0949cdc0d47a13a29bc3f50371a2cb5c822ce53e2448cfaa01bcb6e0aa850d5a380e", "0x9433add687b5a1e12066721789b1db2edf9b6558c3bdc0f452ba33b1da67426abe326e9a34d207bfb1c491c18811bde1", "0x822beda3389963428cccc4a2918fa9a8a51cf0919640350293af70821967108cded5997adae86b33cb917780b097f1ca", "0xa7a9f52bda45e4148ed56dd176df7bd672e9b5ed18888ccdb405f47920fdb0844355f8565cefb17010b38324edd8315f", "0xb35c3a872e18e607b2555c51f9696a17fa18da1f924d503b163b4ec9fe22ed0c110925275cb6c93ce2d013e88f173d6a", "0xadf34b002b2b26ab84fc1bf94e05bd8616a1d06664799ab149363c56a6e0c807fdc473327d25632416e952ea327fcd95", "0xae4a6b9d22a4a3183fac29e2551e1124a8ce4a561a9a2afa9b23032b58d444e6155bb2b48f85c7b6d70393274e230db7", "0xa2ea3be4fc17e9b7ce3110284038d46a09e88a247b6971167a7878d9dcf36925d613c382b400cfa4f37a3ebea3699897", "0x8e5863786b641ce3140fbfe37124d7ad3925472e924f814ebfc45959aaf3f61dc554a597610b5defaecc85b59a99b50f", "0xaefde3193d0f700d0f515ab2aaa43e2ef1d7831c4f7859f48e52693d57f97fa9e520090f3ed700e1c966f4b76048e57f", "0x841a50f772956622798e5cd208dc7534d4e39eddee30d8ce133383d66e5f267e389254a0cdae01b770ecd0a9ca421929", "0x8fbc2bfd28238c7d47d4c03b1b910946c0d94274a199575e5b23242619b1de3497784e646a92aa03e3e24123ae4fcaba", "0x926999579c8eec1cc47d7330112586bdca20b4149c8b2d066f527c8b9f609e61ce27feb69db67eea382649c6905efcf9", "0xb09f31f305efcc65589adf5d3690a76cf339efd67cd43a4e3ced7b839507466e4be72dd91f04e89e4bbef629d46e68c0", "0xb917361f6b95f759642638e0b1d2b3a29c3bdef0b94faa30de562e6078c7e2d25976159df3edbacbf43614635c2640b4", "0x8e7e8a1253bbda0e134d62bfe003a2669d471b47bd2b5cde0ff60d385d8e62279d54022f5ac12053b1e2d3aaa6910b4c", "0xb69671a3c64e0a99d90b0ed108ce1912ff8ed983e4bddd75a370e9babde25ee1f5efb59ec707edddd46793207a8b1fe7", "0x910b2f4ebd37b7ae94108922b233d0920b4aba0bd94202c70f1314418b548d11d8e9caa91f2cd95aff51b9432d122b7f", "0x82f645c90dfb52d195c1020346287c43a80233d3538954548604d09fbab7421241cde8593dbc4acc4986e0ea39a27dd9", "0x8fee895f0a140d88104ce442fed3966f58ff9d275e7373483f6b4249d64a25fb5374bbdc6bce6b5ab0270c2847066f83", "0x84f5bd7aab27b2509397aeb86510dd5ac0a53f2c8f73799bf720f2f87a52277f8d6b0f77f17bc80739c6a7119b7eb062", "0x9903ceced81099d7e146e661bcf01cbaccab5ba54366b85e2177f07e2d8621e19d9c9c3eee14b9266de6b3f9b6ea75ae", "0xb9c16ea2a07afa32dd6c7c06df0dec39bca2067a9339e45475c98917f47e2320f6f235da353fd5e15b477de97ddc68dd", "0x9820a9bbf8b826bec61ebf886de2c4f404c1ebdc8bab82ee1fea816d9de29127ce1852448ff717a3fe8bbfe9e92012e5", "0x817224d9359f5da6f2158c2c7bf9165501424f063e67ba9859a07ab72ee2ee62eb00ca6da821cfa19065c3282ca72c74", "0x94b95c465e6cb00da400558a3c60cfec4b79b27e602ca67cbc91aead08de4b6872d8ea096b0dc06dca4525c8992b8547", "0xa2b539a5bccd43fa347ba9c15f249b417997c6a38c63517ca38394976baa08e20be384a360969ff54e7e721db536b3e5", "0x96caf707e34f62811ee8d32ccf28d8d6ec579bc33e424d0473529af5315c456fd026aa910c1fed70c91982d51df7d3ca", "0x8a77b73e890b644c6a142bdbac59b22d6a676f3b63ddafb52d914bb9d395b8bf5aedcbcc90429337df431ebd758a07a6", "0x8857830a7351025617a08bc44caec28d2fae07ebf5ffc9f01d979ce2a53839a670e61ae2783e138313929129790a51a1", "0xaa3e420321ed6f0aa326d28d1a10f13facec6f605b6218a6eb9cbc074801f3467bf013a456d1415a5536f12599efa3d3", "0x824aed0951957b00ea2f3d423e30328a3527bf6714cf9abbae84cf27e58e5c35452ba89ccc011de7c68c75d6e021d8f1", "0xa2e87cc06bf202e953fb1081933d8b4445527dde20e38ed1a4f440144fd8fa464a2b73e068b140562e9045e0f4bd3144", "0xae3b8f06ad97d7ae3a5e5ca839efff3e4824dc238c0c03fc1a8d2fc8aa546cdfd165b784a31bb4dec7c77e9305b99a4b", "0xb30c3e12395b1fb8b776f3ec9f87c70e35763a7b2ddc68f0f60a4982a84017f27c891a98561c830038deb033698ed7fc", "0x874e507757cd1177d0dff0b0c62ce90130324442a33da3b2c8ee09dbca5d543e3ecfe707e9f1361e7c7db641c72794bb", "0xb53012dd10b5e7460b57c092eaa06d6502720df9edbbe3e3f61a9998a272bf5baaac4a5a732ad4efe35d6fac6feca744", "0x85e6509d711515534d394e6cacbed6c81da710074d16ef3f4950bf2f578d662a494d835674f79c4d6315bced4defc5f0", "0xb6132b2a34b0905dcadc6119fd215419a7971fe545e52f48b768006944b4a9d7db1a74b149e2951ea48c083b752d0804", "0x989867da6415036d19b4bacc926ce6f4df7a556f50a1ba5f3c48eea9cefbb1c09da81481c8009331ee83f0859185e164", "0x960a6c36542876174d3fbc1505413e29f053ed87b8d38fef3af180491c7eff25200b45dd5fe5d4d8e63c7e8c9c00f4c8", "0x9040b59bd739d9cc2e8f6e894683429e4e876a8106238689ff4c22770ae5fdae1f32d962b30301fa0634ee163b524f35", "0xaf3fcd0a45fe9e8fe256dc7eab242ef7f582dd832d147444483c62787ac820fafc6ca55d639a73f76bfa5e7f5462ab8f", "0xb934c799d0736953a73d91e761767fdb78454355c4b15c680ce08accb57ccf941b13a1236980001f9e6195801cffd692", "0x8871e8e741157c2c326b22cf09551e78da3c1ec0fc0543136f581f1550f8bab03b0a7b80525c1e99812cdbf3a9698f96", "0xa8a977f51473a91d178ee8cfa45ffef8d6fd93ab1d6e428f96a3c79816d9c6a93cd70f94d4deda0125fd6816e30f3bea", "0xa7688b3b0a4fc1dd16e8ba6dc758d3cfe1b7cf401c31739484c7fa253cce0967df1b290769bcefc9d23d3e0cb19e6218", "0x8ae84322662a57c6d729e6ff9d2737698cc2da2daeb1f39e506618750ed23442a6740955f299e4a15dda6db3e534d2c6", "0xa04a961cdccfa4b7ef83ced17ab221d6a043b2c718a0d6cc8e6f798507a31f10bf70361f70a049bc8058303fa7f96864", "0xb463e39732a7d9daec8a456fb58e54b30a6e160aa522a18b9a9e836488cce3342bcbb2e1deab0f5e6ec0a8796d77197d", "0xb1434a11c6750f14018a2d3bcf94390e2948f4f187e93bb22070ca3e5393d339dc328cbfc3e48815f51929465ffe7d81", "0x84ff81d73f3828340623d7e3345553610aa22a5432217ef0ebd193cbf4a24234b190c65ca0873c22d10ea7b63bd1fbed", "0xb6fe2723f0c47757932c2ddde7a4f8434f665612f7b87b4009c2635d56b6e16b200859a8ade49276de0ef27a2b6c970a", "0x9742884ed7cd52b4a4a068a43d3faa02551a424136c85a9313f7cb58ea54c04aa83b0728fd741d1fe39621e931e88f8f", "0xb7d2d65ea4d1ad07a5dee39e40d6c03a61264a56b1585b4d76fc5b2a68d80a93a42a0181d432528582bf08d144c2d6a9", "0x88c0f66bada89f8a43e5a6ead2915088173d106c76f724f4a97b0f6758aed6ae5c37c373c6b92cdd4aea8f6261f3a374", "0x81f9c43582cb42db3900747eb49ec94edb2284999a499d1527f03315fd330e5a509afa3bff659853570e9886aab5b28b", "0x821f9d27d6beb416abf9aa5c79afb65a50ed276dbda6060103bc808bcd34426b82da5f23e38e88a55e172f5c294b4d40", "0x8ba307b9e7cb63a6c4f3851b321aebfdb6af34a5a4c3bd949ff7d96603e59b27ff4dc4970715d35f7758260ff942c9e9", "0xb142eb6c5f846de33227d0bda61d445a7c33c98f0a8365fe6ab4c1fabdc130849be597ef734305894a424ea715372d08", "0xa732730ae4512e86a741c8e4c87fee8a05ee840fec0e23b2e037d58dba8dde8d10a9bc5191d34d00598941becbbe467f", "0xadce6f7c30fd221f6b10a0413cc76435c4bb36c2d60bca821e5c67409fe9dbb2f4c36ef85eb3d734695e4be4827e9fd3", "0xa74f00e0f9b23aff7b2527ce69852f8906dab9d6abe62ecd497498ab21e57542e12af9918d4fd610bb09e10b0929c510", "0xa593b6b0ef26448ce4eb3ab07e84238fc020b3cb10d542ff4b16d4e2be1bcde3797e45c9cf753b8dc3b0ffdb63984232", "0xaed3913afccf1aa1ac0eb4980eb8426d0baccebd836d44651fd72af00d09fac488a870223c42aca3ceb39752070405ae", "0xb2c44c66a5ea7fde626548ba4cef8c8710191343d3dadfd3bb653ce715c0e03056a5303a581d47dde66e70ea5a2d2779", "0x8e5029b2ccf5128a12327b5103f7532db599846e422531869560ceaff392236434d87159f597937dbf4054f810c114f4", "0x82beed1a2c4477e5eb39fc5b0e773b30cfec77ef2b1bf17eadaf60eb35b6d0dd9d8cf06315c48d3546badb3f21cd0cca", "0x90077bd6cc0e4be5fff08e5d07a5a158d36cebd1d1363125bc4fae0866ffe825b26f933d4ee5427ba5cd0c33c19a7b06", "0xa7ec0d8f079970e8e34f0ef3a53d3e0e45428ddcef9cc776ead5e542ef06f3c86981644f61c5a637e4faf001fb8c6b3e", "0xae6d4add6d1a6f90b22792bc9d40723ee6850c27d0b97eefafd5b7fd98e424aa97868b5287cc41b4fbd7023bca6a322c", "0x831aa917533d077da07c01417feaa1408846363ba2b8d22c6116bb858a95801547dd88b7d7fa1d2e3f0a02bdeb2e103d", "0x96511b860b07c8a5ed773f36d4aa9d02fb5e7882753bf56303595bcb57e37ccc60288887eb83bef08c657ec261a021a2", "0x921d2a3e7e9790f74068623de327443666b634c8443aba80120a45bba450df920b2374d96df1ce3fb1b06dd06f8cf6e3", "0xaa74451d51fe82b4581ead8e506ec6cd881010f7e7dd51fc388eb9a557db5d3c6721f81c151d08ebd9c2591689fbc13e", "0xa972bfbcf4033d5742d08716c927c442119bdae336bf5dff914523b285ccf31953da2733759aacaa246a9af9f698342c", "0xad1fcd0cae0e76840194ce4150cb8a56ebed728ec9272035f52a799d480dfc85840a4d52d994a18b6edb31e79be6e8ad", "0xa2c69fe1d36f235215432dad48d75887a44c99dfa0d78149acc74087da215a44bdb5f04e6eef88ff7eff80a5a7decc77", "0xa94ab2af2b6ee1bc6e0d4e689ca45380d9fbd3c5a65b9bd249d266a4d4c07bf5d5f7ef2ae6000623aee64027892bf8fe", "0x881ec1fc514e926cdc66480ac59e139148ff8a2a7895a49f0dff45910c90cdda97b66441a25f357d6dd2471cddd99bb3", "0x884e6d3b894a914c8cef946a76d5a0c8351843b2bffa2d1e56c6b5b99c84104381dd1320c451d551c0b966f4086e60f9", "0x817c6c10ce2677b9fc5223500322e2b880583254d0bb0d247d728f8716f5e05c9ff39f135854342a1afecd9fbdcf7c46", "0xaaf4a9cb686a14619aa1fc1ac285dd3843ac3dd99f2b2331c711ec87b03491c02f49101046f3c5c538dc9f8dba2a0ac2", "0x97ecea5ce53ca720b5d845227ae61d70269a2f53540089305c86af35f0898bfd57356e74a8a5e083fa6e1ea70080bd31", "0xa22d811e1a20a75feac0157c418a4bfe745ccb5d29466ffa854dca03e395b6c3504a734341746b2846d76583a780b32e", "0x940cbaa0d2b2db94ae96b6b9cf2deefbfd059e3e5745de9aec4a25f0991b9721e5cd37ef71c631575d1a0c280b01cd5b", "0xae33cb4951191258a11044682de861bf8d92d90ce751b354932dd9f3913f542b6a0f8a4dc228b3cd9244ac32c4582832", "0xa580df5e58c4274fe0f52ac2da1837e32f5c9db92be16c170187db4c358f43e5cfdda7c5911dcc79d77a5764e32325f5", "0x81798178cb9d8affa424f8d3be67576ba94d108a28ccc01d330c51d5a63ca45bb8ca63a2f569b5c5fe1303cecd2d777f", "0x89975b91b94c25c9c3660e4af4047a8bacf964783010820dbc91ff8281509379cb3b24c25080d5a01174dd9a049118d5", "0xa7327fcb3710ed3273b048650bde40a32732ef40a7e58cf7f2f400979c177944c8bc54117ba6c80d5d4260801dddab79", "0x92b475dc8cb5be4b90c482f122a51bcb3b6c70593817e7e2459c28ea54a7845c50272af38119406eaadb9bcb993368d0", "0x9645173e9ecefc4f2eae8363504f7c0b81d85f8949a9f8a6c01f2d49e0a0764f4eacecf3e94016dd407fc14494fce9f9", "0x9215fd8983d7de6ae94d35e6698226fc1454977ae58d42d294be9aad13ac821562ad37d5e7ee5cdfe6e87031d45cd197", "0x810360a1c9b88a9e36f520ab5a1eb8bed93f52deefbe1312a69225c0a08edb10f87cc43b794aced9c74220cefcc57e7d", "0xad7e810efd61ed4684aeda9ed8bb02fb9ae4b4b63fda8217d37012b94ff1b91c0087043bfa4e376f961fff030c729f3b", "0x8b07c95c6a06db8738d10bb03ec11b89375c08e77f0cab7e672ce70b2685667ca19c7e1c8b092821d31108ea18dfd4c7", "0x968825d025ded899ff7c57245250535c732836f7565eab1ae23ee7e513201d413c16e1ba3f5166e7ac6cf74de8ceef4f", "0x908243370c5788200703ade8164943ad5f8c458219186432e74dbc9904a701ea307fd9b94976c866e6c58595fd891c4b", "0x959969d16680bc535cdc6339e6186355d0d6c0d53d7bbfb411641b9bf4b770fd5f575beef5deec5c4fa4d192d455c350", "0xad177f4f826a961adeac76da40e2d930748effff731756c797eddc4e5aa23c91f070fb69b19221748130b0961e68a6bb", "0x82f8462bcc25448ef7e0739425378e9bb8a05e283ce54aae9dbebaf7a3469f57833c9171672ad43a79778366c72a5e37", "0xa28fb275b1845706c2814d9638573e9bc32ff552ebaed761fe96fdbce70395891ca41c400ae438369264e31a2713b15f", "0x8a9c613996b5e51dadb587a787253d6081ea446bf5c71096980bf6bd3c4b69905062a8e8a3792de2d2ece3b177a71089", "0x8d5aefef9f60cb27c1db2c649221204dda48bb9bf8bf48f965741da051340e8e4cab88b9d15c69f3f84f4c854709f48a", "0x93ebf2ca6ad85ab6deace6de1a458706285b31877b1b4d7dcb9d126b63047efaf8c06d580115ec9acee30c8a7212fa55", "0xb3ee46ce189956ca298057fa8223b7fd1128cf52f39159a58bca03c71dd25161ac13f1472301f72aef3e1993fe1ab269", "0xa24d7a8d066504fc3f5027ccb13120e2f22896860e02c45b5eba1dbd512d6a17c28f39155ea581619f9d33db43a96f92", "0xae9ceacbfe12137db2c1a271e1b34b8f92e4816bad1b3b9b6feecc34df0f8b3b0f7ed0133acdf59c537d43d33fc8d429", "0x83967e69bf2b361f86361bd705dce0e1ad26df06da6c52b48176fe8dfcbeb03c462c1a4c9e649eff8c654b18c876fdef", "0x9148e6b814a7d779c19c31e33a068e97b597de1f8100513db3c581190513edc4d544801ce3dd2cf6b19e0cd6daedd28a", "0x94ccdafc84920d320ed22de1e754adea072935d3c5f8c2d1378ebe53d140ea29853f056fb3fb1e375846061a038cc9bc", "0xafb43348498c38b0fa5f971b8cdd3a62c844f0eb52bc33daf2f67850af0880fce84ecfb96201b308d9e6168a0d443ae3", "0x86d5736520a83538d4cd058cc4b4e84213ed00ebd6e7af79ae787adc17a92ba5359e28ba6c91936d967b4b28d24c3070", "0xb5210c1ff212c5b1e9ef9126e08fe120a41e386bb12c22266f7538c6d69c7fd8774f11c02b81fd4e88f9137b020801fe", "0xb78cfd19f94d24e529d0f52e18ce6185cb238edc6bd43086270fd51dd99f664f43dd4c7d2fe506762fbd859028e13fcf", "0xa6e7220598c554abdcc3fdc587b988617b32c7bb0f82c06205467dbedb58276cc07cae317a190f19d19078773f4c2bbb", "0xb88862809487ee430368dccd85a5d72fa4d163ca4aad15c78800e19c1a95be2192719801e315d86cff7795e0544a77e4", "0x87ecb13a03921296f8c42ceb252d04716f10e09c93962239fcaa0a7fef93f19ab3f2680bc406170108bc583e9ff2e721", "0xa810cd473832b6581c36ec4cb403f2849357ba2d0b54df98ef3004b8a530c078032922a81d40158f5fb0043d56477f6e", "0xa247b45dd85ca7fbb718b328f30a03f03c84aef2c583fbdc9fcc9eb8b52b34529e8c8f535505c10598b1b4dac3d7c647", "0x96ee0b91313c68bac4aa9e065ce9e1d77e51ca4cff31d6a438718c58264dee87674bd97fc5c6b8008be709521e4fd008", "0x837567ad073e42266951a9a54750919280a2ac835a73c158407c3a2b1904cf0d17b7195a393c71a18ad029cbd9cf79ee", "0xa6a469c44b67ebf02196213e7a63ad0423aab9a6e54acc6fcbdbb915bc043586993454dc3cd9e4be8f27d67c1050879b", "0x8712d380a843b08b7b294f1f06e2f11f4ad6bcc655fdde86a4d8bc739c23916f6fad2b902fe47d6212f03607907e9f0e", "0x920adfb644b534789943cdae1bdd6e42828dda1696a440af2f54e6b97f4f97470a1c6ea9fa6a2705d8f04911d055acd1", "0xa161c73adf584a0061e963b062f59d90faac65c9b3a936b837a10d817f02fcabfa748824607be45a183dd40f991fe83f", "0x874f4ecd408c76e625ea50bc59c53c2d930ee25baf4b4eca2440bfbffb3b8bc294db579caa7c68629f4d9ec24187c1ba", "0x8bff18087f112be7f4aa654e85c71fef70eee8ae480f61d0383ff6f5ab1a0508f966183bb3fc4d6f29cb7ca234aa50d3", "0xb03b46a3ca3bc743a173cbc008f92ab1aedd7466b35a6d1ca11e894b9482ea9dc75f8d6db2ddd1add99bfbe7657518b7", "0x8b4f3691403c3a8ad9e097f02d130769628feddfa8c2b3dfe8cff64e2bed7d6e5d192c1e2ba0ac348b8585e94acd5fa1", "0xa0d9ca4a212301f97591bf65d5ef2b2664766b427c9dd342e23cb468426e6a56be66b1cb41fea1889ac5d11a8e3c50a5", "0x8c93ed74188ca23b3df29e5396974b9cc135c91fdefdea6c0df694c8116410e93509559af55533a3776ac11b228d69b1", "0x82dd331fb3f9e344ebdeeb557769b86a2cc8cc38f6c298d7572a33aea87c261afa9dbd898989139b9fc16bc1e880a099", "0xa65faedf326bcfd8ef98a51410c78b021d39206704e8291cd1f09e096a66b9b0486be65ff185ca224c45918ac337ddeb", "0xa188b37d363ac072a766fd5d6fa27df07363feff1342217b19e3c37385e42ffde55e4be8355aceaa2f267b6d66b4ac41", "0x810fa3ba3e96d843e3bafd3f2995727f223d3567c8ba77d684c993ba1773c66551eb5009897c51b3fe9b37196984f5ec", "0x87631537541852da323b4353af45a164f68b304d24c01183bf271782e11687f3fcf528394e1566c2a26cb527b3148e64", "0xb721cb2b37b3c477a48e3cc0044167d51ff568a5fd2fb606e5aec7a267000f1ddc07d3db919926ae12761a8e017c767c", "0x904dfad4ba2cc1f6e60d1b708438a70b1743b400164cd981f13c064b8328d5973987d4fb9cf894068f29d3deaf624dfb", "0xa70491538893552c20939fae6be2f07bfa84d97e2534a6bbcc0f1729246b831103505e9f60e97a8fa7d2e6c1c2384579", "0x8726cf1b26b41f443ff7485adcfddc39ace2e62f4d65dd0bb927d933e262b66f1a9b367ded5fbdd6f3b0932553ac1735", "0xae8a11cfdf7aa54c08f80cb645e3339187ab3886babe9fae5239ba507bb3dd1c0d161ca474a2df081dcd3d63e8fe445e", "0x92328719e97ce60e56110f30a00ac5d9c7a2baaf5f8d22355d53c1c77941e3a1fec7d1405e6fbf8959665fe2ba7a8cad", "0x8d9d6255b65798d0018a8cccb0b6343efd41dc14ff2058d3eed9451ceaad681e4a0fa6af67b0a04318aa628024e5553d", "0xb70209090055459296006742d946a513f0cba6d83a05249ee8e7a51052b29c0ca9722dc4af5f9816a1b7938a5dac7f79", "0xaab7b766b9bf91786dfa801fcef6d575dc6f12b77ecc662eb4498f0312e54d0de9ea820e61508fc8aeee5ab5db529349", "0xa8104b462337748b7f086a135d0c3f87f8e51b7165ca6611264b8fb639d9a2f519926cb311fa2055b5fadf03da70c678", "0xb0d2460747d5d8b30fc6c6bd0a87cb343ddb05d90a51b465e8f67d499cfc5e3a9e365da05ae233bbee792cdf90ec67d5", "0xaa55f5bf3815266b4a149f85ed18e451c93de9163575e3ec75dd610381cc0805bb0a4d7c4af5b1f94d10231255436d2c", "0x8d4c6a1944ff94426151909eb5b99cfd92167b967dabe2bf3aa66bb3c26c449c13097de881b2cfc1bf052862c1ef7b03", "0x8862296162451b9b6b77f03bf32e6df71325e8d7485cf3335d66fd48b74c2a8334c241db8263033724f26269ad95b395", "0x901aa96deb26cda5d9321190ae6624d357a41729d72ef1abfd71bebf6139af6d690798daba53b7bc5923462115ff748a", "0x96c195ec4992728a1eb38cdde42d89a7bce150db43adbc9e61e279ea839e538deec71326b618dd39c50d589f78fc0614", "0xb6ff8b8aa0837b99a1a8b46fb37f20ad4aecc6a98381b1308697829a59b8442ffc748637a88cb30c9b1f0f28a926c4f6", "0x8d807e3dca9e7bef277db1d2cfb372408dd587364e8048b304eff00eacde2c723bfc84be9b98553f83cba5c7b3cba248", "0x8800c96adb0195c4fc5b24511450dee503c32bf47044f5e2e25bd6651f514d79a2dd9b01cd8c09f3c9d3859338490f57", "0x89fe366096097e38ec28dd1148887112efa5306cc0c3da09562aafa56f4eb000bf46ff79bf0bdd270cbde6bf0e1c8957", "0xaf409a90c2776e1e7e3760b2042507b8709e943424606e31e791d42f17873a2710797f5baaab4cc4a19998ef648556b0", "0x8d761863c9b6edbd232d35ab853d944f5c950c2b643f84a1a1327ebb947290800710ff01dcfa26dc8e9828481240e8b1", "0x90b95e9be1e55c463ed857c4e0617d6dc3674e99b6aa62ed33c8e79d6dfcf7d122f4f4cc2ee3e7c5a49170cb617d2e2e", "0xb3ff381efefabc4db38cc4727432e0301949ae4f16f8d1dea9b4f4de611cf5a36d84290a0bef160dac4e1955e516b3b0", "0xa8a84564b56a9003adcadb3565dc512239fc79572762cda7b5901a255bc82656bb9c01212ad33d6bef4fbbce18dacc87", "0x90a081890364b222eef54bf0075417f85e340d2fec8b7375995f598aeb33f26b44143ebf56fca7d8b4ebb36b5747b0eb", "0xade6ee49e1293224ddf2d8ab7f14bb5be6bc6284f60fd5b3a1e0cf147b73cff57cf19763b8a36c5083badc79c606b103", "0xb2fa99806dd2fa3de09320b615a2570c416c9bcdb052e592b0aead748bbe407ec9475a3d932ae48b71c2627eb81986a6", "0x91f3b7b73c8ccc9392542711c45fe6f236057e6efad587d661ad5cb4d6e88265f86b807bb1151736b1009ab74fd7acb4", "0x8800e2a46af96696dfbdcbf2ca2918b3dcf28ad970170d2d1783b52b8d945a9167d052beeb55f56c126da7ffa7059baa", "0x9862267a1311c385956b977c9aa08548c28d758d7ba82d43dbc3d0a0fd1b7a221d39e8399997fea9014ac509ff510ac4", "0xb7d24f78886fd3e2d283e18d9ad5a25c1a904e7d9b9104bf47da469d74f34162e27e531380dbbe0a9d051e6ffd51d6e7", "0xb0f445f9d143e28b9df36b0f2c052da87ee2ca374d9d0fbe2eff66ca6fe5fe0d2c1951b428d58f7314b7e74e45d445ea", "0xb63fc4083eabb8437dafeb6a904120691dcb53ce2938b820bb553da0e1eecd476f72495aacb72600cf9cad18698fd3db", "0xb9ffd8108eaebd582d665f8690fe8bb207fd85185e6dd9f0b355a09bac1bbff26e0fdb172bc0498df025414e88fe2eda", "0x967ed453e1f1a4c5b7b6834cc9f75c13f6889edc0cc91dc445727e9f408487bbf05c337103f61397a10011dfbe25d61d", "0x98ceb673aff36e1987d5521a3984a07079c3c6155974bb8b413e8ae1ce84095fe4f7862fba7aefa14753eb26f2a5805f", "0x85f01d28603a8fdf6ce6a50cb5c44f8a36b95b91302e3f4cd95c108ce8f4d212e73aec1b8d936520d9226802a2bd9136", "0x88118e9703200ca07910345fbb789e7a8f92bd80bbc79f0a9e040e8767d33df39f6eded403a9b636eabf9101e588482a", "0x90833a51eef1b10ed74e8f9bbd6197e29c5292e469c854eed10b0da663e2bceb92539710b1858bbb21887bd538d28d89", "0xb513b905ec19191167c6193067b5cfdf5a3d3828375360df1c7e2ced5815437dfd37f0c4c8f009d7fb29ff3c8793f560", "0xb1b6d405d2d18f9554b8a358cc7e2d78a3b34269737d561992c8de83392ac9a2857be4bf15de5a6c74e0c9d0f31f393c", "0xb828bd3e452b797323b798186607849f85d1fb20c616833c0619360dfd6b3e3aa000fd09dafe4b62d74abc41072ff1a9", "0x8efde67d0cca56bb2c464731879c9ac46a52e75bac702a63200a5e192b4f81c641f855ca6747752b84fe469cb7113b6c", "0xb2762ba1c89ac3c9a983c242e4d1c2610ff0528585ed5c0dfc8a2c0253551142af9b59f43158e8915a1da7cc26b9df67", "0x8a3f1157fb820d1497ef6b25cd70b7e16bb8b961b0063ad340d82a79ee76eb2359ca9e15e6d42987ed7f154f5eeaa2da", "0xa75e29f29d38f09c879f971c11beb5368affa084313474a5ecafa2896180b9e47ea1995c2733ec46f421e395a1d9cffe", "0x8e8c3dd3e7196ef0b4996b531ec79e4a1f211db5d5635e48ceb80ff7568b2ff587e845f97ee703bb23a60945ad64314a", "0x8e7f32f4a3e3c584af5e3d406924a0aa34024c42eca74ef6cc2a358fd3c9efaf25f1c03aa1e66bb94b023a2ee2a1cace", "0xab7dce05d59c10a84feb524fcb62478906b3fa045135b23afbede3bb32e0c678d8ebe59feabccb5c8f3550ea76cae44b", "0xb38bb4b44d827f6fd3bd34e31f9186c59e312dbfadd4a7a88e588da10146a78b1f8716c91ad8b806beb8da65cab80c4c", "0x9490ce9442bbbd05438c7f5c4dea789f74a7e92b1886a730544b55ba377840740a3ae4f2f146ee73f47c9278b0e233bc", "0x83c003fab22a7178eed1a668e0f65d4fe38ef3900044e9ec63070c23f2827d36a1e73e5c2b883ec6a2afe2450171b3b3", "0x9982f02405978ddc4fca9063ebbdb152f524c84e79398955e66fe51bc7c1660ec1afc3a86ec49f58d7b7dde03505731c", "0xab337bd83ccdd2322088ffa8d005f450ced6b35790f37ab4534313315ee84312adc25e99cce052863a8bedee991729ed", "0x8312ce4bec94366d88f16127a17419ef64285cd5bf9e5eda010319b48085966ed1252ed2f5a9fd3e0259b91bb65f1827", "0xa60d5a6327c4041b0c00a1aa2f0af056520f83c9ce9d9ccd03a0bd4d9e6a1511f26a422ea86bd858a1f77438adf07e6c", "0xb84a0a0b030bdad83cf5202aa9afe58c9820e52483ab41f835f8c582c129ee3f34aa096d11c1cd922eda02ea1196a882", "0x8077d105317f4a8a8f1aadeb05e0722bb55f11abcb490c36c0904401107eb3372875b0ac233144829e734f0c538d8c1d", "0x9202503bd29a6ec198823a1e4e098f9cfe359ed51eb5174d1ca41368821bfeebcbd49debfd02952c41359d1c7c06d2b1", "0xabc28c155e09365cb77ffead8dc8f602335ef93b2f44e4ef767ce8fc8ef9dd707400f3a722e92776c2e0b40192c06354", "0xb0f6d1442533ca45c9399e0a63a11f85ff288d242cea6cb3b68c02e77bd7d158047cae2d25b3bcd9606f8f66d9b32855", "0xb01c3d56a0db84dc94575f4b6ee2de4beca3230e86bed63e2066beb22768b0a8efb08ebaf8ac3dedb5fe46708b084807", "0x8c8634b0432159f66feaabb165842d1c8ac378f79565b1b90c381aa8450eb4231c3dad11ec9317b9fc2b155c3a771e32", "0x8e67f623d69ecd430c9ee0888520b6038f13a2b6140525b056dc0951f0cfed2822e62cf11d952a483107c5c5acac4826", "0x9590bb1cba816dd6acd5ac5fba5142c0a19d53573e422c74005e0bcf34993a8138c83124cad35a3df65879dba6134edd", "0x801cd96cde0749021a253027118d3ea135f3fcdbe895db08a6c145641f95ebd368dd6a1568d995e1d0084146aebe224a", "0x848b5d196427f6fc1f762ee3d36e832b64a76ec1033cfedc8b985dea93932a7892b8ef1035c653fb9dcd9ab2d9a44ac8", "0xa1017eb83d5c4e2477e7bd2241b2b98c4951a3b391081cae7d75965cadc1acaec755cf350f1f3d29741b0828e36fedea", "0x8d6d2785e30f3c29aad17bd677914a752f831e96d46caf54446d967cb2432be2c849e26f0d193a60bee161ea5c6fe90a", "0x935c0ba4290d4595428e034b5c8001cbd400040d89ab00861108e8f8f4af4258e41f34a7e6b93b04bc253d3b9ffc13bf", "0xaac02257146246998477921cef2e9892228590d323b839f3e64ea893b991b463bc2f47e1e5092ddb47e70b2f5bce7622", "0xb921fde9412970a5d4c9a908ae8ce65861d06c7679af577cf0ad0d5344c421166986bee471fd6a6cecb7d591f06ec985", "0x8ef4c37487b139d6756003060600bb6ebac7ea810b9c4364fc978e842f13ac196d1264fbe5af60d76ff6d9203d8e7d3f", "0x94b65e14022b5cf6a9b95f94be5ace2711957c96f4211c3f7bb36206bd39cfbd0ea82186cab5ad0577a23214a5c86e9e", "0xa31c166d2a2ca1d5a75a5920fef7532681f62191a50d8555fdaa63ba4581c3391cc94a536fc09aac89f64eafceec3f90", "0x919a8cc128de01e9e10f5d83b08b52293fdd41bde2b5ae070f3d95842d4a16e5331cf2f3d61c765570c8022403610fa4", "0xb23d6f8331eef100152d60483cfa14232a85ee712c8538c9b6417a5a7c5b353c2ac401390c6c215cb101f5cee6b5f43e", "0xab357160c08a18319510a571eafff154298ce1020de8e1dc6138a09fcb0fcbcdd8359f7e9386bda00b7b9cdea745ffdc", "0xab55079aea34afa5c0bd1124b9cdfe01f325b402fdfa017301bf87812eaa811ea5798c3aaf818074d420d1c782b10ada", "0xade616010dc5009e7fc4f8d8b00dc716686a5fa0a7816ad9e503e15839d3b909b69d9dd929b7575376434ffec0d2bea8", "0x863997b97ed46898a8a014599508fa3079f414b1f4a0c4fdc6d74ae8b444afa350f327f8bfc2a85d27f9e2d049c50135", "0x8d602ff596334efd4925549ed95f2aa762b0629189f0df6dbb162581657cf3ea6863cd2287b4d9c8ad52813d87fcd235", "0xb70f68c596dcdeed92ad5c6c348578b26862a51eb5364237b1221e840c47a8702f0fbc56eb520a22c0eed99795d3903e", "0x9628088f8e0853cefadee305a8bf47fa990c50fa96a82511bbe6e5dc81ef4b794e7918a109070f92fc8384d77ace226f", "0x97e26a46e068b605ce96007197ecd943c9a23881862f4797a12a3e96ba2b8d07806ad9e2a0646796b1889c6b7d75188c", "0xb1edf467c068cc163e2d6413cc22b16751e78b3312fe47b7ea82b08a1206d64415b2c8f2a677fa89171e82cc49797150", "0xa44d15ef18745b251429703e3cab188420e2d974de07251501799b016617f9630643fcd06f895634d8ecdd579e1bf000", "0xabd126df3917ba48c618ee4dbdf87df506193462f792874439043fa1b844466f6f4e0ff2e42516e63b5b23c0892b2695", "0xa2a67f57c4aa3c2aa1eeddbfd5009a89c26c2ce8fa3c96a64626aba19514beb125f27df8559506f737de3eae0f1fc18f", "0xa633e0132197e6038197304b296ab171f1d8e0d0f34dcf66fe9146ac385b0239232a8470b9205a4802ab432389f4836d", "0xa914b3a28509a906c3821463b936455d58ff45dcbe158922f9efb2037f2eb0ce8e92532d29b5d5a3fcd0d23fa773f272", "0xa0e1412ce4505daf1a2e59ce4f0fc0e0023e335b50d2b204422f57cd65744cc7a8ed35d5ef131a42c70b27111d3115b7", "0xa2339e2f2b6072e88816224fdd612c04d64e7967a492b9f8829db15367f565745325d361fd0607b0def1be384d010d9e", "0xa7309fc41203cb99382e8193a1dcf03ac190a7ce04835304eb7e341d78634e83ea47cb15b885601956736d04cdfcaa01", "0x81f3ccd6c7f5b39e4e873365f8c37b214e8ab122d04a606fbb7339dc3298c427e922ec7418002561d4106505b5c399ee", "0x92c121cf914ca549130e352eb297872a63200e99b148d88fbc9506ad882bec9d0203d65f280fb5b0ba92e336b7f932e8", "0xa4b330cf3f064f5b131578626ad7043ce2a433b6f175feb0b52d36134a454ca219373fd30d5e5796410e005b69082e47", "0x86fe5774112403ad83f9c55d58317eeb17ad8e1176d9f2f69c2afb7ed83bc718ed4e0245ceab4b377f5f062dcd4c00e7", "0x809d152a7e2654c7fd175b57f7928365a521be92e1ed06c05188a95864ddb25f7cab4c71db7d61bbf4cae46f3a1d96ce", "0xb82d663e55c2a5ada7e169e9b1a87bc1c0177baf1ec1c96559b4cb1c5214ce1ddf2ab8d345014cab6402f3774235cf5a", "0x86580af86df1bd2c385adb8f9a079e925981b7184db66fc5fe5b14cddb82e7d836b06eaeef14924ac529487b23dae111", "0xb5f5f4c5c94944ecc804df6ab8687d64e27d988cbfeae1ba7394e0f6adbf778c5881ead7cd8082dd7d68542b9bb4ecd5", "0xa6016916146c2685c46e8fdd24186394e2d5496e77e08c0c6a709d4cd7dfa97f1efcef94922b89196819076a91ad37b5", "0xb778e7367ded3b6eab53d5fc257f7a87e8faf74a593900f2f517220add2125be3f6142022660d8181df8d164ad9441ce", "0x8581b2d36abe6f553add4d24be761bec1b8efaa2929519114346615380b3c55b59e6ad86990e312f7e234d0203bdf59b", "0x9917e74fd45c3f71a829ff5498a7f6b5599b48c098dda2339bf04352bfc7f368ccf1a407f5835901240e76452ae807d7", "0xafd196ce6f9335069138fd2e3d133134da253978b4ce373152c0f26affe77a336505787594022e610f8feb722f7cc1fb", "0xa477491a1562e329764645e8f24d8e228e5ef28c9f74c6b5b3abc4b6a562c15ffb0f680d372aed04d9e1bf944dece7be", "0x9767440d58c57d3077319d3a330e5322b9ba16981ec74a5a14d53462eab59ae7fd2b14025bfc63b268862094acb444e6", "0x80986d921be3513ef69264423f351a61cb48390c1be8673aee0f089076086aaebea7ebe268fd0aa7182695606116f679", "0xa9554c5c921c07b450ee04e34ec58e054ac1541b26ce2ce5a393367a97348ba0089f53db6660ad76b60278b66fd12e3e", "0x95097e7d2999b3e84bf052c775581cf361325325f4a50192521d8f4693c830bed667d88f482dc1e3f833aa2bd22d2cbf", "0x9014c91d0f85aefd28436b5228c12f6353c055a9326c7efbf5e071e089e2ee7c070fcbc84c5fafc336cbb8fa6fec1ca1", "0x90f57ba36ee1066b55d37384942d8b57ae00f3cf9a3c1d6a3dfee1d1af42d4b5fa9baeb0cd7e46687d1d6d090ddb931d", "0x8e4b1db12fd760a17214c9e47f1fce6e43c0dbb4589a827a13ac61aaae93759345697bb438a00edab92e0b7b62414683", "0x8022a959a513cdc0e9c705e0fc04eafd05ff37c867ae0f31f6d01cddd5df86138a426cab2ff0ac8ff03a62e20f7e8f51", "0x914e9a38829834c7360443b8ed86137e6f936389488eccf05b4b4db7c9425611705076ecb3f27105d24b85c852be7511", "0x957fb10783e2bd0db1ba66b18e794df710bc3b2b05776be146fa5863c15b1ebdd39747b1a95d9564e1772cdfc4f37b8a", "0xb6307028444daed8ed785ac9d0de76bc3fe23ff2cc7e48102553613bbfb5afe0ebe45e4212a27021c8eb870721e62a1f", "0x8f76143597777d940b15a01b39c5e1b045464d146d9a30a6abe8b5d3907250e6c7f858ff2308f8591e8b0a7b3f3c568a", "0x96163138ac0ce5fd00ae9a289648fd9300a0ca0f63a88481d703ecd281c06a52a3b5178e849e331f9c85ca4ba398f4cc", "0xa63ef47c3e18245b0482596a09f488a716df3cbd0f9e5cfabed0d742843e65db8961c556f45f49762f3a6ac8b627b3ef", "0x8cb595466552e7c4d42909f232d4063e0a663a8ef6f6c9b7ce3a0542b2459cde04e0e54c7623d404acb5b82775ac04f6", "0xb47fe69960eb45f399368807cff16d941a5a4ebad1f5ec46e3dc8a2e4d598a7e6114d8f0ca791e9720fd786070524e2b", "0x89eb5ff83eea9df490e5beca1a1fbbbbcf7184a37e2c8c91ede7a1e654c81e8cd41eceece4042ea7918a4f4646b67fd6", "0xa84f5d155ed08b9054eecb15f689ba81e44589e6e7207a99790c598962837ca99ec12344105b16641ca91165672f7153", "0xa6cc8f25c2d5b2d2f220ec359e6a37a52b95fa6af6e173c65e7cd55299eff4aa9e6d9e6f2769e6459313f1f2aecb0fab", "0xafcde944411f017a9f7979755294981e941cc41f03df5e10522ef7c7505e5f1babdd67b3bf5258e8623150062eb41d9b", "0x8fab39f39c0f40182fcd996ade2012643fe7731808afbc53f9b26900b4d4d1f0f5312d9d40b3df8baa4739970a49c732", "0xae193af9726da0ebe7df1f9ee1c4846a5b2a7621403baf8e66c66b60f523e719c30c6b4f897bb14b27d3ff3da8392eeb", "0x8ac5adb82d852eba255764029f42e6da92dcdd0e224d387d1ef94174038db9709ac558d90d7e7c57ad4ce7f89bbfc38c", "0xa2066b3458fdf678ee487a55dd5bfb74fde03b54620cb0e25412a89ee28ad0d685e309a51e3e4694be2fa6f1593a344c", "0x88d031745dd0ae07d61a15b594be5d4b2e2a29e715d081649ad63605e3404b0c3a5353f0fd9fad9c05c18e93ce674fa1", "0x8283cfb0ef743a043f2b77ecaeba3005e2ca50435585b5dd24777ee6bce12332f85e21b446b536da38508807f0f07563", "0xb376de22d5f6b0af0b59f7d9764561f4244cf8ffe22890ecd3dcf2ff1832130c9b821e068c9d8773136f4796721e5963", "0xae3afc50c764f406353965363840bf28ee85e7064eb9d5f0bb3c31c64ab10f48c853e942ee2c9b51bae59651eaa08c2f", "0x948b204d103917461a01a6c57a88f2d66b476eae5b00be20ec8c747650e864bc8a83aee0aff59cb7584b7a3387e0ee48", "0x81ab098a082b07f896c5ffd1e4446cb7fb44804cbbf38d125208b233fc82f8ec9a6a8d8dd1c9a1162dc28ffeec0dde50", "0xa149c6f1312821ced2969268789a3151bdda213451760b397139a028da609c4134ac083169feb0ee423a0acafd10eceb", "0xb0ac9e27a5dadaf523010f730b28f0ebac01f460d3bbbe277dc9d44218abb5686f4fac89ae462682fef9edbba663520a", "0x8d0e0073cca273daaaa61b6fc54bfe5a009bc3e20ae820f6c93ba77b19eca517d457e948a2de5e77678e4241807157cb", "0xad61d3a2edf7c7533a04964b97499503fd8374ca64286dba80465e68fe932e96749b476f458c6fc57cb1a7ca85764d11", "0x90eb5e121ae46bc01a30881eaa556f46bd8457a4e80787cf634aab355082de34ac57d7f497446468225f7721e68e2a47", "0x8cdac557de7c42d1f3780e33dec1b81889f6352279be81c65566cdd4952d4c15d79e656cbd46035ab090b385e90245ef", "0x82b67e61b88b84f4f4d4f65df37b3e3dcf8ec91ea1b5c008fdccd52da643adbe6468a1cfdb999e87d195afe2883a3b46", "0x8503b467e8f5d6048a4a9b78496c58493a462852cab54a70594ae3fd064cfd0deb4b8f336a262155d9fedcaa67d2f6fd", "0x8db56c5ac763a57b6ce6832930c57117058e3e5a81532b7d19346346205e2ec614eb1a2ee836ef621de50a7bc9b7f040", "0xad344699198f3c6e8c0a3470f92aaffc805b76266734414c298e10b5b3797ca53578de7ccb2f458f5e0448203f55282b", "0x80602032c43c9e2a09154cc88b83238343b7a139f566d64cb482d87436b288a98f1ea244fd3bff8da3c398686a900c14", "0xa6385bd50ecd548cfb37174cdbb89e10025b5cadaf3cff164c95d7aef5a33e3d6a9bf0c681b9e11db9ef54ebeee2a0c1", "0xabf2d95f4aa34b0581eb9257a0cc8462b2213941a5deb8ba014283293e8b36613951b61261cc67bbd09526a54cbbff76", "0xa3d5de52f48df72c289ff713e445991f142390798cd42bd9d9dbefaee4af4f5faf09042d126b975cf6b98711c3072553", "0x8e627302ff3d686cff8872a1b7c2a57b35f45bf2fc9aa42b049d8b4d6996a662b8e7cbac6597f0cb79b0cc4e29fbf133", "0x8510702e101b39a1efbf4e504e6123540c34b5689645e70d0bac1ecc1baf47d86c05cef6c4317a4e99b4edaeb53f2d00", "0xaa173f0ecbcc6088f878f8726d317748c81ebf501bba461f163b55d66099b191ec7c55f7702f351a9c8eb42cfa3280e2", "0xb560a697eafab695bcef1416648a0a664a71e311ecbe5823ae903bd0ed2057b9d7574b9a86d3fe22aa3e6ddce38ea513", "0x8df6304a3d9cf40100f3f687575419c998cd77e5cc27d579cf4f8e98642de3609af384a0337d145dd7c5635172d26a71", "0x8105c7f3e4d30a29151849673853b457c1885c186c132d0a98e63096c3774bc9deb956cf957367e633d0913680bda307", "0x95373fc22c0917c3c2044ac688c4f29a63ed858a45c0d6d2d0fe97afd6f532dcb648670594290c1c89010ecc69259bef", "0x8c2fae9bcadab341f49b55230310df93cac46be42d4caa0d42e45104148a91e527af1b4209c0d972448162aed28fab64", "0xb05a77baab70683f76209626eaefdda2d36a0b66c780a20142d23c55bd479ddd4ad95b24579384b6cf62c8eb4c92d021", "0x8e6bc6a7ea2755b4aaa19c1c1dee93811fcde514f03485fdc3252f0ab7f032c315614f6336e57cea25dcfb8fb6084eeb", "0xb656a27d06aade55eadae2ad2a1059198918ea6cc3fd22c0ed881294d34d5ac7b5e4700cc24350e27d76646263b223aa", "0xa296469f24f6f56da92d713afcd4dd606e7da1f79dc4e434593c53695847eefc81c7c446486c4b3b8c8d00c90c166f14", "0x87a326f57713ac2c9dffeb3af44b9f3c613a8f952676fc46343299122b47ee0f8d792abaa4b5db6451ced5dd153aabd0", "0xb689e554ba9293b9c1f6344a3c8fcb6951d9f9eac4a2e2df13de021aade7c186be27500e81388e5b8bcab4c80f220a31", "0x87ae0aa0aa48eac53d1ca5a7b93917de12db9e40ceabf8fdb40884ae771cfdf095411deef7c9f821af0b7070454a2608", "0xa71ffa7eae8ace94e6c3581d4cb2ad25d48cbd27edc9ec45baa2c8eb932a4773c3272b2ffaf077b40f76942a1f3af7f2", "0x94c218c91a9b73da6b7a495b3728f3028df8ad9133312fc0c03e8c5253b7ccb83ed14688fd4602e2fd41f29a0bc698bd", "0xae1e77b90ca33728af07a4c03fb2ef71cd92e2618e7bf8ed4d785ce90097fc4866c29999eb84a6cf1819d75285a03af2", "0xb7a5945b277dab9993cf761e838b0ac6eaa903d7111fca79f9fde3d4285af7a89bf6634a71909d095d7619d913972c9c", "0x8c43b37be02f39b22029b20aca31bff661abce4471dca88aa3bddefd9c92304a088b2dfc8c4795acc301ca3160656af2", "0xb32e5d0fba024554bd5fe8a793ebe8003335ddd7f585876df2048dcf759a01285fecb53daae4950ba57f3a282a4d8495", "0x85ea7fd5e10c7b659df5289b2978b2c89e244f269e061b9a15fcab7983fc1962b63546e82d5731c97ec74b6804be63ef", "0x96b89f39181141a7e32986ac02d7586088c5a9662cec39843f397f3178714d02f929af70630c12cbaba0268f8ba2d4fa", "0x929ab1a2a009b1eb37a2817c89696a06426529ebe3f306c586ab717bd34c35a53eca2d7ddcdef36117872db660024af9", "0xa696dccf439e9ca41511e16bf3042d7ec0e2f86c099e4fc8879d778a5ea79e33aa7ce96b23dc4332b7ba26859d8e674d", "0xa8fe69a678f9a194b8670a41e941f0460f6e2dbc60470ab4d6ae2679cc9c6ce2c3a39df2303bee486dbfde6844e6b31a", "0x95f58f5c82de2f2a927ca99bf63c9fc02e9030c7e46d0bf6b67fe83a448d0ae1c99541b59caf0e1ccab8326231af09a5", "0xa57badb2c56ca2c45953bd569caf22968f76ed46b9bac389163d6fe22a715c83d5e94ae8759b0e6e8c2f27bff7748f3f", "0x868726fd49963b24acb5333364dffea147e98f33aa19c7919dc9aca0fd26661cfaded74ede7418a5fadbe7f5ae67b67b", "0xa8d8550dcc64d9f1dd7bcdab236c4122f2b65ea404bb483256d712c7518f08bb028ff8801f1da6aed6cbfc5c7062e33b", "0x97e25a87dae23155809476232178538d4bc05d4ff0882916eb29ae515f2a62bfce73083466cc0010ca956aca200aeacc", "0xb4ea26be3f4bd04aa82d7c4b0913b97bcdf5e88b76c57eb1a336cbd0a3eb29de751e1bc47c0e8258adec3f17426d0c71", "0x99ee555a4d9b3cf2eb420b2af8e3bc99046880536116d0ce7193464ac40685ef14e0e3c442f604e32f8338cb0ef92558", "0x8c64efa1da63cd08f319103c5c7a761221080e74227bbc58b8fb35d08aa42078810d7af3e60446cbaff160c319535648", "0x8d9fd88040076c28420e3395cbdfea402e4077a3808a97b7939d49ecbcf1418fe50a0460e1c1b22ac3f6e7771d65169a", "0xae3c19882d7a9875d439265a0c7003c8d410367627d21575a864b9cb4918de7dbdb58a364af40c5e045f3df40f95d337", "0xb4f7bfacab7b2cafe393f1322d6dcc6f21ffe69cd31edc8db18c06f1a2b512c27bd0618091fd207ba8df1808e9d45914", "0x94f134acd0007c623fb7934bcb65ef853313eb283a889a3ffa79a37a5c8f3665f3d5b4876bc66223610c21dc9b919d37", "0xaa15f74051171daacdc1f1093d3f8e2d13da2833624b80a934afec86fc02208b8f55d24b7d66076444e7633f46375c6a", "0xa32d6bb47ef9c836d9d2371807bafbbbbb1ae719530c19d6013f1d1f813c49a60e4fa51d83693586cba3a840b23c0404", "0xb61b3599145ea8680011aa2366dc511a358b7d67672d5b0c5be6db03b0efb8ca5a8294cf220ea7409621f1664e00e631", "0x859cafc3ee90b7ececa1ed8ef2b2fc17567126ff10ca712d5ffdd16aa411a5a7d8d32c9cab1fbf63e87dce1c6e2f5f53", "0xa2fef1b0b2874387010e9ae425f3a9676d01a095d017493648bcdf3b31304b087ccddb5cf76abc4e1548b88919663b6b", "0x939e18c73befc1ba2932a65ede34c70e4b91e74cc2129d57ace43ed2b3af2a9cc22a40fbf50d79a63681b6d98852866d", "0xb3b4259d37b1b14aee5b676c9a0dd2d7f679ab95c120cb5f09f9fbf10b0a920cb613655ddb7b9e2ba5af4a221f31303c", "0x997255fe51aaca6e5a9cb3359bcbf25b2bb9e30649bbd53a8a7c556df07e441c4e27328b38934f09c09d9500b5fabf66", "0xabb91be2a2d860fd662ed4f1c6edeefd4da8dc10e79251cf87f06029906e7f0be9b486462718f0525d5e049472692cb7", "0xb2398e593bf340a15f7801e1d1fbda69d93f2a32a889ec7c6ae5e8a37567ac3e5227213c1392ee86cfb3b56ec2787839", "0x8ddf10ccdd72922bed36829a36073a460c2118fc7a56ff9c1ac72581c799b15c762cb56cb78e3d118bb9f6a7e56cb25e", "0x93e6bc0a4708d16387cacd44cf59363b994dc67d7ada7b6d6dbd831c606d975247541b42b2a309f814c1bfe205681fc6", "0xb93fc35c05998cffda2978e12e75812122831523041f10d52f810d34ff71944979054b04de0117e81ddf5b0b4b3e13c0", "0x92221631c44d60d68c6bc7b287509f37ee44cbe5fdb6935cee36b58b17c7325098f98f7910d2c3ca5dc885ad1d6dabc7", "0xa230124424a57fad3b1671f404a94d7c05f4c67b7a8fbacfccea28887b78d7c1ed40b92a58348e4d61328891cd2f6cee", "0xa6a230edb8518a0f49d7231bc3e0bceb5c2ac427f045819f8584ba6f3ae3d63ed107a9a62aad543d7e1fcf1f20605706", "0x845be1fe94223c7f1f97d74c49d682472585d8f772762baad8a9d341d9c3015534cc83d102113c51a9dea2ab10d8d27b", "0xb44262515e34f2db597c8128c7614d33858740310a49cdbdf9c8677c5343884b42c1292759f55b8b4abc4c86e4728033", "0x805592e4a3cd07c1844bc23783408310accfdb769cca882ad4d07d608e590a288b7370c2cb327f5336e72b7083a0e30f", "0x95153e8b1140df34ee864f4ca601cb873cdd3efa634af0c4093fbaede36f51b55571ab271e6a133020cd34db8411241f", "0x82878c1285cfa5ea1d32175c9401f3cc99f6bb224d622d3fd98cc7b0a27372f13f7ab463ce3a33ec96f9be38dbe2dfe3", "0xb7588748f55783077c27fc47d33e20c5c0f5a53fc0ac10194c003aa09b9f055d08ec971effa4b7f760553997a56967b3", "0xb36b4de6d1883b6951f59cfae381581f9c6352fcfcf1524fccdab1571a20f80441d9152dc6b48bcbbf00371337ca0bd5", "0x89c5523f2574e1c340a955cbed9c2f7b5fbceb260cb1133160dabb7d41c2f613ec3f6e74bbfab3c4a0a6f0626dbe068f", "0xa52f58cc39f968a9813b1a8ddc4e83f4219e4dd82c7aa1dd083bea7edf967151d635aa9597457f879771759b876774e4", "0x8300a67c2e2e123f89704abfde095463045dbd97e20d4c1157bab35e9e1d3d18f1f4aaba9cbe6aa2d544e92578eaa1b6", "0xac6a7f2918768eb6a43df9d3a8a04f8f72ee52f2e91c064c1c7d75cad1a3e83e5aba9fe55bb94f818099ac91ccf2e961", "0x8d64a2b0991cf164e29835c8ddef6069993a71ec2a7de8157bbfa2e00f6367be646ed74cbaf524f0e9fe13fb09fa15fd", "0x8b2ffe5a545f9f680b49d0a9797a4a11700a2e2e348c34a7a985fc278f0f12def6e06710f40f9d48e4b7fbb71e072229", "0x8ab8f71cd337fa19178924e961958653abf7a598e3f022138b55c228440a2bac4176cea3aea393549c03cd38a13eb3fc", "0x8419d28318c19ea4a179b7abb43669fe96347426ef3ac06b158d79c0acf777a09e8e770c2fb10e14b3a0421705990b23", "0x8bacdac310e1e49660359d0a7a17fe3d334eb820e61ae25e84cb52f863a2f74cbe89c2e9fc3283745d93a99b79132354", "0xb57ace3fa2b9f6b2db60c0d861ace7d7e657c5d35d992588aeed588c6ce3a80b6f0d49f8a26607f0b17167ab21b675e4", "0x83e265cde477f2ecc164f49ddc7fb255bb05ff6adc347408353b7336dc3a14fdedc86d5a7fb23f36b8423248a7a67ed1", "0xa60ada971f9f2d79d436de5d3d045f5ab05308cae3098acaf5521115134b2a40d664828bb89895840db7f7fb499edbc5", "0xa63eea12efd89b62d3952bf0542a73890b104dd1d7ff360d4755ebfa148fd62de668edac9eeb20507967ea37fb220202", "0xa0275767a270289adc991cc4571eff205b58ad6d3e93778ddbf95b75146d82517e8921bd0d0564e5b75fa0ccdab8e624", "0xb9b03fd3bf07201ba3a039176a965d736b4ef7912dd9e9bf69fe1b57c330a6aa170e5521fe8be62505f3af81b41d7806", "0xa95f640e26fb1106ced1729d6053e41a16e4896acac54992279ff873e5a969aad1dcfa10311e28b8f409ac1dab7f03bb", "0xb144778921742418053cb3c70516c63162c187f00db2062193bb2c14031075dbe055d020cde761b26e8c58d0ea6df2c1", "0x8432fbb799e0435ef428d4fefc309a05dd589bce74d7a87faf659823e8c9ed51d3e42603d878e80f439a38be4321c2fa", "0xb08ddef14e42d4fd5d8bf39feb7485848f0060d43b51ed5bdda39c05fe154fb111d29719ee61a23c392141358c0cfcff", "0x8ae3c5329a5e025b86b5370e06f5e61177df4bda075856fade20a17bfef79c92f54ed495f310130021ba94fb7c33632b", "0x92b6d3c9444100b4d7391febfc1dddaa224651677c3695c47a289a40d7a96d200b83b64e6d9df51f534564f272a2c6c6", "0xb432bc2a3f93d28b5e506d68527f1efeb2e2570f6be0794576e2a6ef9138926fdad8dd2eabfa979b79ab7266370e86bc", "0x8bc315eacedbcfc462ece66a29662ca3dcd451f83de5c7626ef8712c196208fb3d8a0faf80b2e80384f0dd9772f61a23", "0xa72375b797283f0f4266dec188678e2b2c060dfed5880fc6bb0c996b06e91a5343ea2b695adaab0a6fd183b040b46b56", "0xa43445036fbaa414621918d6a897d3692fdae7b2961d87e2a03741360e45ebb19fcb1703d23f1e15bb1e2babcafc56ac", "0xb9636b2ffe305e63a1a84bd44fb402442b1799bd5272638287aa87ca548649b23ce8ce7f67be077caed6aa2dbc454b78", "0x99a30bf0921d854c282b83d438a79f615424f28c2f99d26a05201c93d10378ab2cd94a792b571ddae5d4e0c0013f4006", "0x8648e3c2f93d70b392443be116b48a863e4b75991bab5db656a4ef3c1e7f645e8d536771dfe4e8d1ceda3be8d32978b0", "0xab50dc9e6924c1d2e9d2e335b2d679fc7d1a7632e84964d3bac0c9fe57e85aa5906ec2e7b0399d98ddd022e9b19b5904", "0xab729328d98d295f8f3272afaf5d8345ff54d58ff9884da14f17ecbdb7371857fdf2f3ef58080054e9874cc919b46224", "0x83fa5da7592bd451cad3ad7702b4006332b3aae23beab4c4cb887fa6348317d234bf62a359e665b28818e5410c278a09", "0x8bdbff566ae9d368f114858ef1f009439b3e9f4649f73efa946e678d6c781d52c69af195df0a68170f5f191b2eac286b", "0x91245e59b4425fd4edb2a61d0d47c1ccc83d3ced8180de34887b9655b5dcda033d48cde0bdc3b7de846d246c053a02e8", "0xa2cb00721e68f1cad8933947456f07144dc69653f96ceed845bd577d599521ba99cdc02421118971d56d7603ed118cbf", "0xaf8cd66d303e808b22ec57860dd909ca64c27ec2c60e26ffecfdc1179d8762ffd2739d87b43959496e9fee4108df71df", "0x9954136812dffcd5d3f167a500e7ab339c15cfc9b3398d83f64b0daa3dd5b9a851204f424a3493b4e326d3de81e50a62", "0x93252254d12511955f1aa464883ad0da793f84d900fea83e1df8bca0f2f4cf5b5f9acbaec06a24160d33f908ab5fea38", "0x997cb55c26996586ba436a95566bd535e9c22452ca5d2a0ded2bd175376557fa895f9f4def4519241ff386a063f2e526", "0xa12c78ad451e0ac911260ade2927a768b50cb4125343025d43474e7f465cdc446e9f52a84609c5e7e87ae6c9b3f56cda", "0xa789d4ca55cbba327086563831b34487d63d0980ba8cf55197c016702ed6da9b102b1f0709ce3da3c53ff925793a3d73", "0xa5d76acbb76741ce85be0e655b99baa04f7f587347947c0a30d27f8a49ae78cce06e1cde770a8b618d3db402be1c0c4b", "0x873c0366668c8faddb0eb7c86f485718d65f8c4734020f1a18efd5fa123d3ea8a990977fe13592cd01d17e60809cb5ff", "0xb659b71fe70f37573ff7c5970cc095a1dc0da3973979778f80a71a347ef25ad5746b2b9608bad4ab9a4a53a4d7df42d7", "0xa34cbe05888e5e5f024a2db14cb6dcdc401a9cbd13d73d3c37b348f68688f87c24ca790030b8f84fef9e74b4eab5e412", "0x94ce8010f85875c045b0f014db93ef5ab9f1f6842e9a5743dce9e4cb872c94affd9e77c1f1d1ab8b8660b52345d9acb9", "0xadefa9b27a62edc0c5b019ddd3ebf45e4de846165256cf6329331def2e088c5232456d3de470fdce3fa758bfdd387512", "0xa6b83821ba7c1f83cc9e4529cf4903adb93b26108e3d1f20a753070db072ad5a3689643144bdd9c5ea06bb9a7a515cd0", "0xa3a9ddedc2a1b183eb1d52de26718151744db6050f86f3580790c51d09226bf05f15111691926151ecdbef683baa992c", "0xa64bac89e7686932cdc5670d07f0b50830e69bfb8c93791c87c7ffa4913f8da881a9d8a8ce8c1a9ce5b6079358c54136", "0xa77b5a63452cb1320b61ab6c7c2ef9cfbcade5fd4727583751fb2bf3ea330b5ca67757ec1f517bf4d503ec924fe32fbd", "0x8746fd8d8eb99639d8cd0ca34c0d9c3230ed5a312aab1d3d925953a17973ee5aeb66e68667e93caf9cb817c868ea8f3d", "0x88a2462a26558fc1fbd6e31aa8abdc706190a17c27fdc4217ffd2297d1b1f3321016e5c4b2384c5454d5717dc732ed03", "0xb78893a97e93d730c8201af2e0d3b31cb923d38dc594ffa98a714e627c473d42ea82e0c4d2eeb06862ee22a9b2c54588", "0x920cc8b5f1297cf215a43f6fc843e379146b4229411c44c0231f6749793d40f07b9af7699fd5d21fd69400b97febe027", "0xa0f0eafce1e098a6b58c7ad8945e297cd93aaf10bc55e32e2e32503f02e59fc1d5776936577d77c0b1162cb93b88518b", "0x98480ba0064e97a2e7a6c4769b4d8c2a322cfc9a3b2ca2e67e9317e2ce04c6e1108169a20bd97692e1cb1f1423b14908", "0x83dbbb2fda7e287288011764a00b8357753a6a44794cc8245a2275237f11affdc38977214e463ad67aec032f3dfa37e9", "0x86442fff37598ce2b12015ff19b01bb8a780b40ad353d143a0f30a06f6d23afd5c2b0a1253716c855dbf445cc5dd6865", "0xb8a4c60c5171189414887847b9ed9501bff4e4c107240f063e2d254820d2906b69ef70406c585918c4d24f1dd052142b", "0x919f33a98e84015b2034b57b5ffe9340220926b2c6e45f86fd79ec879dbe06a148ae68b77b73bf7d01bd638a81165617", "0x95c13e78d89474a47fbc0664f6f806744b75dede95a479bbf844db4a7f4c3ae410ec721cb6ffcd9fa9c323da5740d5ae", "0xab7151acc41fffd8ec6e90387700bcd7e1cde291ea669567295bea1b9dd3f1df2e0f31f3588cd1a1c08af8120aca4921", "0x80e74c5c47414bd6eeef24b6793fb1fa2d8fb397467045fcff887c52476741d5bc4ff8b6d3387cb53ad285485630537f", "0xa296ad23995268276aa351a7764d36df3a5a3cffd7dbeddbcea6b1f77adc112629fdeffa0918b3242b3ccd5e7587e946", "0x813d2506a28a2b01cb60f49d6bd5e63c9b056aa56946faf2f33bd4f28a8d947569cfead3ae53166fc65285740b210f86", "0x924b265385e1646287d8c09f6c855b094daaee74b9e64a0dddcf9ad88c6979f8280ba30c8597b911ef58ddb6c67e9fe3", "0x8d531513c70c2d3566039f7ca47cd2352fd2d55b25675a65250bdb8b06c3843db7b2d29c626eed6391c238fc651cf350", "0x82b338181b62fdc81ceb558a6843df767b6a6e3ceedc5485664b4ea2f555904b1a45fbb35f6cf5d96f27da10df82a325", "0x92e62faaedea83a37f314e1d3cb4faaa200178371d917938e59ac35090be1db4b4f4e0edb78b9c991de202efe4f313d8", "0x99d645e1b642c2dc065bac9aaa0621bc648c9a8351efb6891559c3a41ba737bd155fb32d7731950514e3ecf4d75980e4", "0xb34a13968b9e414172fb5d5ece9a39cf2eb656128c3f2f6cc7a9f0c69c6bae34f555ecc8f8837dc34b5e470e29055c78", "0xa2a0bb7f3a0b23a2cbc6585d59f87cd7e56b2bbcb0ae48f828685edd9f7af0f5edb4c8e9718a0aaf6ef04553ba71f3b7", "0x8e1a94bec053ed378e524b6685152d2b52d428266f2b6eadd4bcb7c4e162ed21ab3e1364879673442ee2162635b7a4d8", "0x9944adaff14a85eab81c73f38f386701713b52513c4d4b838d58d4ffa1d17260a6d056b02334850ea9a31677c4b078bd", "0xa450067c7eceb0854b3eca3db6cf38669d72cb7143c3a68787833cbca44f02c0be9bfbe082896f8a57debb13deb2afb1", "0x8be4ad3ac9ef02f7df09254d569939757101ee2eda8586fefcd8c847adc1efe5bdcb963a0cafa17651befaafb376a531", "0x90f6de91ea50255f148ac435e08cf2ac00c772a466e38155bd7e8acf9197af55662c7b5227f88589b71abe9dcf7ba343", "0x86e5a24f0748b106dee2d4d54e14a3b0af45a96cbee69cac811a4196403ebbee17fd24946d7e7e1b962ac7f66dbaf610", "0xafdd96fbcda7aa73bf9eeb2292e036c25753d249caee3b9c013009cc22e10d3ec29e2aa6ddbb21c4e949b0c0bccaa7f4", "0xb5a4e7436d5473647c002120a2cb436b9b28e27ad4ebdd7c5f122b91597c507d256d0cbd889d65b3a908531936e53053", "0xb632414c3da704d80ac2f3e5e0e9f18a3637cdc2ebeb613c29300745582427138819c4e7b0bec3099c1b8739dac1807b", "0xa28df1464d3372ce9f37ef1db33cc010f752156afae6f76949d98cd799c0cf225c20228ae86a4da592d65f0cffe3951b", "0x898b93d0a31f7d3f11f253cb7a102db54b669fd150da302d8354d8e02b1739a47cb9bd88015f3baf12b00b879442464e", "0x96fb88d89a12049091070cb0048a381902965e67a8493e3991eaabe5d3b7ff7eecd5c94493a93b174df3d9b2c9511755", "0xb899cb2176f59a5cfba3e3d346813da7a82b03417cad6342f19cc8f12f28985b03bf031e856a4743fd7ebe16324805b0", "0xa60e2d31bc48e0c0579db15516718a03b73f5138f15037491f4dae336c904e312eda82d50862f4debd1622bb0e56d866", "0x979fc8b987b5cef7d4f4b58b53a2c278bd25a5c0ea6f41c715142ea5ff224c707de38451b0ad3aa5e749aa219256650a", "0xb2a75bff18e1a6b9cf2a4079572e41205741979f57e7631654a3c0fcec57c876c6df44733c9da3d863db8dff392b44a3", "0xb7a0f0e811222c91e3df98ff7f286b750bc3b20d2083966d713a84a2281744199e664879401e77470d44e5a90f3e5181", "0x82b74ba21c9d147fbc338730e8f1f8a6e7fc847c3110944eb17a48bea5e06eecded84595d485506d15a3e675fd0e5e62", "0xa7f44eef817d5556f0d1abcf420301217d23c69dd2988f44d91ea1f1a16c322263cbacd0f190b9ba22b0f141b9267b4f", "0xaadb68164ede84fc1cb3334b3194d84ba868d5a88e4c9a27519eef4923bc4abf81aab8114449496c073c2a6a0eb24114", "0xb5378605fabe9a8c12a5dc55ef2b1de7f51aedb61960735c08767a565793cea1922a603a6983dc25f7cea738d0f7c40d", "0xa97a4a5cd8d51302e5e670aee78fe6b5723f6cc892902bbb4f131e82ca1dfd5de820731e7e3367fb0c4c1922a02196e3", "0x8bdfeb15c29244d4a28896f2b2cb211243cd6a1984a3f5e3b0ebe5341c419beeab3304b390a009ffb47588018034b0ea", "0xa9af3022727f2aa2fca3b096968e97edad3f08edcbd0dbca107b892ae8f746a9c0485e0d6eb5f267999b23a845923ed0", "0x8e7594034feef412f055590fbb15b6322dc4c6ab7a4baef4685bd13d71a83f7d682b5781bdfa0d1c659489ce9c2b8000", "0x84977ca6c865ebee021c58106c1a4ad0c745949ecc5332948002fd09bd9b890524878d0c29da96fd11207621136421fe", "0x8687551a79158e56b2375a271136756313122132a6670fa51f99a1b5c229ed8eea1655a734abae13228b3ebfd2a825dd", "0xa0227d6708979d99edfc10f7d9d3719fd3fc68b0d815a7185b60307e4c9146ad2f9be2b8b4f242e320d4288ceeb9504c", "0x89f75583a16735f9dd8b7782a130437805b34280ccea8dac6ecaee4b83fe96947e7b53598b06fecfffdf57ffc12cc445", "0xa0056c3353227f6dd9cfc8e3399aa5a8f1d71edf25d3d64c982910f50786b1e395c508d3e3727ac360e3e040c64b5298", "0xb070e61a6d813626144b312ded1788a6d0c7cec650a762b2f8df6e4743941dd82a2511cd956a3f141fc81e15f4e092da", "0xb4e6db232e028a1f989bb5fc13416711f42d389f63564d60851f009dcffac01acfd54efa307aa6d4c0f932892d4e62b0", "0x89b5991a67db90024ddd844e5e1a03ef9b943ad54194ae0a97df775dde1addf31561874f4e40fbc37a896630f3bbda58", "0xad0e8442cb8c77d891df49cdb9efcf2b0d15ac93ec9be1ad5c3b3cca1f4647b675e79c075335c1f681d56f14dc250d76", "0xb5d55a6ae65bb34dd8306806cb49b5ccb1c83a282ee47085cf26c4e648e19a52d9c422f65c1cd7e03ca63e926c5e92ea", "0xb749501347e5ec07e13a79f0cb112f1b6534393458b3678a77f02ca89dca973fa7b30e55f0b25d8b92b97f6cb0120056", "0x94144b4a3ffc5eec6ba35ce9c245c148b39372d19a928e236a60e27d7bc227d18a8cac9983851071935d8ffb64b3a34f", "0x92bb4f9f85bc8c028a3391306603151c6896673135f8a7aefedd27acb322c04ef5dac982fc47b455d6740023e0dd3ea3", "0xb9633a4a101461a782fc2aa092e9dbe4e2ad00987578f18cd7cf0021a909951d60fe79654eb7897806795f93c8ff4d1c", "0x809f0196753024821b48a016eca5dbb449a7c55750f25981bb7a4b4c0e0846c09b8f6128137905055fc43a3f0deb4a74", "0xa27dc9cdd1e78737a443570194a03d89285576d3d7f3a3cf15cc55b3013e42635d4723e2e8fe1d0b274428604b630db9", "0x861f60f0462e04cd84924c36a28163def63e777318d00884ab8cb64c8df1df0bce5900342163edb60449296484a6c5bf", "0xb7bc23fb4e14af4c4704a944253e760adefeca8caee0882b6bbd572c84434042236f39ae07a8f21a560f486b15d82819", "0xb9a6eb492d6dd448654214bd01d6dc5ff12067a11537ab82023fc16167507ee25eed2c91693912f4155d1c07ed9650b3", "0x97678af29c68f9a5e213bf0fb85c265303714482cfc4c2c00b4a1e8a76ed08834ee6af52357b143a1ca590fb0265ea5a", "0x8a15b499e9eca5b6cac3070b5409e8296778222018ad8b53a5d1f6b70ad9bb10c68a015d105c941ed657bf3499299e33", "0xb487fefede2e8091f2c7bfe85770db2edff1db83d4effe7f7d87bff5ab1ace35e9b823a71adfec6737fede8d67b3c467", "0x8b51b916402aa2c437fce3bcad6dad3be8301a1a7eab9d163085b322ffb6c62abf28637636fe6114573950117fc92898", "0xb06a2106d031a45a494adec0881cb2f82275dff9dcdd2bc16807e76f3bec28a6734edd3d54f0be8199799a78cd6228ad", "0xaf0a185391bbe2315eb97feac98ad6dd2e5d931d012c621abd6e404a31cc188b286fef14871762190acf086482b2b5e2", "0x8e78ee8206506dd06eb7729e32fceda3bebd8924a64e4d8621c72e36758fda3d0001af42443851d6c0aea58562870b43", "0xa1ba52a569f0461aaf90b49b92be976c0e73ec4a2c884752ee52ffb62dd137770c985123d405dfb5de70692db454b54a", "0x8d51b692fa1543c51f6b62b9acb8625ed94b746ef96c944ca02859a4133a5629da2e2ce84e111a7af8d9a5b836401c64", "0xa7a20d45044cf6492e0531d0b8b26ffbae6232fa05a96ed7f06bdb64c2b0f5ca7ec59d5477038096a02579e633c7a3ff", "0x84df867b98c53c1fcd4620fef133ee18849c78d3809d6aca0fb6f50ff993a053a455993f216c42ab6090fa5356b8d564", "0xa7227c439f14c48e2577d5713c97a5205feb69acb0b449152842e278fa71e8046adfab468089c8b2288af1fc51fa945b", "0x855189b3a105670779997690876dfaa512b4a25a24931a912c2f0f1936971d2882fb4d9f0b3d9daba77eaf660e9d05d5", "0xb5696bd6706de51c502f40385f87f43040a5abf99df705d6aac74d88c913b8ecf7a99a63d7a37d9bdf3a941b9e432ff5", "0xab997beb0d6df9c98d5b49864ef0b41a2a2f407e1687dfd6089959757ba30ed02228940b0e841afe6911990c74d536c4", "0xb36b65f85546ebfdbe98823d5555144f96b4ab39279facd19c0de3b8919f105ba0315a0784dce4344b1bc62d8bb4a5a3", "0xb8371f0e4450788720ac5e0f6cd3ecc5413d33895083b2c168d961ec2b5c3de411a4cc0712481cbe8df8c2fa1a7af006", "0x98325d8026b810a8b7a114171ae59a57e8bbc9848e7c3df992efc523621729fd8c9f52114ce01d7730541a1ada6f1df1", "0x8d0e76dbd37806259486cd9a31bc8b2306c2b95452dc395546a1042d1d17863ef7a74c636b782e214d3aa0e8d717f94a", "0xa4e15ead76da0214d702c859fb4a8accdcdad75ed08b865842bd203391ec4cba2dcc916455e685f662923b96ee0c023f", "0x8618190972086ebb0c4c1b4a6c94421a13f378bc961cc8267a301de7390c5e73c3333864b3b7696d81148f9d4843fd02", "0x85369d6cc7342e1aa15b59141517d8db8baaaeb7ab9670f3ba3905353948d575923d283b7e5a05b13a30e7baf1208a86", "0x87c51ef42233c24a6da901f28c9a075d9ba3c625687c387ad6757b72ca6b5a8885e6902a3082da7281611728b1e45f26", "0xaa6348a4f71927a3106ad0ea8b02fc8d8c65531e4ab0bd0a17243e66f35afe252e40ab8eef9f13ae55a72566ffdaff5c", "0x96a3bc976e9d03765cc3fee275fa05b4a84c94fed6b767e23ca689394501e96f56f7a97cffddc579a6abff632bf153be", "0x97dbf96c6176379fdb2b888be4e757b2bca54e74124bd068d3fa1dbd82a011bbeb75079da38e0cd22a761fe208ecad9b", "0xb70cf0a1d14089a4129ec4e295313863a59da8c7e26bf74cc0e704ed7f0ee4d7760090d0ddf7728180f1bf2c5ac64955", "0x882d664714cc0ffe53cbc9bef21f23f3649824f423c4dbad1f893d22c4687ab29583688699efc4d5101aa08b0c3e267a", "0x80ecb7cc963e677ccaddbe3320831dd6ee41209acf4ed41b16dc4817121a3d86a1aac9c4db3d8c08a55d28257088af32", "0xa25ba667d832b145f9ce18c3f9b1bd00737aa36db020e1b99752c8ef7d27c6c448982bd8d352e1b6df266b8d8358a8d5", "0x83734841c13dee12759d40bdd209b277e743b0d08cc0dd1e0b7afd2d65bfa640400eefcf6be4a52e463e5b3d885eeac6", "0x848d16505b04804afc773aebabb51b36fd8aacfbb0e09b36c0d5d57df3c0a3b92f33e7d5ad0a7006ec46ebb91df42b8c", "0x909a8d793f599e33bb9f1dc4792a507a97169c87cd5c087310bc05f30afcd247470b4b56dec59894c0fb1d48d39bb54e", "0x8e558a8559df84a1ba8b244ece667f858095c50bb33a5381e60fcc6ba586b69693566d8819b4246a27287f16846c1dfa", "0x84d6b69729f5aaa000cd710c2352087592cfbdf20d5e1166977e195818e593fa1a50d1e04566be23163a2523dc1612f1", "0x9536d262b7a42125d89f4f32b407d737ba8d9242acfc99d965913ab3e043dcac9f7072a43708553562cac4cba841df30", "0x9598548923ca119d6a15fd10861596601dd1dedbcccca97bb208cdc1153cf82991ea8cc17686fbaa867921065265970c", "0xb87f2d4af6d026e4d2836bc3d390a4a18e98a6e386282ce96744603bab74974272e97ac2da281afa21885e2cbb3a8001", "0x991ece62bf07d1a348dd22191868372904b9f8cf065ae7aa4e44fd24a53faf6d851842e35fb472895963aa1992894918", "0xa8c53dea4c665b30e51d22ca6bc1bc78aaf172b0a48e64a1d4b93439b053877ec26cb5221c55efd64fa841bbf7d5aff4", "0x93487ec939ed8e740f15335b58617c3f917f72d07b7a369befd479ae2554d04deb240d4a14394b26192efae4d2f4f35d", "0xa44793ab4035443f8f2968a40e043b4555960193ffa3358d22112093aadfe2c136587e4139ffd46d91ed4107f61ea5e0", "0xb13fe033da5f0d227c75927d3dacb06dbaf3e1322f9d5c7c009de75cdcba5e308232838785ab69a70f0bedea755e003f", "0x970a29b075faccd0700fe60d1f726bdebf82d2cc8252f4a84543ebd3b16f91be42a75c9719a39c4096139f0f31393d58", "0xa4c3eb1f7160f8216fc176fb244df53008ff32f2892363d85254002e66e2de21ccfe1f3b1047589abee50f29b9d507e3", "0x8c552885eab04ba40922a8f0c3c38c96089c95ff1405258d3f1efe8d179e39e1295cbf67677894c607ae986e4e6b1fb0", "0xb3671746fa7f848c4e2ae6946894defadd815230b906b419143523cc0597bc1d6c0a4c1e09d49b66b4a2c11cde3a4de3", "0x937a249a95813a5e2ef428e355efd202e15a37d73e56cfb7e57ea9f943f2ce5ca8026f2f1fd25bf164ba89d07077d858", "0x83646bdf6053a04aa9e2f112499769e5bd5d0d10f2e13db3ca89bd45c0b3b7a2d752b7d137fb3909f9c62b78166c9339", "0xb4eac4b91e763666696811b7ed45e97fd78310377ebea1674b58a2250973f80492ac35110ed1240cd9bb2d17493d708c", "0x82db43a99bc6573e9d92a3fd6635dbbb249ac66ba53099c3c0c8c8080b121dd8243cd5c6e36ba0a4d2525bae57f5c89c", "0xa64d6a264a681b49d134c655d5fc7756127f1ee7c93d328820f32bca68869f53115c0d27fef35fe71f7bc4fdaed97348", "0x8739b7a9e2b4bc1831e7f04517771bc7cde683a5e74e052542517f8375a2f64e53e0d5ac925ef722327e7bb195b4d1d9", "0x8f337cdd29918a2493515ebb5cf702bbe8ecb23b53c6d18920cc22f519e276ca9b991d3313e2d38ae17ae8bdfa4f8b7e", "0xb0edeab9850e193a61f138ef2739fc42ceec98f25e7e8403bfd5fa34a7bc956b9d0898250d18a69fa4625a9b3d6129da", "0xa9920f26fe0a6d51044e623665d998745c9eca5bce12051198b88a77d728c8238f97d4196f26e43b24f8841500b998d0", "0x86e655d61502b979eeeeb6f9a7e1d0074f936451d0a1b0d2fa4fb3225b439a3770767b649256fe481361f481a8dbc276", "0x84d3b32fa62096831cc3bf013488a9f3f481dfe293ae209ed19585a03f7db8d961a7a9dd0db82bd7f62d612707575d9c", "0x81c827826ec9346995ffccf62a241e3b2d32f7357acd1b1f8f7a7dbc97022d3eb51b8a1230e23ce0b401d2e535e8cd78", "0x94a1e40c151191c5b055b21e86f32e69cbc751dcbdf759a48580951834b96a1eed75914c0d19a38aefd21fb6c8d43d0c", "0xab890222b44bc21b71f7c75e15b6c6e16bb03371acce4f8d4353ff3b8fcd42a14026589c5ed19555a3e15e4d18bfc3a3", "0xaccb0be851e93c6c8cc64724cdb86887eea284194b10e7a43c90528ed97e9ec71ca69c6fac13899530593756dd49eab2", "0xb630220aa9e1829c233331413ee28c5efe94ea8ea08d0c6bfd781955078b43a4f92915257187d8526873e6c919c6a1de", "0xadd389a4d358c585f1274b73f6c3c45b58ef8df11f9d11221f620e241bf3579fba07427b288c0c682885a700cc1fa28d", "0xa9fe6ca8bf2961a3386e8b8dcecc29c0567b5c0b3bcf3b0f9169f88e372b80151af883871fc5229815f94f43a6f5b2b0", "0xad839ae003b92b37ea431fa35998b46a0afc3f9c0dd54c3b3bf7a262467b13ff3c323ada1c1ae02ac7716528bdf39e3e", "0x9356d3fd0edcbbb65713c0f2a214394f831b26f792124b08c5f26e7f734b8711a87b7c4623408da6a091c9aef1f6af3c", "0x896b25b083c35ac67f0af3784a6a82435b0e27433d4d74cd6d1eafe11e6827827799490fb1c77c11de25f0d75f14e047", "0x8bfa019391c9627e8e5f05c213db625f0f1e51ec68816455f876c7e55b8f17a4f13e5aae9e3fb9e1cf920b1402ee2b40", "0x8ba3a6faa6a860a8f3ce1e884aa8769ceded86380a86520ab177ab83043d380a4f535fe13884346c5e51bee68da6ab41", "0xa8292d0844084e4e3bb7af92b1989f841a46640288c5b220fecfad063ee94e86e13d3d08038ec2ac82f41c96a3bfe14d", "0x8229bb030b2fc566e11fd33c7eab7a1bb7b49fed872ea1f815004f7398cb03b85ea14e310ec19e1f23e0bdaf60f8f76c", "0x8cfbf869ade3ec551562ff7f63c2745cc3a1f4d4dc853a0cd42dd5f6fe54228f86195ea8fe217643b32e9f513f34a545", "0xac52a3c8d3270ddfe1b5630159da9290a5ccf9ccbdef43b58fc0a191a6c03b8a5974cf6e2bbc7bd98d4a40a3581482d7", "0xab13decb9e2669e33a7049b8eca3ca327c40dea15ad6e0e7fa63ed506db1d258bc36ac88b35f65cae0984e937eb6575d", "0xb5e748eb1a7a1e274ff0cc56311c198f2c076fe4b7e73e5f80396fe85358549df906584e6bb2c8195b3e2be7736850a5", "0xb5cb911325d8f963c41f691a60c37831c7d3bbd92736efa33d1f77a22b3fde7f283127256c2f47e197571e6fe0b46149", "0x8a01dc6ed1b55f26427a014faa347130738b191a06b800e32042a46c13f60b49534520214359d68eb2e170c31e2b8672", "0xa72fa874866e19b2efb8e069328362bf7921ec375e3bcd6b1619384c3f7ee980f6cf686f3544e9374ff54b4d17a1629c", "0x8db21092f7c5f110fba63650b119e82f4b42a997095d65f08f8237b02dd66fdf959f788df2c35124db1dbd330a235671", "0x8c65d50433d9954fe28a09fa7ba91a70a590fe7ba6b3060f5e4be0f6cef860b9897fa935fb4ebc42133524eb071dd169", "0xb4614058e8fa21138fc5e4592623e78b8982ed72aa35ee4391b164f00c68d277fa9f9eba2eeefc890b4e86eba5124591", "0xab2ad3a1bce2fbd55ca6b7c23786171fe1440a97d99d6df4d80d07dd56ac2d7203c294b32fc9e10a6c259381a73f24a1", "0x812ae3315fdc18774a8da3713a4679e8ed10b9405edc548c00cacbe25a587d32040566676f135e4723c5dc25df5a22e9", "0xa464b75f95d01e5655b54730334f443c8ff27c3cb79ec7af4b2f9da3c2039c609908cd128572e1fd0552eb597e8cef8d", "0xa0db3172e93ca5138fe419e1c49a1925140999f6eff7c593e5681951ee0ec1c7e454c851782cbd2b8c9bc90d466e90e0", "0x806db23ba7d00b87d544eed926b3443f5f9c60da6b41b1c489fba8f73593b6e3b46ebfcab671ee009396cd77d5e68aa1", "0x8bfdf2c0044cc80260994e1c0374588b6653947b178e8b312be5c2a05e05767e98ea15077278506aee7df4fee1aaf89e", "0x827f6558c16841b5592ff089c9c31e31eb03097623524394813a2e4093ad2d3f8f845504e2af92195aaa8a1679d8d692", "0x925c4f8eab2531135cd71a4ec88e7035b5eea34ba9d799c5898856080256b4a15ed1a746e002552e2a86c9c157e22e83", "0xa9f9a368f0e0b24d00a35b325964c85b69533013f9c2cfad9708be5fb87ff455210f8cb8d2ce3ba58ca3f27495552899", "0x8ac0d3bebc1cae534024187e7c71f8927ba8fcc6a1926cb61c2b6c8f26bb7831019e635a376146c29872a506784a4aaa", "0x97c577be2cbbfdb37ad754fae9df2ada5fc5889869efc7e18a13f8e502fbf3f4067a509efbd46fd990ab47ce9a70f5a8", "0x935e7d82bca19f16614aa43b4a3474e4d20d064e4bfdf1cea2909e5c9ab72cfe3e54dc50030e41ee84f3588cebc524e9", "0x941aafc08f7c0d94cebfbb1f0aad5202c02e6e37f2c12614f57e727efa275f3926348f567107ee6d8914dd71e6060271", "0xaf0fbc1ba05b4b5b63399686df3619968be5d40073de0313cbf5f913d3d4b518d4c249cdd2176468ccaa36040a484f58", "0xa0c414f23f46ca6d69ce74c6f8a00c036cb0edd098af0c1a7d39c802b52cfb2d5dbdf93fb0295453d4646e2af7954d45", "0x909cf39e11b3875bb63b39687ae1b5d1f5a15445e39bf164a0b14691b4ddb39a8e4363f584ef42213616abc4785b5d66", "0xa92bac085d1194fbd1c88299f07a061d0bdd3f980b663e81e6254dbb288bf11478c0ee880e28e01560f12c5ccb3c0103", "0x841705cd5cd76b943e2b7c5e845b9dd3c8defe8ef67e93078d6d5e67ade33ad4b0fd413bc196f93b0a4073c855cd97d4", "0x8e7eb8364f384a9161e81d3f1d52ceca9b65536ae49cc35b48c3e2236322ba4ae9973e0840802d9fa4f4d82ea833544f", "0xaed3ab927548bc8bec31467ba80689c71a168e34f50dcb6892f19a33a099f5aa6b3f9cb79f5c0699e837b9a8c7f27efe", "0xb8fbf7696210a36e20edabd77839f4dfdf50d6d015cdf81d587f90284a9bcef7d2a1ff520728d7cc69a4843d6c20dedd", "0xa9d533769ce6830211c884ae50a82a7bf259b44ac71f9fb11f0296fdb3981e6b4c1753fe744647b247ebc433a5a61436", "0x8b4bdf90d33360b7f428c71cde0a49fb733badba8c726876945f58c620ce7768ae0e98fc8c31fa59d8955a4823336bb1", "0x808d42238e440e6571c59e52a35ae32547d502dc24fd1759d8ea70a7231a95859baf30b490a4ba55fa2f3aaa11204597", "0x85594701f1d2fee6dc1956bc44c7b31db93bdeec2f3a7d622c1a08b26994760773e3d57521a44cfd7e407ac3fd430429", "0xa66de045ce7173043a6825e9dc440ac957e2efb6df0a337f4f8003eb0c719d873a52e6eba3cb0d69d977ca37d9187674", "0x87a1c6a1fdff993fa51efa5c3ba034c079c0928a7d599b906336af7c2dcab9721ceaf3108c646490af9dff9a754f54b3", "0x926424223e462ceb75aed7c22ade8a7911a903b7e5dd4bc49746ddce8657f4616325cd12667d4393ac52cdd866396d0e", "0xb5dc96106593b42b30f06f0b0a1e0c1aafc70432e31807252d3674f0b1ea5e58eac8424879d655c9488d85a879a3e572", "0x997ca0987735cc716507cb0124b1d266d218b40c9d8e0ecbf26a1d65719c82a637ce7e8be4b4815d307df717bde7c72a", "0x92994d3f57a569b7760324bb5ae4e8e14e1633d175dab06aa57b8e391540e05f662fdc08b8830f489a063f59b689a688", "0xa8087fcc6aa4642cb998bea11facfe87eb33b90a9aa428ab86a4124ad032fc7d2e57795311a54ec9f55cc120ebe42df1", "0xa9bd7d1de6c0706052ca0b362e2e70e8c8f70f1f026ea189b4f87a08ce810297ebfe781cc8004430776c54c1a05ae90c", "0x856d33282e8a8e33a3d237fb0a0cbabaf77ba9edf2fa35a831fdafcadf620561846aa6cbb6bdc5e681118e1245834165", "0x9524a7aa8e97a31a6958439c5f3339b19370f03e86b89b1d02d87e4887309dbbe9a3a8d2befd3b7ed5143c8da7e0a8ad", "0x824fdf433e090f8acbd258ac7429b21f36f9f3b337c6d0b71d1416a5c88a767883e255b2888b7c906dd2e9560c4af24c", "0x88c7fee662ca7844f42ed5527996b35723abffd0d22d4ca203b9452c639a5066031207a5ae763dbc0865b3299d19b1ec", "0x919dca5c5595082c221d5ab3a5bc230f45da7f6dec4eb389371e142c1b9c6a2c919074842479c2844b72c0d806170c0c", "0xb939be8175715e55a684578d8be3ceff3087f60fa875fff48e52a6e6e9979c955efef8ff67cfa2b79499ea23778e33b0", "0x873b6db725e7397d11bc9bed9ac4468e36619135be686790a79bc6ed4249058f1387c9a802ea86499f692cf635851066", "0xaeae06db3ec47e9e5647323fa02fac44e06e59b885ad8506bf71b184ab3895510c82f78b6b22a5d978e8218e7f761e9f", "0xb99c0a8359c72ab88448bae45d4bf98797a26bca48b0d4460cd6cf65a4e8c3dd823970ac3eb774ae5d0cea4e7fadf33e", "0x8f10c8ec41cdfb986a1647463076a533e6b0eec08520c1562401b36bb063ac972aa6b28a0b6ce717254e35940b900e3c", "0xa106d9be199636d7add43b942290269351578500d8245d4aae4c083954e4f27f64740a3138a66230391f2d0e6043a8de", "0xa469997908244578e8909ff57cffc070f1dbd86f0098df3cfeb46b7a085cfecc93dc69ee7cad90ff1dc5a34d50fe580c", "0xa4ef087bea9c20eb0afc0ee4caba7a9d29dfa872137828c721391273e402fb6714afc80c40e98bbd8276d3836bffa080", "0xb07a013f73cd5b98dae0d0f9c1c0f35bff8a9f019975c4e1499e9bee736ca6fcd504f9bc32df1655ff333062382cff04", "0xb0a77188673e87cc83348c4cc5db1eecf6b5184e236220c8eeed7585e4b928db849944a76ec60ef7708ef6dac02d5592", "0xb1284b37e59b529f0084c0dacf0af6c0b91fc0f387bf649a8c74819debf606f7b07fc3e572500016fb145ec2b24e9f17", "0x97b20b5b4d6b9129da185adfbf0d3d0b0faeba5b9715f10299e48ea0521709a8296a9264ce77c275a59c012b50b6519a", "0xb9d37e946fae5e4d65c1fbfacc8a62e445a1c9d0f882e60cca649125af303b3b23af53c81d7bac544fb7fcfc7a314665", "0x8e5acaac379f4bb0127efbef26180f91ff60e4c525bc9b798fc50dfaf4fe8a5aa84f18f3d3cfb8baead7d1e0499af753", "0xb0c0b8ab1235bf1cda43d4152e71efc1a06c548edb964eb4afceb201c8af24240bf8ab5cae30a08604e77432b0a5faf0", "0x8cc28d75d5c8d062d649cbc218e31c4d327e067e6dbd737ec0a35c91db44fbbd0d40ec424f5ed79814add16947417572", "0x95ae6219e9fd47efaa9cb088753df06bc101405ba50a179d7c9f7c85679e182d3033f35b00dbba71fdcd186cd775c52e", "0xb5d28fa09f186ebc5aa37453c9b4d9474a7997b8ae92748ecb940c14868792292ac7d10ade01e2f8069242b308cf97e5", "0x8c922a0faa14cc6b7221f302df3342f38fc8521ec6c653f2587890192732c6da289777a6cd310747ea7b7d104af95995", "0xb9ad5f660b65230de54de535d4c0fcae5bc6b59db21dea5500fdc12eea4470fb8ea003690fdd16d052523418d5e01e8c", "0xa39a9dd41a0ff78c82979483731f1cd68d3921c3e9965869662c22e02dde3877802e180ba93f06e7346f96d9fa9261d2", "0x8b32875977ec372c583b24234c27ed73aef00cdff61eb3c3776e073afbdeade548de9497c32ec6d703ff8ad0a5cb7fe4", "0x9644cbe755a5642fe9d26cfecf170d3164f1848c2c2e271d5b6574a01755f3980b3fc870b98cf8528fef6ecef4210c16", "0x81ea9d1fdd9dd66d60f40ce0712764b99da9448ae0b300f8324e1c52f154e472a086dda840cb2e0b9813dc8ce8afd4b5", "0x906aaa4a7a7cdf01909c5cfbc7ded2abc4b869213cbf7c922d4171a4f2e637e56f17020b852ad339d83b8ac92f111666", "0x939b5f11acbdeff998f2a080393033c9b9d8d5c70912ea651c53815c572d36ee822a98d6dfffb2e339f29201264f2cf4", "0xaba4898bf1ccea9b9e2df1ff19001e05891581659c1cbbde7ee76c349c7fc7857261d9785823c9463a8aea3f40e86b38", "0x83ca1a56b8a0be4820bdb5a9346357c68f9772e43f0b887729a50d2eb2a326bbcede676c8bf2e51d7c89bbd8fdb778a6", "0x94e86e9fe6addfe2c3ee3a547267ed921f4230d877a85bb4442c2d9350c2fa9a9c54e6fe662de82d1a2407e4ab1691c2", "0xa0cc3bdef671a59d77c6984338b023fa2b431b32e9ed2abe80484d73edc6540979d6f10812ecc06d4d0c5d4eaca7183c", "0xb5343413c1b5776b55ea3c7cdd1f3af1f6bd802ea95effe3f2b91a523817719d2ecc3f8d5f3cc2623ace7e35f99ca967", "0x92085d1ed0ed28d8cabe3e7ff1905ed52c7ceb1eac5503760c52fb5ee3a726aba7c90b483c032acc3f166b083d7ec370", "0x8ec679520455275cd957fca8122724d287db5df7d29f1702a322879b127bff215e5b71d9c191901465d19c86c8d8d404", "0xb65eb2c63d8a30332eb24ee8a0c70156fc89325ebbb38bacac7cf3f8636ad8a472d81ccca80423772abc00192d886d8a", "0xa9fe1c060b974bee4d590f2873b28635b61bfcf614e61ff88b1be3eee4320f4874e21e8d666d8ac8c9aba672efc6ecae", "0xb3fe2a9a389c006a831dea7e777062df84b5c2803f9574d7fbe10b7e1c125817986af8b6454d6be9d931a5ac94cfe963", "0x95418ad13b734b6f0d33822d9912c4c49b558f68d08c1b34a0127fcfa666bcae8e6fda8832d2c75bb9170794a20e4d7c", "0xa9a7df761e7f18b79494bf429572140c8c6e9d456c4d4e336184f3f51525a65eb9582bea1e601bdb6ef8150b7ca736a5", "0xa0de03b1e75edf7998c8c1ac69b4a1544a6fa675a1941950297917366682e5644a4bda9cdeedfaf9473d7fccd9080b0c", "0xa61838af8d95c95edf32663a68f007d95167bf6e41b0c784a30b22d8300cfdd5703bd6d16e86396638f6db6ae7e42a85", "0x8866d62084d905c145ff2d41025299d8b702ac1814a7dec4e277412c161bc9a62fed735536789cb43c88693c6b423882", "0x91da22c378c81497fe363e7f695c0268443abee50f8a6625b8a41e865638a643f07b157ee566de09ba09846934b4e2d7", "0x941d21dd57c9496aa68f0c0c05507405fdd413acb59bc668ce7e92e1936c68ec4b065c3c30123319884149e88228f0b2", "0xa77af9b094bc26966ddf2bf9e1520c898194a5ccb694915950dadc204facbe3066d3d89f50972642d76b14884cfbaa21", "0x8e76162932346869f4618bde744647f7ab52ab498ad654bdf2a4feeb986ac6e51370841e5acbb589e38b6e7142bb3049", "0xb60979ace17d6937ece72e4f015da4657a443dd01cebc7143ef11c09e42d4aa8855999a65a79e2ea0067f31c9fc2ab0f", "0xb3e2ffdd5ee6fd110b982fd4fad4b93d0fca65478f986d086eeccb0804960bfaa1919afa743c2239973ea65091fe57d2", "0x8ce0ce05e7d7160d44574011da687454dbd3c8b8290aa671731b066e2c82f8cf2d63cb8e932d78c6122ec610e44660e6", "0xab005dd8d297045c39e2f72fb1c48edb501ccf3575d3d04b9817b3afee3f0bb0f3f53f64bda37d1d9cde545aae999bae", "0x95bd7edb4c4cd60e3cb8a72558845a3cce6bb7032ccdf33d5a49ebb6ddf203bc3c79e7b7e550735d2d75b04c8b2441e8", "0x889953ee256206284094e4735dbbb17975bafc7c3cb94c9fbfee4c3e653857bfd49e818f64a47567f721b98411a3b454", "0xb188423e707640ab0e75a061e0b62830cde8afab8e1ad3dae30db69ffae4e2fc005bababbdcbd7213b918ed4f70e0c14", "0xa97e0fafe011abd70d4f99a0b36638b3d6e7354284588f17a88970ed48f348f88392779e9a038c6cbc9208d998485072", "0x87db11014a91cb9b63e8dfaa82cdebca98272d89eb445ee1e3ff9dbaf2b3fad1a03b888cffc128e4fe208ed0dddece0f", "0xaad2e40364edd905d66ea4ac9d51f9640d6fda9a54957d26ba233809851529b32c85660fa401dbee3679ec54fa6dd966", "0x863e99336ca6edf03a5a259e59a2d0f308206e8a2fb320cfc0be06057366df8e0f94b33a28f574092736b3c5ada84270", "0xb34bcc56a057589f34939a1adc51de4ff6a9f4fee9c7fa9aa131e28d0cf0759a0c871b640162acdfbf91f3f1b59a3703", "0x935dd28f2896092995c5eff1618e5b6efe7a40178888d7826da9b0503c2d6e68a28e7fac1a334e166d0205f0695ef614", "0xb842cd5f8f5de5ca6c68cb4a5c1d7b451984930eb4cc18fd0934d52fdc9c3d2d451b1c395594d73bc3451432bfba653f", "0x9014537885ce2debad736bc1926b25fdab9f69b216bf024f589c49dc7e6478c71d595c3647c9f65ff980b14f4bb2283b", "0x8e827ccca1dd4cd21707140d10703177d722be0bbe5cac578db26f1ef8ad2909103af3c601a53795435b27bf95d0c9ed", "0x8a0b8ad4d466c09d4f1e9167410dbe2edc6e0e6229d4b3036d30f85eb6a333a18b1c968f6ca6d6889bb08fecde017ef4", "0x9241ee66c0191b06266332dc9161dede384c4bb4e116dbd0890f3c3790ec5566da4568243665c4725b718ac0f6b5c179", "0xaeb4d5fad81d2b505d47958a08262b6f1b1de9373c2c9ba6362594194dea3e002ab03b8cbb43f867be83065d3d370f19", "0x8781bc83bb73f7760628629fe19e4714b494dbed444c4e4e4729b7f6a8d12ee347841a199888794c2234f51fa26fc2b9", "0xb58864f0acd1c2afa29367e637cbde1968d18589245d9936c9a489c6c495f54f0113ecdcbe4680ac085dd3c397c4d0c3", "0x94a24284afaeead61e70f3e30f87248d76e9726759445ca18cdb9360586c60cc9f0ec1c397f9675083e0b56459784e2e", "0xaed358853f2b54dcbddf865e1816c2e89be12e940e1abfa661e2ee63ffc24a8c8096be2072fa83556482c0d89e975124", "0xb95374e6b4fc0765708e370bc881e271abf2e35c08b056a03b847e089831ef4fe3124b9c5849d9c276eb2e35b3daf264", "0xb834cdbcfb24c8f84bfa4c552e7fadc0028a140952fd69ed13a516e1314a4cd35d4b954a77d51a1b93e1f5d657d0315d", "0x8fb6d09d23bfa90e7443753d45a918d91d75d8e12ec7d016c0dfe94e5c592ba6aaf483d2f16108d190822d955ad9cdc3", "0xaa315cd3c60247a6ad4b04f26c5404c2713b95972843e4b87b5a36a89f201667d70f0adf20757ebe1de1b29ae27dda50", "0xa116862dca409db8beff5b1ccd6301cdd0c92ca29a3d6d20eb8b87f25965f42699ca66974dd1a355200157476b998f3b", "0xb4c2f5fe173c4dc8311b60d04a65ce1be87f070ac42e13cd19c6559a2931c6ee104859cc2520edebbc66a13dc7d30693", "0x8d4a02bf99b2260c334e7d81775c5cf582b00b0c982ce7745e5a90624919028278f5e9b098573bad5515ce7fa92a80c8", "0x8543493bf564ce6d97bd23be9bff1aba08bd5821ca834f311a26c9139c92a48f0c2d9dfe645afa95fec07d675d1fd53b", "0x9344239d13fde08f98cb48f1f87d34cf6abe8faecd0b682955382a975e6eed64e863fa19043290c0736261622e00045c", "0xaa49d0518f343005ca72b9e6c7dcaa97225ce6bb8b908ebbe7b1a22884ff8bfb090890364e325a0d414ad180b8f161d1", "0x907d7fd3e009355ab326847c4a2431f688627faa698c13c03ffdd476ecf988678407f029b8543a475dcb3dafdf2e7a9c", "0x845f1f10c6c5dad2adc7935f5cd2e2b32f169a99091d4f1b05babe7317b9b1cdce29b5e62f947dc621b9acbfe517a258", "0x8f3be8e3b380ea6cdf9e9c237f5e88fd5a357e5ded80ea1fc2019810814de82501273b4da38916881125b6fa0cfd4459", "0xb9c7f487c089bf1d20c822e579628db91ed9c82d6ca652983aa16d98b4270c4da19757f216a71b9c13ddee3e6e43705f", "0x8ba2d8c88ad2b872db104ea8ddbb006ec2f3749fd0e19298a804bb3a5d94de19285cc7fb19fee58a66f7851d1a66c39f", "0x9375ecd3ed16786fe161af5d5c908f56eeb467a144d3bbddfc767e90065b7c94fc53431adebecba2b6c9b5821184d36e", "0xa49e069bfadb1e2e8bff6a4286872e2a9765d62f0eaa4fcb0e5af4bbbed8be3510fb19849125a40a8a81d1e33e81c3eb", "0x9522cc66757b386aa6b88619525c8ce47a5c346d590bb3647d12f991e6c65c3ab3c0cfc28f0726b6756c892eae1672be", "0xa9a0f1f51ff877406fa83a807aeb17b92a283879f447b8a2159653db577848cc451cbadd01f70441e351e9ed433c18bc", "0x8ff7533dcff6be8714df573e33f82cf8e9f2bcaaa43e939c4759d52b754e502717950de4b4252fb904560fc31dce94a4", "0x959724671e265a28d67c29d95210e97b894b360da55e4cf16e6682e7912491ed8ca14bfaa4dce9c25a25b16af580494f", "0x92566730c3002f4046c737032487d0833c971e775de59fe02d9835c9858e2e3bc37f157424a69764596c625c482a2219", "0xa84b47ceff13ed9c3e5e9cdf6739a66d3e7c2bd8a6ba318fefb1a9aecf653bb2981da6733ddb33c4b0a4523acc429d23", "0xb4ddf571317e44f859386d6140828a42cf94994e2f1dcbcc9777f4eebbfc64fc1e160b49379acc27c4672b8e41835c5d", "0x8ab95c94072b853d1603fdd0a43b30db617d13c1d1255b99075198e1947bfa5f59aed2b1147548a1b5e986cd9173d15c", "0x89511f2eab33894fd4b3753d24249f410ff7263052c1fef6166fc63a79816656b0d24c529e45ccce6be28de6e375d916", "0xa0866160ca63d4f2be1b4ea050dac6b59db554e2ebb4e5b592859d8df339b46fd7cb89aaed0951c3ee540aee982c238a", "0x8fcc5cbba1b94970f5ff2eb1922322f5b0aa7d918d4b380c9e7abfd57afd8b247c346bff7b87af82efbce3052511cd1b", "0x99aeb2a5e846b0a2874cca02c66ed40d5569eb65ab2495bc3f964a092e91e1517941f2688e79f8cca49cd3674c4e06dc", "0xb7a096dc3bad5ca49bee94efd884aa3ff5615cf3825cf95fbe0ce132e35f46581d6482fa82666c7ef5f1643eaee8f1ca", "0x94393b1da6eaac2ffd186b7725eca582f1ddc8cdd916004657f8a564a7c588175cb443fc6943b39029f5bbe0add3fad8", "0x884b85fe012ccbcd849cb68c3ad832d83b3ef1c40c3954ffdc97f103b1ed582c801e1a41d9950f6bddc1d11f19d5ec76", "0xb00061c00131eded8305a7ce76362163deb33596569afb46fe499a7c9d7a0734c084d336b38d168024c2bb42b58e7660", "0xa439153ac8e6ca037381e3240e7ba08d056c83d7090f16ed538df25901835e09e27de2073646e7d7f3c65056af6e4ce7", "0x830fc9ca099097d1f38b90e6843dc86f702be9d20bdacc3e52cae659dc41df5b8d2c970effa6f83a5229b0244a86fe22", "0xb81ea2ffaaff2bb00dd59a9ab825ba5eed4db0d8ac9c8ed1a632ce8f086328a1cddd045fbe1ace289083c1325881b7e7", "0xb51ea03c58daf2db32c99b9c4789b183365168cb5019c72c4cc91ac30b5fb7311d3db76e6fa41b7cd4a8c81e2f6cdc94", "0xa4170b2c6d09ca5beb08318730419b6f19215ce6c631c854116f904be3bc30dd85a80c946a8ab054d3e307afaa3f8fbc", "0x897cc42ff28971ff54d2a55dd6b35cfb8610ac902f3c06e3a5cea0e0a257e870c471236a8e84709211c742a09c5601a6", "0xa18f2e98d389dace36641621488664ecbb422088ab03b74e67009b8b8acacaaa24fdcf42093935f355207d934adc52a8", "0x92adcfb678cc2ba19c866f3f2b988fdcb4610567f3ab436cc0cb9acaf5a88414848d71133ebdbec1983e38e6190f1b5f", "0xa86d43c2ce01b366330d3b36b3ca85f000c3548b8297e48478da1ee7d70d8576d4650cba7852ed125c0d7cb6109aa7f3", "0x8ed31ceed9445437d7732dce78a762d72ff32a7636bfb3fd7974b7ae15db414d8184a1766915244355deb354fbc5803b", "0x9268f70032584f416e92225d65af9ea18c466ebc7ae30952d56a4e36fd9ea811dde0a126da9220ba3c596ec54d8a335e", "0x9433b99ee94f2d3fbdd63b163a2bdf440379334c52308bd24537f7defd807145a062ff255a50d119a7f29f4b85d250e3", "0x90ce664f5e4628a02278f5cf5060d1a34f123854634b1870906e5723ac9afd044d48289be283b267d45fcbf3f4656aaf", "0xaaf21c4d59378bb835d42ae5c5e5ab7a3c8c36a59e75997989313197752b79a472d866a23683b329ea69b048b87fa13e", "0xb83c0589b304cec9ede549fde54f8a7c2a468c6657da8c02169a6351605261202610b2055c639b9ed2d5b8c401fb8f56", "0x9370f326ea0f170c2c05fe2c5a49189f20aec93b6b18a5572a818cd4c2a6adb359e68975557b349fb54f065d572f4c92", "0xac3232fa5ce6f03fca238bef1ce902432a90b8afce1c85457a6bee5571c033d4bceefafc863af04d4e85ac72a4d94d51", "0x80d9ea168ff821b22c30e93e4c7960ce3ad3c1e6deeebedd342a36d01bd942419b187e2f382dbfd8caa34cca08d06a48", "0xa387a3c61676fb3381eefa2a45d82625635a666e999aba30e3b037ec9e040f414f9e1ad9652abd3bcad63f95d85038db", "0xa1b229fe32121e0b391b0f6e0180670b9dc89d79f7337de4c77ea7ad0073e9593846f06797c20e923092a08263204416", "0x92164a9d841a2b828cedf2511213268b698520f8d1285852186644e9a0c97512cafa4bfbe29af892c929ebccd102e998", "0x82ee2fa56308a67c7db4fd7ef539b5a9f26a1c2cc36da8c3206ba4b08258fbb3cec6fe5cdbd111433fb1ba2a1e275927", "0x8c77bfe9e191f190a49d46f05600603fa42345592539b82923388d72392404e0b29a493a15e75e8b068dddcd444c2928", "0x80b927f93ccf79dcf5c5b20bcf5a7d91d7a17bc0401bb7cc9b53a6797feac31026eb114257621f5a64a52876e4474cc1", "0xb6b68b6501c37804d4833d5a063dd108a46310b1400549074e3cac84acc6d88f73948b7ad48d686de89c1ec043ae8c1a", "0xab3da00f9bdc13e3f77624f58a3a18fc3728956f84b5b549d62f1033ae4b300538e53896e2d943f160618e05af265117", "0xb6830e87233b8eace65327fdc764159645b75d2fd4024bf8f313b2dd5f45617d7ecfb4a0b53ccafb5429815a9a1adde6", "0xb9251cfe32a6dc0440615aadcd98b6b1b46e3f4e44324e8f5142912b597ee3526bea2431e2b0282bb58f71be5b63f65e", "0xaf8d70711e81cdddfb39e67a1b76643292652584c1ce7ce4feb1641431ad596e75c9120e85f1a341e7a4da920a9cdd94", "0x98cd4e996594e89495c078bfd52a4586b932c50a449a7c8dfdd16043ca4cda94dafbaa8ad1b44249c99bbcc52152506e", "0xb9fc6d1c24f48404a4a64fbe3e43342738797905db46e4132aee5f086aaa4c704918ad508aaefa455cfe1b36572e6242", "0xa365e871d30ba9291cedaba1be7b04e968905d003e9e1af7e3b55c5eb048818ae5b913514fb08b24fb4fbdccbb35d0b8", "0x93bf99510971ea9af9f1e364f1234c898380677c8e8de9b0dd24432760164e46c787bc9ec42a7ad450500706cf247b2d", "0xb872f825a5b6e7b9c7a9ddfeded3516f0b1449acc9b4fd29fc6eba162051c17416a31e5be6d3563f424d28e65bab8b8f", "0xb06b780e5a5e8eb4f4c9dc040f749cf9709c8a4c9ef15e925f442b696e41e5095db0778a6c73bcd329b265f2c6955c8b", "0x848f1a981f5fc6cd9180cdddb8d032ad32cdfa614fc750d690dbae36cc0cd355cbf1574af9b3ffc8b878f1b2fafb9544", "0xa03f48cbff3e9e8a3a655578051a5ae37567433093ac500ed0021c6250a51b767afac9bdb194ee1e3eac38a08c0eaf45", "0xb5be78ce638ff8c4aa84352b536628231d3f7558c5be3bf010b28feac3022e64691fa672f358c8b663904aebe24a54ed", "0xa9d4da70ff676fa55d1728ba6ab03b471fa38b08854d99e985d88c2d050102d8ccffbe1c90249a5607fa7520b15fe791", "0x8fe9f7092ffb0b69862c8e972fb1ecf54308c96d41354ed0569638bb0364f1749838d6d32051fff1599112978c6e229c", "0xae6083e95f37770ecae0df1e010456f165d96cfe9a7278c85c15cffd61034081ce5723e25e2bede719dc9341ec8ed481", "0xa260891891103089a7afbd9081ea116cfd596fd1015f5b65e10b0961eb37fab7d09c69b7ce4be8bf35e4131848fb3fe4", "0x8d729fa32f6eb9fd2f6a140bef34e8299a2f3111bffd0fe463aa8622c9d98bfd31a1df3f3e87cd5abc52a595f96b970e", "0xa30ec6047ae4bc7da4daa7f4c28c93aedb1112cfe240e681d07e1a183782c9ff6783ac077c155af23c69643b712a533f", "0xac830726544bfe7b5467339e5114c1a75f2a2a8d89453ce86115e6a789387e23551cd64620ead6283dfa4538eb313d86", "0x8445c135b7a48068d8ed3e011c6d818cfe462b445095e2fbf940301e50ded23f272d799eea47683fc027430ce14613ef", "0x95785411715c9ae9d8293ce16a693a2aa83e3cb1b4aa9f76333d0da2bf00c55f65e21e42e50e6c5772ce213dd7b4f7a0", "0xb273b024fa18b7568c0d1c4d2f0c4e79ec509dafac8c5951f14192d63ddbcf2d8a7512c1c1b615cc38fa3e336618e0c5", "0xa78b9d3ea4b6a90572eb27956f411f1d105fdb577ee2ffeec9f221da9b45db84bfe866af1f29597220c75e0c37a628d8", "0xa4be2bf058c36699c41513c4d667681ce161a437c09d81383244fc55e1c44e8b1363439d0cce90a3e44581fb31d49493", "0xb6eef13040f17dd4eba22aaf284d2f988a4a0c4605db44b8d2f4bf9567ac794550b543cc513c5f3e2820242dd704152e", "0x87eb00489071fa95d008c5244b88e317a3454652dcb1c441213aa16b28cd3ecaa9b22fec0bdd483c1df71c37119100b1", "0x92d388acdcb49793afca329cd06e645544d2269234e8b0b27d2818c809c21726bc9cf725651b951e358a63c83dedee24", "0xae27e219277a73030da27ab5603c72c8bd81b6224b7e488d7193806a41343dff2456132274991a4722fdb0ef265d04cd", "0x97583e08ecb82bbc27c0c8476d710389fa9ffbead5c43001bd36c1b018f29faa98de778644883e51870b69c5ffb558b5", "0x90a799a8ce73387599babf6b7da12767c0591cadd36c20a7990e7c05ea1aa2b9645654ec65308ee008816623a2757a6a", "0xa1b47841a0a2b06efd9ab8c111309cc5fc9e1d5896b3e42ed531f6057e5ade8977c29831ce08dbda40348386b1dcc06d", "0xb92b8ef59bbddb50c9457691bc023d63dfcc54e0fd88bd5d27a09e0d98ac290fc90e6a8f6b88492043bf7c87fac8f3e4", "0xa9d6240b07d62e22ec8ab9b1f6007c975a77b7320f02504fc7c468b4ee9cfcfd945456ff0128bc0ef2174d9e09333f8d", "0x8e96534c94693226dc32bca79a595ca6de503af635f802e86442c67e77564829756961d9b701187fe91318da515bf0e6", "0xb6ba290623cd8dd5c2f50931c0045d1cfb0c30877bc8fe58cbc3ff61ee8da100045a39153916efa1936f4aee0892b473", "0xb43baa7717fac02d4294f5b3bb5e58a65b3557747e3188b482410388daac7a9c177f762d943fd5dcf871273921213da8", "0xb9cf00f8fb5e2ef2b836659fece15e735060b2ea39b8e901d3dcbdcf612be8bf82d013833718c04cd46ffaa70b85f42e", "0x8017d0c57419e414cbba504368723e751ef990cc6f05dad7b3c2de6360adc774ad95512875ab8337d110bf39a42026fa", "0xae7401048b838c0dcd4b26bb6c56d79d51964a0daba780970b6c97daee4ea45854ea0ac0e4139b3fe60dac189f84df65", "0x887b237b0cd0f816b749b21db0b40072f9145f7896c36916296973f9e6990ede110f14e5976c906d08987c9836cca57f", "0xa88c3d5770148aee59930561ca1223aceb2c832fb5417e188dca935905301fc4c6c2c9270bc1dff7add490a125eb81c6", "0xb6cf9b02c0cd91895ad209e38c54039523f137b5848b9d3ad33ae43af6c20c98434952db375fe378de7866f2d0e8b18a", "0x84ef3d322ff580c8ad584b1fe4fe346c60866eb6a56e982ba2cf3b021ecb1fdb75ecc6c29747adda86d9264430b3f816", "0xa0561c27224baf0927ad144cb71e31e54a064c598373fcf0d66aebf98ab7af1d8e2f343f77baefff69a6da750a219e11", "0xaa5cc43f5b8162b016f5e1b61214c0c9d15b1078911c650b75e6cdfb49b85ee04c6739f5b1687d15908444f691f732de", "0xad4ac099b935589c7b8fdfdf3db332b7b82bb948e13a5beb121ebd7db81a87d278024a1434bcf0115c54ca5109585c3d", "0x8a00466abf3f109a1dcd19e643b603d3af23d42794ef8ca2514dd507ecea44a031ac6dbc18bd02f99701168b25c1791e", "0xb00b5900dfad79645f8bee4e5adc7b84eb22e5b1e67df77ccb505b7fc044a6c08a8ea5faca662414eb945f874f884cea", "0x950e204e5f17112250b22ea6bb8423baf522fc0af494366f18fe0f949f51d6e6812074a80875cf1ed9c8e7420058d541", "0x91e5cbf8bb1a1d50c81608c9727b414d0dd2fb467ebc92f100882a3772e54f94979cfdf8e373fdef7c7fcdd60fec9e00", "0xa093f6a857b8caaff80599c2e89c962b415ecbaa70d8fd973155fa976a284c6b29a855f5f7a3521134d00d2972755188", "0xb4d55a3551b00da54cc010f80d99ddd2544bde9219a3173dfaadf3848edc7e4056ab532fb75ac26f5f7141e724267663", "0xa03ea050fc9b011d1b04041b5765d6f6453a93a1819cd9bd6328637d0b428f08526466912895dcc2e3008ee58822e9a7", "0x99b12b3665e473d01bc6985844f8994fb65cb15745024fb7af518398c4a37ff215da8f054e8fdf3286984ae36a73ca5e", "0x9972c7e7a7fb12e15f78d55abcaf322c11249cd44a08f62c95288f34f66b51f146302bce750ff4d591707075d9123bd2", "0xa64b4a6d72354e596d87cda213c4fc2814009461570ccb27d455bbe131f8d948421a71925425b546d8cf63d5458cd64b", "0x91c215c73b195795ede2228b7ed1f6e37892e0c6b0f4a0b5a16c57aa1100c84df9239054a173b6110d6c2b7f4bf1ce52", "0x88807198910ec1303480f76a3683870246a995e36adaeadc29c22f0bdba8152fe705bd070b75de657b04934f7d0ccf80", "0xb37c0026c7b32eb02cacac5b55cb5fe784b8e48b2945c64d3037af83ece556a117f0ff053a5968c2f5fa230e291c1238", "0x94c768384ce212bc2387e91ce8b45e4ff120987e42472888a317abc9dcdf3563b62e7a61c8e98d7cdcbe272167d91fc6", "0xa10c2564936e967a390cb14ef6e8f8b04ea9ece5214a38837eda09e79e0c7970b1f83adf017c10efd6faa8b7ffa2c567", "0xa5085eed3a95f9d4b1269182ea1e0d719b7809bf5009096557a0674bde4201b0ddc1f0f16a908fc468846b3721748ce3", "0x87468eb620b79a0a455a259a6b4dfbc297d0d53336537b771254dd956b145dc816b195b7002647ea218552e345818a3f", "0xace2b77ffb87366af0a9cb5d27d6fc4a14323dbbf1643f5f3c4559306330d86461bb008894054394cbfaefeaa0bc2745", "0xb27f56e840a54fbd793f0b7a7631aa4cee64b5947e4382b2dfb5eb1790270288884c2a19afebe5dc0c6ef335d4531c1c", "0x876e438633931f7f895062ee16c4b9d10428875f7bc79a8e156a64d379a77a2c45bf5430c5ab94330f03da352f1e9006", "0xa2512a252587d200d2092b44c914df54e04ff8bcef36bf631f84bde0cf5a732e3dc7f00f662842cfd74b0b0f7f24180e", "0x827f1bc8f54a35b7a4bd8154f79bcc055e45faed2e74adf7cf21cca95df44d96899e847bd70ead6bb27b9c0ed97bbd8b", "0xa0c92cf5a9ed843714f3aea9fe7b880f622d0b4a3bf66de291d1b745279accf6ba35097849691370f41732ba64b5966b", "0xa63f5c1e222775658421c487b1256b52626c6f79cb55a9b7deb2352622cedffb08502042d622eb3b02c97f9c09f9c957", "0x8cc093d52651e65fb390e186db6cc4de559176af4624d1c44cb9b0e836832419dacac7b8db0627b96288977b738d785d", "0xaa7b6a17dfcec146134562d32a12f7bd7fe9522e300859202a02939e69dbd345ed7ff164a184296268f9984f9312e8fc", "0x8ac76721f0d2b679f023d06cbd28c85ae5f4b43c614867ccee88651d4101d4fd352dbdb65bf36bfc3ebc0109e4b0c6f9", "0x8d350f7c05fc0dcd9a1170748846fb1f5d39453e4cb31e6d1457bed287d96fc393b2ecc53793ca729906a33e59c6834a", "0xb9913510dfc5056d7ec5309f0b631d1ec53e3a776412ada9aefdaf033c90da9a49fdde6719e7c76340e86599b1f0eec2", "0x94955626bf4ce87612c5cfffcf73bf1c46a4c11a736602b9ba066328dc52ad6d51e6d4f53453d4ed55a51e0aad810271", "0xb0fcab384fd4016b2f1e53f1aafd160ae3b1a8865cd6c155d7073ecc1664e05b1d8bca1def39c158c7086c4e1103345e", "0x827de3f03edfbde08570b72de6662c8bfa499b066a0a27ebad9b481c273097d17a5a0a67f01553da5392ec3f149b2a78", "0xab7940384c25e9027c55c40df20bd2a0d479a165ced9b1046958353cd69015eeb1e44ed2fd64e407805ba42df10fc7bf", "0x8ad456f6ff8cd58bd57567d931f923d0c99141978511b17e03cab7390a72b9f62498b2893e1b05c7c22dd274e9a31919", "0xac75399e999effe564672db426faa17a839e57c5ef735985c70cd559a377adec23928382767b55ed5a52f7b11b54b756", "0xb17f975a00b817299ac7af5f2024ea820351805df58b43724393bfb3920a8cd747a3bbd4b8286e795521489db3657168", "0xa2bed800a6d95501674d9ee866e7314063407231491d794f8cf57d5be020452729c1c7cefd8c50dc1540181f5caab248", "0x9743f5473171271ffdd3cc59a3ae50545901a7b45cd4bc3570db487865f3b73c0595bebabbfe79268809ee1862e86e4a", "0xb7eab77c2d4687b60d9d7b04e842b3880c7940140012583898d39fcc22d9b9b0a9be2c2e3788b3e6f30319b39c338f09", "0x8e2b8f797a436a1b661140e9569dcf3e1eea0a77c7ff2bc4ff0f3e49af04ed2de95e255df8765f1d0927fb456a9926b1", "0x8aefea201d4a1f4ff98ffce94e540bb313f2d4dfe7e9db484a41f13fc316ed02b282e1acc9bc6f56cad2dc2e393a44c9", "0xb950c17c0e5ca6607d182144aa7556bb0efe24c68f06d79d6413a973b493bfdf04fd147a4f1ab03033a32004cc3ea66f", "0xb7b8dcbb179a07165f2dc6aa829fad09f582a71b05c3e3ea0396bf9e6fe73076f47035c031c2101e8e38e0d597eadd30", "0xa9d77ed89c77ec1bf8335d08d41c3c94dcca9fd1c54f22837b4e54506b212aa38d7440126c80648ab7723ff18e65ed72", "0xa819d6dfd4aef70e52b8402fe5d135f8082d40eb7d3bb5c4d7997395b621e2bb10682a1bad2c9caa33dd818550fc3ec6", "0x8f6ee34128fac8bbf13ce2d68b2bb363eb4fd65b297075f88e1446ddeac242500eeb4ef0735e105882ff5ba8c44c139b", "0xb4440e48255c1644bcecf3a1e9958f1ec4901cb5b1122ee5b56ffd02cad1c29c4266999dbb85aa2605c1b125490074d4", "0xa43304a067bede5f347775d5811cf65a6380a8d552a652a0063580b5c5ef12a0867a39c7912fa219e184f4538eba1251", "0xa891ad67a790089ffc9f6d53e6a3d63d3556f5f693e0cd8a7d0131db06fd4520e719cfcc3934f0a8f62a95f90840f1d4", "0xaea6df8e9bb871081aa0fc5a9bafb00be7d54012c5baf653791907d5042a326aeee966fd9012a582cc16695f5baf7042", "0x8ffa2660dc52ed1cd4eff67d6a84a8404f358a5f713d04328922269bee1e75e9d49afeec0c8ad751620f22352a438e25", "0x87ec6108e2d63b06abed350f8b363b7489d642486f879a6c3aa90e5b0f335efc2ff2834eef9353951a42136f8e6a1b32", "0x865619436076c2760d9e87ddc905023c6de0a8d56eef12c98a98c87837f2ca3f27fd26a2ad752252dbcbe2b9f1d5a032", "0x980437dce55964293cb315c650c5586ffd97e7a944a83f6618af31c9d92c37b53ca7a21bb5bc557c151b9a9e217e7098", "0x95d128fc369df4ad8316b72aea0ca363cbc7b0620d6d7bb18f7076a8717a6a46956ff140948b0cc4f6d2ce33b5c10054", "0x8c7212d4a67b9ec70ebbca04358ad2d36494618d2859609163526d7b3acc2fc935ca98519380f55e6550f70a9bc76862", "0x893a2968819401bf355e85eee0f0ed0406a6d4a7d7f172d0017420f71e00bb0ba984f6020999a3cdf874d3cd8ebcd371", "0x9103c1af82dece25d87274e89ea0acd7e68c2921c4af3d8d7c82ab0ed9990a5811231b5b06113e7fa43a6bd492b4564f", "0x99cfd87a94eab7d35466caa4ed7d7bb45e5c932b2ec094258fb14bf205659f83c209b83b2f2c9ccb175974b2a33e7746", "0x874b6b93e4ee61be3f00c32dd84c897ccd6855c4b6251eb0953b4023634490ed17753cd3223472873cbc6095b2945075", "0x84a32c0dc4ea60d33aac3e03e70d6d639cc9c4cc435c539eff915017be3b7bdaba33349562a87746291ebe9bc5671f24", "0xa7057b24208928ad67914e653f5ac1792c417f413d9176ba635502c3f9c688f7e2ee81800d7e3dc0a340c464da2fd9c5", "0xa03fb9ed8286aacfa69fbd5d953bec591c2ae4153400983d5dbb6cd9ea37fff46ca9e5cceb9d117f73e9992a6c055ad2", "0x863b2de04e89936c9a4a2b40380f42f20aefbae18d03750fd816c658aee9c4a03df7b12121f795c85d01f415baaeaa59", "0x8526eb9bd31790fe8292360d7a4c3eed23be23dd6b8b8f01d2309dbfdc0cfd33ad1568ddd7f8a610f3f85a9dfafc6a92", "0xb46ab8c5091a493d6d4d60490c40aa27950574a338ea5bbc045be3a114af87bdcb160a8c80435a9b7ad815f3cb56a3f3", "0xaeadc47b41a8d8b4176629557646202f868b1d728b2dda58a347d937e7ffc8303f20d26d6c00b34c851b8aeec547885d", "0xaebb19fc424d72c1f1822aa7adc744cd0ef7e55727186f8df8771c784925058c248406ebeeaf3c1a9ee005a26e9a10c6", "0x8ff96e81c1a4a2ab1b4476c21018fae0a67e92129ee36120cae8699f2d7e57e891f5c624902cb1b845b944926a605cc3", "0x8251b8d2c43fadcaa049a9e7aff838dae4fb32884018d58d46403ac5f3beb5c518bfd45f03b8abb710369186075eb71c", "0xa8b2a64f865f51a5e5e86a66455c093407933d9d255d6b61e1fd81ffafc9538d73caaf342338a66ba8ee166372a3d105", "0xaad915f31c6ba7fdc04e2aaac62e84ef434b7ee76a325f07dc430d12c84081999720181067b87d792efd0117d7ee1eab", "0xa13db3bb60389883fd41d565c54fb5180d9c47ce2fe7a169ae96e01d17495f7f4fa928d7e556e7c74319c4c25d653eb2", "0xa4491b0198459b3f552855d680a59214eb74e6a4d6c5fa3b309887dc50ebea2ecf6d26c040550f7dc478b452481466fb", "0x8f017f13d4b1e3f0c087843582b52d5f8d13240912254d826dd11f8703a99a2f3166dfbdfdffd9a3492979d77524276b", "0x96c3d5dcd032660d50d7cd9db2914f117240a63439966162b10c8f1f3cf74bc83b0f15451a43b31dbd85e4a7ce0e4bb1", "0xb479ec4bb79573d32e0ec93b92bdd7ec8c26ddb5a2d3865e7d4209d119fd3499eaac527615ffac78c440e60ef3867ae0", "0xb2c49c4a33aa94b52b6410b599e81ff15490aafa7e43c8031c865a84e4676354a9c81eb4e7b8be6825fdcefd1e317d44", "0x906dc51d6a90c089b6704b47592805578a6eed106608eeb276832f127e1b8e858b72e448edcbefb497d152447e0e68ff", "0xb0e81c63b764d7dfbe3f3fddc9905aef50f3633e5d6a4af6b340495124abedcff5700dfd1577bbbed7b6bf97d02719cb", "0x9304c64701e3b4ed6d146e48a881f7d83a17f58357cca0c073b2bb593afd2d94f6e2a7a1ec511d0a67ad6ff4c3be5937", "0xb6fdbd12ba05aa598d80b83f70a15ef90e5cba7e6e75fa038540ee741b644cd1f408a6cecfd2a891ef8d902de586c6b5", "0xb80557871a6521b1b3c74a1ba083ae055b575df607f1f7b04c867ba8c8c181ea68f8d90be6031f4d25002cca27c44da2", "0xaa7285b8e9712e06b091f64163f1266926a36607f9d624af9996856ed2aaf03a580cb22ce407d1ade436c28b44ca173f", "0x8148d72b975238b51e6ea389e5486940d22641b48637d7dfadfa603a605bfc6d74a016480023945d0b85935e396aea5d", "0x8a014933a6aea2684b5762af43dcf4bdbb633cd0428d42d71167a2b6fc563ece5e618bff22f1db2ddb69b845b9a2db19", "0x990d91740041db770d0e0eb9d9d97d826f09fd354b91c41e0716c29f8420e0e8aac0d575231efba12fe831091ec38d5a", "0x9454d0d32e7e308ddec57cf2522fb1b67a2706e33fb3895e9e1f18284129ab4f4c0b7e51af25681d248d7832c05eb698", "0xa5bd434e75bac105cb3e329665a35bce6a12f71dd90c15165777d64d4c13a82bceedb9b48e762bd24034e0fc9fbe45f4", "0xb09e3b95e41800d4dc29c6ffdaab2cd611a0050347f6414f154a47ee20ee59bf8cf7181454169d479ebce1eb5c777c46", "0xb193e341d6a047d15eea33766d656d807b89393665a783a316e9ba10518e5515c8e0ade3d6e15641d917a8a172a5a635", "0xade435ec0671b3621dde69e07ead596014f6e1daa1152707a8c18877a8b067bde2895dd47444ffa69db2bbef1f1d8816", "0xa7fd3d6d87522dfc56fb47aef9ce781a1597c56a8bbfd796baba907afdc872f753d732bfda1d3402aee6c4e0c189f52d", "0xa298cb4f4218d0464b2fab393e512bbc477c3225aa449743299b2c3572f065bc3a42d07e29546167ed9e1b6b3b3a3af3", "0xa9ee57540e1fd9c27f4f0430d194b91401d0c642456c18527127d1f95e2dba41c2c86d1990432eb38a692fda058fafde", "0x81d6c1a5f93c04e6d8e5a7e0678c1fc89a1c47a5c920bcd36180125c49fcf7c114866b90e90a165823560b19898a7c16", "0xa4b7a1ec9e93c899b9fd9aaf264c50e42c36c0788d68296a471f7a3447af4dbc81e4fa96070139941564083ec5b5b5a1", "0xb3364e327d381f46940c0e11e29f9d994efc6978bf37a32586636c0070b03e4e23d00650c1440f448809e1018ef9f6d8", "0x8056e0913a60155348300e3a62e28b5e30629a90f7dd4fe11289097076708110a1d70f7855601782a3cdc5bdb1ca9626", "0xb4980fd3ea17bac0ba9ee1c470b17e575bb52e83ebdd7d40c93f4f87bebeaff1c8a679f9d3d09d635f068d37d5bd28bd", "0x905a9299e7e1853648e398901dfcd437aa575c826551f83520df62984f5679cb5f0ea86aa45ed3e18b67ddc0dfafe809", "0xab99553bf31a84f2e0264eb34a08e13d8d15e2484aa9352354becf9a15999c76cc568d68274b70a65e49703fc23540d0", "0xa43681597bc574d2dae8964c9a8dc1a07613d7a1272bdcb818d98c85d44e16d744250c33f3b5e4d552d97396b55e601f", "0xa54e5a31716fccb50245898c99865644405b8dc920ded7a11f3d19bdc255996054b268e16f2e40273f11480e7145f41e", "0x8134f3ad5ef2ad4ba12a8a4e4d8508d91394d2bcdc38b7c8c8c0b0a820357ac9f79d286c65220f471eb1adca1d98fc68", "0x94e2f755e60471578ab2c1adb9e9cea28d4eec9b0e92e0140770bca7002c365fcabfe1e5fb4fe6cfe79a0413712aa3ef", "0xad48f8d0ce7eb3cc6e2a3086ad96f562e5bed98a360721492ae2e74dc158586e77ec8c35d5fd5927376301b7741bad2b", "0x8614f0630bdd7fbad3a31f55afd9789f1c605dc85e7dc67e2edfd77f5105f878bb79beded6e9f0b109e38ea7da67e8d5", "0x9804c284c4c5e77dabb73f655b12181534ca877c3e1e134aa3f47c23b7ec92277db34d2b0a5d38d2b69e5d1c3008a3e3", "0xa51b99c3088e473afdaa9e0a9f7e75a373530d3b04e44e1148da0726b95e9f5f0c7e571b2da000310817c36f84b19f7f", "0xac4ff909933b3b76c726b0a382157cdc74ab851a1ac6cef76953c6444441804cc43abb883363f416592e8f6cfbc4550b", "0xae7d915eb9fc928b65a29d6edbc75682d08584d0014f7bcf17d59118421ae07d26a02137d1e4de6938bcd1ab8ef48fad", "0x852f7e453b1af89b754df6d11a40d5d41ea057376e8ecacd705aacd2f917457f4a093d6b9a8801837fa0f62986ad7149", "0x92c6bf5ada5d0c3d4dd8058483de36c215fa98edab9d75242f3eff9db07c734ad67337da6f0eefe23a487bf75a600dee", "0xa2b42c09d0db615853763552a48d2e704542bbd786aae016eb58acbf6c0226c844f5fb31e428cb6450b9db855f8f2a6f", "0x880cc07968266dbfdcfbc21815cd69e0eddfee239167ac693fb0413912d816f2578a74f7716eecd6deefa68c6eccd394", "0xb885b3ace736cd373e8098bf75ba66fa1c6943ca1bc4408cd98ac7074775c4478594f91154b8a743d9c697e1b29f5840", "0xa51ce78de512bd87bfa0835de819941dffbf18bec23221b61d8096fc9436af64e0693c335b54e7bfc763f287bdca2db6", "0xa3c76166a3bdb9b06ef696e57603b58871bc72883ee9d45171a30fe6e1d50e30bc9c51b4a0f5a7270e19a77b89733850", "0xacefc5c6f8a1e7c24d7b41e0fc7f6f3dc0ede6cf3115ffb9a6e54b1d954cbca9bda8ad7a084be9be245a1b8e9770d141", "0xb420ed079941842510e31cfad117fa11fb6b4f97dfbc6298cb840f27ebaceba23eeaf3f513bcffbf5e4aae946310182d", "0x95c3bb5ef26c5ed2f035aa5d389c6b3c15a6705b9818a3fefaed28922158b35642b2e8e5a1a620fdad07e75ad4b43af4", "0x825149f9081ecf07a2a4e3e8b5d21bade86c1a882475d51c55ee909330b70c5a2ac63771c8600c6f38df716af61a3ea1", "0x873b935aae16d9f08adbc25353cee18af2f1b8d5f26dec6538d6bbddc515f2217ed7d235dcfea59ae61b428798b28637", "0x9294150843a2bedcedb3bb74c43eb28e759cf9499582c5430bccefb574a8ddd4f11f9929257ff4c153990f9970a2558f", "0xb619563a811cc531da07f4f04e5c4c6423010ff9f8ed7e6ec9449162e3d501b269fb1c564c09c0429431879b0f45df02", "0x91b509b87eb09f007d839627514658c7341bc76d468920fe8a740a8cb96a7e7e631e0ea584a7e3dc1172266f641d0f5c", "0x8b8aceace9a7b9b4317f1f01308c3904d7663856946afbcea141a1c615e21ccad06b71217413e832166e9dd915fbe098", "0x87b3b36e725833ea0b0f54753c3728c0dbc87c52d44d705ffc709f2d2394414c652d3283bab28dcce09799504996cee0", "0xb2670aad5691cbf308e4a6a77a075c4422e6cbe86fdba24e9f84a313e90b0696afb6a067eebb42ba2d10340d6a2f6e51", "0x876784a9aff3d54faa89b2bacd3ff5862f70195d0b2edc58e8d1068b3c9074c0da1cfa23671fe12f35e33b8a329c0ccd", "0x8b48b9e758e8a8eae182f5cbec96f67d20cca6d3eee80a2d09208eb1d5d872e09ef23d0df8ebbb9b01c7449d0e3e3650", "0xb79303453100654c04a487bdcadc9e3578bc80930c489a7069a52e8ca1dba36c492c8c899ce025f8364599899baa287d", "0x961b35a6111da54ece6494f24dacd5ea46181f55775b5f03df0e370c34a5046ac2b4082925855325bb42bc2a2c98381d", "0xa31feb1be3f5a0247a1f7d487987eb622e34fca817832904c6ee3ee60277e5847945a6f6ea1ac24542c72e47bdf647df", "0xa12a2aa3e7327e457e1aae30e9612715dd2cfed32892c1cd6dcda4e9a18203af8a44afb46d03b2eed89f6b9c5a2c0c23", "0xa08265a838e69a2ca2f80fead6ccf16f6366415b920c0b22ee359bcd8d4464ecf156f400a16a7918d52e6d733dd64211", "0xb723d6344e938d801cca1a00032af200e541d4471fd6cbd38fb9130daa83f6a1dffbbe7e67fc20f9577f884acd7594b2", "0xa6733d83ec78ba98e72ddd1e7ff79b7adb0e559e256760d0c590a986e742445e8cdf560d44b29439c26d87edd0b07c8c", "0xa61c2c27d3f7b9ff4695a17afedf63818d4bfba390507e1f4d0d806ce8778d9418784430ce3d4199fd3bdbc2504d2af3", "0x8332f3b63a6dc985376e8b1b25eeae68be6160fbe40053ba7bcf6f073204f682da72321786e422d3482fd60c9e5aa034", "0xa280f44877583fbb6b860d500b1a3f572e3ee833ec8f06476b3d8002058e25964062feaa1e5bec1536d734a5cfa09145", "0xa4026a52d277fcea512440d2204f53047718ebfcae7b48ac57ea7f6bfbc5de9d7304db9a9a6cbb273612281049ddaec5", "0x95cdf69c831ab2fad6c2535ede9c07e663d2ddccc936b64e0843d2df2a7b1c31f1759c3c20f1e7a57b1c8f0dbb21b540", "0x95c96cec88806469c277ab567863c5209027cecc06c7012358e5f555689c0d9a5ffb219a464f086b45817e8536b86d2f", "0xafe38d4684132a0f03d806a4c8df556bf589b25271fbc6fe2e1ed16de7962b341c5003755da758d0959d2e6499b06c68", "0xa9b77784fda64987f97c3a23c5e8f61b918be0f7c59ba285084116d60465c4a2aaafc8857eb16823282cc83143eb9126", "0xa830f05881ad3ce532a55685877f529d32a5dbe56cea57ffad52c4128ee0fad0eeaf0da4362b55075e77eda7babe70e5", "0x992b3ad190d6578033c13ed5abfee4ef49cbc492babb90061e3c51ee4b5790cdd4c8fc1abff1fa2c00183b6b64f0bbbe", "0xb1015424d9364aeff75de191652dc66484fdbec3e98199a9eb9671ec57bec6a13ff4b38446e28e4d8aedb58dd619cd90", "0xa745304604075d60c9db36cada4063ac7558e7ec2835d7da8485e58d8422e817457b8da069f56511b02601289fbb8981", "0xa5ba4330bc5cb3dbe0486ddf995632a7260a46180a08f42ae51a2e47778142132463cc9f10021a9ad36986108fefa1a9", "0xb419e9fd4babcaf8180d5479db188bb3da232ae77a1c4ed65687c306e6262f8083070a9ac32220cddb3af2ec73114092", "0xa49e23dc5f3468f3bf3a0bb7e4a114a788b951ff6f23a3396ae9e12cbff0abd1240878a3d1892105413dbc38818e807c", "0xb7ecc7b4831f650202987e85b86bc0053f40d983f252e9832ef503aea81c51221ce93279da4aa7466c026b2d2070e55d", "0x96a8c35cb87f84fa84dcd6399cc2a0fd79cc9158ef4bdde4bae31a129616c8a9f2576cd19baa3f497ca34060979aed7d", "0x8681b2c00aa62c2b519f664a95dcb8faef601a3b961bb4ce5d85a75030f40965e2983871d41ea394aee934e859581548", "0x85c229a07efa54a713d0790963a392400f55fbb1a43995a535dc6c929f20d6a65cf4efb434e0ad1cb61f689b8011a3bc", "0x90856f7f3444e5ad44651c28e24cc085a5db4d2ffe79aa53228c26718cf53a6e44615f3c5cda5aa752d5f762c4623c66", "0x978999b7d8aa3f28a04076f74d11c41ef9c89fdfe514936c4238e0f13c38ec97e51a5c078ebc6409e517bfe7ccb42630", "0xa099914dd7ed934d8e0d363a648e9038eb7c1ec03fa04dbcaa40f7721c618c3ef947afef7a16b4d7ac8c12aa46637f03", "0xab2a104fed3c83d16f2cda06878fa5f30c8c9411de71bfb67fd2fc9aa454dcbcf3d299d72f8cc12e919466a50fcf7426", "0xa4471d111db4418f56915689482f6144efc4664cfb0311727f36c864648d35734351becc48875df96f4abd3cfcf820f9", "0x83be11727cd30ea94ccc8fa31b09b81c9d6a9a5d3a4686af9da99587332fe78c1f94282f9755854bafd6033549afec91", "0x88020ff971dc1a01a9e993cd50a5d2131ffdcbb990c1a6aaa54b20d8f23f9546a70918ea57a21530dcc440c1509c24ad", "0xae24547623465e87905eaffa1fa5d52bb7c453a8dbd89614fa8819a2abcedaf455c2345099b7324ae36eb0ad7c8ef977", "0xb59b0c60997de1ee00b7c388bc7101d136c9803bf5437b1d589ba57c213f4f835a3e4125b54738e78abbc21b000f2016", "0xa584c434dfe194546526691b68fa968c831c31da42303a1d735d960901c74011d522246f37f299555416b8cf25c5a548", "0x80408ce3724f4837d4d52376d255e10f69eb8558399ae5ca6c11b78b98fe67d4b93157d2b9b639f1b5b64198bfe87713", "0xabb941e8d406c2606e0ddc35c113604fdd9d249eacc51cb64e2991e551b8639ce44d288cc92afa7a1e7fc599cfc84b22", "0xb223173f560cacb1c21dba0f1713839e348ad02cbfdef0626748604c86f89e0f4c919ed40b583343795bdd519ba952c8", "0xaf1c70512ec3a19d98b8a1fc3ff7f7f5048a27d17d438d43f561974bbdd116fcd5d5c21040f3447af3f0266848d47a15", "0x8a44809568ebe50405bede19b4d2607199159b26a1b33e03d180e6840c5cf59d991a4fb150d111443235d75ecad085b7", "0xb06207cdca46b125a27b3221b5b50cf27af4c527dd7c80e2dbcebbb09778a96df3af67e50f07725239ce3583dad60660", "0x993352d9278814ec89b26a11c4a7c4941bf8f0e6781ae79559d14749ee5def672259792db4587f85f0100c7bb812f933", "0x9180b8a718b971fd27bc82c8582d19c4b4f012453e8c0ffeeeffe745581fc6c07875ab28be3af3fa3896d19f0c89ac5b", "0x8b8e1263eb48d0fe304032dd5ea1f30e73f0121265f7458ba9054d3626894e8a5fef665340abd2ede9653045c2665938", "0x99a2beee4a10b7941c24b2092192faf52b819afd033e4a2de050fd6c7f56d364d0cf5f99764c3357cf32399e60fc5d74", "0x946a4aad7f8647ea60bee2c5fcdeb6f9a58fb2cfca70c4d10e458027a04846e13798c66506151be3df9454b1e417893f", "0xa672a88847652d260b5472d6908d1d57e200f1e492d30dd1cecc441cdfc9b76e016d9bab560efd4d7f3c30801de884a9", "0x9414e1959c156cde1eb24e628395744db75fc24b9df4595350aaad0bc38e0246c9b4148f6443ef68b8e253a4a6bcf11c", "0x9316e9e4ec5fab4f80d6540df0e3a4774db52f1d759d2e5b5bcd3d7b53597bb007eb1887cb7dc61f62497d51ffc8d996", "0x902d6d77bb49492c7a00bc4b70277bc28c8bf9888f4307bb017ac75a962decdedf3a4e2cf6c1ea9f9ba551f4610cbbd7", "0xb07025a18b0e32dd5e12ec6a85781aa3554329ea12c4cd0d3b2c22e43d777ef6f89876dd90a9c8fb097ddf61cf18adc5", "0xb355a849ad3227caa4476759137e813505ec523cbc2d4105bc7148a4630f9e81918d110479a2d5f5e4cd9ccec9d9d3e3", "0xb49532cfdf02ee760109881ad030b89c48ee3bb7f219ccafc13c93aead754d29bdafe345be54c482e9d5672bd4505080", "0x9477802410e263e4f938d57fa8f2a6cac7754c5d38505b73ee35ea3f057aad958cb9722ba6b7b3cfc4524e9ca93f9cdc", "0x9148ea83b4436339580f3dbc9ba51509e9ab13c03063587a57e125432dd0915f5d2a8f456a68f8fff57d5f08c8f34d6e", "0xb00b6b5392b1930b54352c02b1b3b4f6186d20bf21698689bbfc7d13e86538a4397b90e9d5c93fd2054640c4dbe52a4f", "0x926a9702500441243cd446e7cbf15dde16400259726794694b1d9a40263a9fc9e12f7bcbf12a27cb9aaba9e2d5848ddc", "0xa0c6155f42686cbe7684a1dc327100962e13bafcf3db97971fc116d9f5c0c8355377e3d70979cdbd58fd3ea52440901c", "0xa277f899f99edb8791889d0817ea6a96c24a61acfda3ad8c3379e7c62b9d4facc4b965020b588651672fd261a77f1bfc", "0x8f528cebb866b501f91afa50e995234bef5bf20bff13005de99cb51eaac7b4f0bf38580cfd0470de40f577ead5d9ba0f", "0x963fc03a44e9d502cc1d23250efef44d299befd03b898d07ce63ca607bb474b5cf7c965a7b9b0f32198b04a8393821f7", "0xab087438d0a51078c378bf4a93bd48ef933ff0f1fa68d02d4460820df564e6642a663b5e50a5fe509527d55cb510ae04", "0xb0592e1f2c54746bb076be0fa480e1c4bebc4225e1236bcda3b299aa3853e3afb401233bdbcfc4a007b0523a720fbf62", "0x851613517966de76c1c55a94dc4595f299398a9808f2d2f0a84330ba657ab1f357701d0895f658c18a44cb00547f6f57", "0xa2fe9a1dd251e72b0fe4db27be508bb55208f8f1616b13d8be288363ec722826b1a1fd729fc561c3369bf13950bf1fd6", "0xb896cb2bc2d0c77739853bc59b0f89b2e008ba1f701c9cbe3bef035f499e1baee8f0ff1e794854a48c320586a2dfc81a", "0xa1b60f98e5e5106785a9b81a85423452ee9ef980fa7fa8464f4366e73f89c50435a0c37b2906052b8e58e212ebd366cf", "0xa853b0ebd9609656636df2e6acd5d8839c0fda56f7bf9288a943b06f0b67901a32b95e016ca8bc99bd7b5eab31347e72", "0xb290fa4c1346963bd5225235e6bdf7c542174dab4c908ab483d1745b9b3a6015525e398e1761c90e4b49968d05e30eea", "0xb0f65a33ad18f154f1351f07879a183ad62e5144ad9f3241c2d06533dad09cbb2253949daff1bb02d24d16a3569f7ef0", "0xa00db59b8d4218faf5aeafcd39231027324408f208ec1f54d55a1c41228b463b88304d909d16b718cfc784213917b71e", "0xb8d695dd33dc2c3bc73d98248c535b2770ad7fa31aa726f0aa4b3299efb0295ba9b4a51c71d314a4a1bd5872307534d1", "0xb848057cca2ca837ee49c42b88422303e58ea7d2fc76535260eb5bd609255e430514e927cc188324faa8e657396d63ec", "0x92677836061364685c2aaf0313fa32322746074ed5666fd5f142a7e8f87135f45cd10e78a17557a4067a51dfde890371", "0xa854b22c9056a3a24ab164a53e5c5cf388616c33e67d8ebb4590cb16b2e7d88b54b1393c93760d154208b5ca822dc68f", "0x86fff174920388bfab841118fb076b2b0cdec3fdb6c3d9a476262f82689fb0ed3f1897f7be9dbf0932bb14d346815c63", "0x99661cf4c94a74e182752bcc4b98a8c2218a8f2765642025048e12e88ba776f14f7be73a2d79bd21a61def757f47f904", "0x8a8893144d771dca28760cba0f950a5d634195fd401ec8cf1145146286caffb0b1a6ba0c4c1828d0a5480ce49073c64c", "0x938a59ae761359ee2688571e7b7d54692848eb5dde57ffc572b473001ea199786886f8c6346a226209484afb61d2e526", "0x923f68a6aa6616714cf077cf548aeb845bfdd78f2f6851d8148cba9e33a374017f2f3da186c39b82d14785a093313222", "0xac923a93d7da7013e73ce8b4a2b14b8fd0cc93dc29d5de941a70285bdd19be4740fedfe0c56b046689252a3696e9c5bc", "0xb49b32c76d4ec1a2c68d4989285a920a805993bc6fcce6dacd3d2ddae73373050a5c44ba8422a3781050682fa0ef6ba2", "0x8a367941c07c3bdca5712524a1411bad7945c7c48ffc7103b1d4dff2c25751b0624219d1ccde8c3f70c465f954be5445", "0xb838f029df455efb6c530d0e370bbbf7d87d61a9aea3d2fe5474c5fe0a39cf235ceecf9693c5c6c5820b1ba8f820bd31", "0xa8983b7c715eaac7f13a001d2abc462dfc1559dab4a6b554119c271aa8fe00ffcf6b6949a1121f324d6d26cb877bcbae", "0xa2afb24ad95a6f14a6796315fbe0d8d7700d08f0cfaf7a2abe841f5f18d4fecf094406cbd54da7232a159f9c5b6e805e", "0x87e8e95ad2d62f947b2766ff405a23f7a8afba14e7f718a691d95369c79955cdebe24c54662553c60a3f55e6322c0f6f", "0x87c2cbcecb754e0cc96128e707e5c5005c9de07ffd899efa3437cadc23362f5a1d3fcdd30a1f5bdc72af3fb594398c2a", "0x91afd6ee04f0496dc633db88b9370d41c428b04fd991002502da2e9a0ef051bcd7b760e860829a44fbe5539fa65f8525", "0x8c50e5d1a24515a9dd624fe08b12223a75ca55196f769f24748686315329b337efadca1c63f88bee0ac292dd0a587440", "0x8a07e8f912a38d94309f317c32068e87f68f51bdfa082d96026f5f5f8a2211621f8a3856dda8069386bf15fb2d28c18f", "0x94ad1dbe341c44eeaf4dc133eed47d8dbfe752575e836c075745770a6679ff1f0e7883b6aa917462993a7f469d74cab5", "0x8745f8bd86c2bb30efa7efb7725489f2654f3e1ac4ea95bd7ad0f3cfa223055d06c187a16192d9d7bdaea7b050c6a324", "0x900d149c8d79418cda5955974c450a70845e02e5a4ecbcc584a3ca64d237df73987c303e3eeb79da1af83bf62d9e579f", "0x8f652ab565f677fb1a7ba03b08004e3cda06b86c6f1b0b9ab932e0834acf1370abb2914c15b0d08327b5504e5990681c", "0x9103097d088be1f75ab9d3da879106c2f597e2cc91ec31e73430647bdd5c33bcfd771530d5521e7e14df6acda44f38a6", "0xb0fec7791cfb0f96e60601e1aeced9a92446b61fedab832539d1d1037558612d78419efa87ff5f6b7aab8fd697d4d9de", "0xb9d2945bdb188b98958854ba287eb0480ef614199c4235ce5f15fc670b8c5ffe8eeb120c09c53ea8a543a022e6a321ac", "0xa9461bb7d5490973ebaa51afc0bb4a5e42acdccb80e2f939e88b77ac28a98870e103e1042899750f8667a8cc9123bae9", "0xa37fdf11d4bcb2aed74b9f460a30aa34afea93386fa4cdb690f0a71bc58f0b8df60bec56e7a24f225978b862626fa00e", "0xa214420e183e03d531cf91661466ea2187d84b6e814b8b20b3730a9400a7d25cf23181bb85589ebc982cec414f5c2923", "0xad09a45a698a6beb3e0915f540ef16e9af7087f53328972532d6b5dfe98ce4020555ece65c6cbad8bd6be8a4dfefe6fd", "0xab6742800b02728c92d806976764cb027413d6f86edd08ad8bb5922a2969ee9836878cd39db70db0bd9a2646862acc4f", "0x974ca9305bd5ea1dc1755dff3b63e8bfe9f744321046c1395659bcea2a987b528e64d5aa96ac7b015650b2253b37888d", "0x84eee9d6bce039c52c2ebc4fccc0ad70e20c82f47c558098da4be2f386a493cbc76adc795b5488c8d11b6518c2c4fab8", "0x875d7bda46efcb63944e1ccf760a20144df3b00d53282b781e95f12bfc8f8316dfe6492c2efbf796f1150e36e436e9df", "0xb68a2208e0c587b5c31b5f6cb32d3e6058a9642e2d9855da4f85566e1412db528475892060bb932c55b3a80877ad7b4a", "0xba006368ecab5febb6ab348644d9b63de202293085ed468df8bc24d992ae8ce468470aa37f36a73630c789fb9c819b30", "0x90a196035150846cd2b482c7b17027471372a8ce7d914c4d82b6ea7fa705d8ed5817bd42d63886242585baf7d1397a1c", "0xa223b4c85e0daa8434b015fd9170b5561fe676664b67064974a1e9325066ecf88fc81f97ab5011c59fad28cedd04b240", "0x82e8ec43139cf15c6bbeed484b62e06cded8a39b5ce0389e4cbe9c9e9c02f2f0275d8d8d4e8dfec8f69a191bef220408", "0x81a3fc07a7b68d92c6ee4b6d28f5653ee9ec85f7e2ee1c51c075c1b130a8c5097dc661cf10c5aff1c7114b1a6a19f11a", "0x8ed2ef8331546d98819a5dd0e6c9f8cb2630d0847671314a28f277faf68da080b53891dd75c82cbcf7788b255490785d", "0xacecabf84a6f9bbed6b2fc2e7e4b48f02ef2f15e597538a73aea8f98addc6badda15e4695a67ecdb505c1554e8f345ec", "0xb8f51019b2aa575f8476e03dcadf86cc8391f007e5f922c2a36b2daa63f5a503646a468990cd5c65148d323942193051", "0xaaa595a84b403ec65729bc1c8055a94f874bf9adddc6c507b3e1f24f79d3ad359595a672b93aab3394db4e2d4a7d8970", "0x895144c55fcbd0f64d7dd69e6855cfb956e02b5658eadf0f026a70703f3643037268fdd673b0d21b288578a83c6338dd", "0xa2e92ae6d0d237d1274259a8f99d4ea4912a299816350b876fba5ebc60b714490e198a916e1c38c6e020a792496fa23c", "0xa45795fda3b5bb0ad1d3c628f6add5b2a4473a1414c1a232e80e70d1cfffd7f8a8d9861f8df2946999d7dbb56bf60113", "0xb6659bf7f6f2fef61c39923e8c23b8c70e9c903028d8f62516d16755cd3fba2fe41c285aa9432dc75ab08f8a1d8a81fc", "0xa735609a6bc5bfd85e58234fc439ff1f58f1ff1dd966c5921d8b649e21f006bf2b8642ad8a75063c159aaf6935789293", "0xa3c622eb387c9d15e7bda2e3e84d007cb13a6d50d655c3f2f289758e49d3b37b9a35e4535d3cc53d8efd51f407281f19", "0x8afe147b53ad99220f5ef9d763bfc91f9c20caecbcf823564236fb0e6ede49414c57d71eec4772c8715cc65a81af0047", "0xb5f0203233cf71913951e9c9c4e10d9243e3e4a1f2cb235bf3f42009120ba96e04aa414c9938ea8873b63148478927e8", "0x93c52493361b458d196172d7ba982a90a4f79f03aa8008edc322950de3ce6acf4c3977807a2ffa9e924047e02072b229", "0xb9e72b805c8ac56503f4a86c82720afbd5c73654408a22a2ac0b2e5caccdfb0e20b59807433a6233bc97ae58cf14c70a", "0xaf0475779b5cee278cca14c82da2a9f9c8ef222eb885e8c50cca2315fea420de6e04146590ed0dd5a29c0e0812964df5", "0xb430ccab85690db02c2d0eb610f3197884ca12bc5f23c51e282bf3a6aa7e4a79222c3d8761454caf55d6c01a327595f9", "0x830032937418b26ee6da9b5206f3e24dc76acd98589e37937e963a8333e5430abd6ce3dd93ef4b8997bd41440eed75d6", "0x8820a6d73180f3fe255199f3f175c5eb770461ad5cfdde2fb11508041ed19b8c4ce66ad6ecebf7d7e836cc2318df47ca", "0xaef1393e7d97278e77bbf52ef6e1c1d5db721ccf75fe753cf47a881fa034ca61eaa5098ee5a344c156d2b14ff9e284ad", "0x8a4a26c07218948c1196c45d927ef4d2c42ade5e29fe7a91eaebe34a29900072ce5194cf28d51f746f4c4c649daf4396", "0x84011dc150b7177abdcb715efbd8c201f9cb39c36e6069af5c50a096021768ba40cef45b659c70915af209f904ede3b6", "0xb1bd90675411389bb66910b21a4bbb50edce5330850c5ab0b682393950124252766fc81f5ecfc72fb7184387238c402e", "0x8dfdcd30583b696d2c7744655f79809f451a60c9ad5bf1226dc078b19f4585d7b3ef7fa9d54e1ac09520d95cbfd20928", "0xb351b4dc6d98f75b8e5a48eb7c6f6e4b78451991c9ba630e5a1b9874c15ac450cd409c1a024713bf2cf82dc400e025ef", "0xa462b8bc97ac668b97b28b3ae24b9f5de60e098d7b23ecb600d2194cd35827fb79f77c3e50d358f5bd72ee83fef18fa0", "0xa183753265c5f7890270821880cce5f9b2965b115ba783c6dba9769536f57a04465d7da5049c7cf8b3fcf48146173c18", "0xa8a771b81ed0d09e0da4d79f990e58eabcd2be3a2680419502dd592783fe52f657fe55125b385c41d0ba3b9b9cf54a83", "0xa71ec577db46011689d073245e3b1c3222a9b1fe6aa5b83629adec5733dd48617ebea91346f0dd0e6cdaa86e4931b168", "0xa334b8b244f0d598a02da6ae0f918a7857a54dce928376c4c85df15f3b0f2ba3ac321296b8b7c9dd47d770daf16c8f8c", "0xa29037f8ef925c417c90c4df4f9fb27fb977d04e2b3dd5e8547d33e92ab72e7a00f5461de21e28835319eae5db145eb7", "0xb91054108ae78b00e3298d667b913ebc44d8f26e531eae78a8fe26fdfb60271c97efb2dee5f47ef5a3c15c8228138927", "0x926c13efbe90604f6244be9315a34f72a1f8d1aab7572df431998949c378cddbf2fe393502c930fff614ff06ae98a0ce", "0x995c758fd5600e6537089b1baa4fbe0376ab274ff3e82a17768b40df6f91c2e443411de9cafa1e65ea88fb8b87d504f4", "0x9245ba307a7a90847da75fca8d77ec03fdfc812c871e7a2529c56a0a79a6de16084258e7a9ac4ae8a3756f394336e21c", "0x99e0cfa2bb57a7e624231317044c15e52196ecce020db567c8e8cb960354a0be9862ee0c128c60b44777e65ac315e59f", "0xad4f6b3d27bbbb744126601053c3dc98c07ff0eb0b38a898bd80dce778372846d67e5ab8fb34fb3ad0ef3f235d77ba7f", "0xa0f12cae3722bbbca2e539eb9cc7614632a2aefe51410430070a12b5bc5314ecec5857b7ff8f41e9980cac23064f7c56", "0xb487f1bc59485848c98222fd3bc36c8c9bb3d2912e2911f4ceca32c840a7921477f9b1fe00877e05c96c75d3eecae061", "0xa6033db53925654e18ecb3ce715715c36165d7035db9397087ac3a0585e587998a53973d011ac6d48af439493029cee6", "0xa6b4d09cd01c70a3311fd131d3710ccf97bde3e7b80efd5a8c0eaeffeb48cca0f951ced905290267b115b06d46f2693b", "0xa9dff1df0a8f4f218a98b6f818a693fb0d611fed0fc3143537cbd6578d479af13a653a8155e535548a2a0628ae24fa58", "0xa58e469f65d366b519f9a394cacb7edaddac214463b7b6d62c2dbc1316e11c6c5184ce45c16de2d77f990dcdd8b55430", "0x989e71734f8119103586dc9a3c5f5033ddc815a21018b34c1f876cdfc112efa868d5751bf6419323e4e59fa6a03ece1c", "0xa2da00e05036c884369e04cf55f3de7d659cd5fa3f849092b2519dd263694efe0f051953d9d94b7e121f0aee8b6174d7", "0x968f3c029f57ee31c4e1adea89a7f92e28483af9a74f30fbdb995dc2d40e8e657dff8f8d340d4a92bf65f54440f2859f", "0x932778df6f60ac1639c1453ef0cbd2bf67592759dcccb3e96dcc743ff01679e4c7dd0ef2b0833dda548d32cb4eba49e2", "0xa805a31139f8e0d6dae1ac87d454b23a3dc9fc653d4ca18d4f8ebab30fc189c16e73981c2cb7dd6f8c30454a5208109d", "0xa9ba0991296caa2aaa4a1ceacfb205544c2a2ec97088eace1d84ee5e2767656a172f75d2f0c4e16a3640a0e0dec316e0", "0xb1e49055c968dced47ec95ae934cf45023836d180702e20e2df57e0f62fb85d7ac60d657ba3ae13b8560b67210449459", "0xa94e1da570a38809c71e37571066acabff7bf5632737c9ab6e4a32856924bf6211139ab3cedbf083850ff2d0e0c0fcfc", "0x88ef1bb322000c5a5515b310c838c9af4c1cdbb32eab1c83ac3b2283191cd40e9573747d663763a28dad0d64adc13840", "0xa987ce205f923100df0fbd5a85f22c9b99b9b9cbe6ddfa8dfda1b8fe95b4f71ff01d6c5b64ca02eb24edb2b255a14ef0", "0x84fe8221a9e95d9178359918a108de4763ebfa7a6487facb9c963406882a08a9a93f492f8e77cf9e7ea41ae079c45993", "0xaa1cf3dc7c5dcfa15bbbc811a4bb6dbac4fba4f97fb1ed344ab60264d7051f6eef19ea9773441d89929ee942ed089319", "0x8f6a7d610d59d9f54689bbe6a41f92d9f6096cde919c1ab94c3c7fcecf0851423bc191e5612349e10f855121c0570f56", "0xb5af1fa7894428a53ea520f260f3dc3726da245026b6d5d240625380bfb9c7c186df0204bb604efac5e613a70af5106e", "0xa5bce6055ff812e72ce105f147147c7d48d7a2313884dd1f488b1240ee320f13e8a33f5441953a8e7a3209f65b673ce1", "0xb9b55b4a1422677d95821e1d042ab81bbf0bf087496504021ec2e17e238c2ca6b44fb3b635a5c9eac0871a724b8d47c3", "0x941c38e533ce4a673a3830845b56786585e5fe49c427f2e5c279fc6db08530c8f91db3e6c7822ec6bb4f956940052d18", "0xa38e191d66c625f975313c7007bbe7431b5a06ed2da1290a7d5d0f2ec73770d476efd07b8e632de64597d47df175cbb0", "0x94ba76b667abf055621db4c4145d18743a368d951565632ed4e743dd50dd3333507c0c34f286a5c5fdbf38191a2255cd", "0xa5ca38c60be5602f2bfa6e00c687ac96ac36d517145018ddbee6f12eb0faa63dd57909b9eeed26085fe5ac44e55d10ab", "0xb00fea3b825e60c1ed1c5deb4b551aa65a340e5af36b17d5262c9cd2c508711e4dc50dc2521a2c16c7c901902266e64a", "0x971b86fc4033485e235ccb0997a236206ba25c6859075edbcdf3c943116a5030b7f75ebca9753d863a522ba21a215a90", "0xb3b31f52370de246ee215400975b674f6da39b2f32514fe6bd54e747752eedca22bb840493b44a67df42a3639c5f901f", "0xaffbbfac9c1ba7cbfa1839d2ae271dd6149869b75790bf103230637da41857fc326ef3552ff31c15bda0694080198143", "0xa95d42aa7ef1962520845aa3688f2752d291926f7b0d73ea2ee24f0612c03b43f2b0fe3c9a9a99620ffc8d487b981bc2", "0x914a266065caf64985e8c5b1cb2e3f4e3fe94d7d085a1881b1fefa435afef4e1b39a98551d096a62e4f5cc1a7f0fdc2e", "0x81a0b4a96e2b75bc1bf2dbd165d58d55cfd259000a35504d1ffb18bc346a3e6f07602c683723864ffb980f840836fd8d", "0x91c1556631cddd4c00b65b67962b39e4a33429029d311c8acf73a18600e362304fb68bccb56fde40f49e95b7829e0b87", "0x8befbacc19e57f7c885d1b7a6028359eb3d80792fe13b92a8400df21ce48deb0bb60f2ddb50e3d74f39f85d7eab23adc", "0x92f9458d674df6e990789690ec9ca73dacb67fc9255b58c417c555a8cc1208ace56e8e538f86ba0f3615573a0fbac00d", "0xb4b1b3062512d6ae7417850c08c13f707d5838e43d48eb98dd4621baf62eee9e82348f80fe9b888a12874bfa538771f8", "0xa13c4a3ac642ede37d9c883f5319e748d2b938f708c9d779714108a449b343f7b71a6e3ef4080fee125b416762920273", "0xaf44983d5fc8cceee0551ef934e6e653f2d3efa385e5c8a27a272463a6f333e290378cc307c2b664eb923c78994e706e", "0xa389fd6c59fe2b4031cc244e22d3991e541bd203dd5b5e73a6159e72df1ab41d49994961500dcde7989e945213184778", "0x8d2141e4a17836c548de9598d7b298b03f0e6c73b7364979a411c464e0628e21cff6ac3d6decdba5d1c4909eff479761", "0x980b22ef53b7bdf188a3f14bc51b0dbfdf9c758826daa3cbc1e3986022406a8aa9a6a79e400567120b88c67faa35ce5f", "0xa28882f0a055f96df3711de5d0aa69473e71245f4f3e9aa944e9d1fb166e02caa50832e46da6d3a03b4801735fd01b29", "0x8db106a37d7b88f5d995c126abb563934dd8de516af48e85695d02b1aea07f79217e3cdd03c6f5ca57421830186c772b", "0xb5a7e50da0559a675c472f7dfaee456caab6695ab7870541b2be8c2b118c63752427184aad81f0e1afc61aef1f28c46f", "0x9962118780e20fe291d10b64f28d09442a8e1b5cffd0f3dd68d980d0614050a626c616b44e9807fbee7accecae00686a", "0xb38ddf33745e8d2ad6a991aefaf656a33c5f8cbe5d5b6b6fd03bd962153d8fd0e01b5f8f96d80ae53ab28d593ab1d4e7", "0x857dc12c0544ff2c0c703761d901aba636415dee45618aba2e3454ff9cbc634a85c8b05565e88520ff9be2d097c8b2b1", "0xa80d465c3f8cc63af6d74a6a5086b626c1cb4a8c0fee425964c3bd203d9d7094e299f81ce96d58afc20c8c9a029d9dae", "0x89e1c8fbde8563763be483123a3ed702efac189c6d8ab4d16c85e74bbaf856048cc42d5d6e138633a38572ba5ec3f594", "0x893a594cf495535f6d216508f8d03c317dcf03446668cba688da90f52d0111ac83d76ad09bf5ea47056846585ee5c791", "0xaadbd8be0ae452f7f9450c7d2957598a20cbf10139a4023a78b4438172d62b18b0de39754dd2f8862dbd50a3a0815e53", "0xae7d39670ecca3eb6db2095da2517a581b0e8853bdfef619b1fad9aacd443e7e6a40f18209fadd44038a55085c5fe8b2", "0x866ef241520eacb6331593cfcb206f7409d2f33d04542e6e52cba5447934e02d44c471f6c9a45963f9307e9809ab91d9", "0xb1a09911ad3864678f7be79a9c3c3eb5c84a0a45f8dcb52c67148f43439aeaaa9fd3ed3471276b7e588b49d6ebe3033a", "0xadd07b7f0dbb34049cd8feeb3c18da5944bf706871cfd9f14ff72f6c59ad217ebb1f0258b13b167851929387e4e34cfe", "0xae048892d5c328eefbdd4fba67d95901e3c14d974bfc0a1fc68155ca9f0d59e61d7ba17c6c9948b120cf35fd26e6fee9", "0x9185b4f3b7da0ddb4e0d0f09b8a9e0d6943a4611e43f13c3e2a767ed8592d31e0ba3ebe1914026a3627680274291f6e5", "0xa9c022d4e37b0802284ce3b7ee9258628ab4044f0db4de53d1c3efba9de19d15d65cc5e608dbe149c21c2af47d0b07b5", "0xb24dbd5852f8f24921a4e27013b6c3fa8885b973266cb839b9c388efad95821d5d746348179dcc07542bd0d0aefad1ce", "0xb5fb4f279300876a539a27a441348764908bc0051ebd66dc51739807305e73db3d2f6f0f294ffb91b508ab150eaf8527", "0xace50841e718265b290c3483ed4b0fdd1175338c5f1f7530ae9a0e75d5f80216f4de37536adcbc8d8c95982e88808cd0", "0xb19cadcde0f63bd1a9c24bd9c2806f53c14c0b9735bf351601498408ba503ddbd2037c891041cbba47f58b8c483f3b21", "0xb6061e63558d312eb891b97b39aa552fa218568d79ee26fe6dd5b864aea9e3216d8f2e2f3b093503be274766dac41426", "0x89730fdb2876ab6f0fe780d695f6e12090259027e789b819956d786e977518057e5d1d7f5ab24a3ae3d5d4c97773bd2b", "0xb6fa841e81f9f2cad0163a02a63ae96dc341f7ae803b616efc6e1da2fbea551c1b96b11ad02c4afbdf6d0cc9f23da172", "0x8fb66187182629c861ddb6896d7ed3caf2ad050c3dba8ab8eb0d7a2c924c3d44c48d1a148f9e33fb1f061b86972f8d21", "0x86022ac339c1f84a7fa9e05358c1a5b316b4fc0b83dbe9c8c7225dc514f709d66490b539359b084ce776e301024345fa", "0xb50b9c321468da950f01480bb62b6edafd42f83c0001d6e97f2bd523a1c49a0e8574fb66380ea28d23a7c4d54784f9f0", "0xa31c05f7032f30d1dac06678be64d0250a071fd655e557400e4a7f4c152be4d5c7aa32529baf3e5be7c4bd49820054f6", "0xb95ac0848cd322684772119f5b682d90a66bbf9dac411d9d86d2c34844bbd944dbaf8e47aa41380455abd51687931a78", "0xae4a6a5ce9553b65a05f7935e61e496a4a0f6fd8203367a2c627394c9ce1e280750297b74cdc48fd1d9a31e93f97bef4", "0xa22daf35f6e9b05e52e0b07f7bd1dbbebd2c263033fb0e1b2c804e2d964e2f11bc0ece6aca6af079dd3a9939c9c80674", "0x902150e0cb1f16b9b59690db35281e28998ce275acb313900da8b2d8dfd29fa1795f8ca3ff820c31d0697de29df347c1", "0xb17b5104a5dc665cdd7d47e476153d715eb78c6e5199303e4b5445c21a7fa7cf85fe7cfd08d7570f4e84e579b005428c", "0xa03f49b81c15433f121680aa02d734bb9e363af2156654a62bcb5b2ba2218398ccb0ff61104ea5d7df5b16ea18623b1e", "0x802101abd5d3c88876e75a27ffc2f9ddcce75e6b24f23dba03e5201281a7bd5cc7530b6a003be92d225093ca17d3c3bb", "0xa4d183f63c1b4521a6b52226fc19106158fc8ea402461a5cccdaa35fee93669df6a8661f45c1750cd01308149b7bf08e", "0x8d17c22e0c8403b69736364d460b3014775c591032604413d20a5096a94d4030d7c50b9fe3240e31d0311efcf9816a47", "0x947225acfcce5992eab96276f668c3cbe5f298b90a59f2bb213be9997d8850919e8f496f182689b5cbd54084a7332482", "0x8df6f4ed216fc8d1905e06163ba1c90d336ab991a18564b0169623eb39b84e627fa267397da15d3ed754d1f3423bff07", "0x83480007a88f1a36dea464c32b849a3a999316044f12281e2e1c25f07d495f9b1710b4ba0d88e9560e72433addd50bc2", "0xb3019d6e591cf5b33eb972e49e06c6d0a82a73a75d78d383dd6f6a4269838289e6e07c245f54fed67f5c9bb0fd5e1c5f", "0x92e8ce05e94927a9fb02debadb99cf30a26172b2705003a2c0c47b3d8002bf1060edb0f6a5750aad827c98a656b19199", "0xac2aff801448dbbfc13cca7d603fd9c69e82100d997faf11f465323b97255504f10c0c77401e4d1890339d8b224f5803", "0xb0453d9903d08f508ee27e577445dc098baed6cde0ac984b42e0f0efed62760bd58d5816cf1e109d204607b7b175e30c", "0xae68dc4ba5067e825d46d2c7c67f1009ceb49d68e8d3e4c57f4bcd299eb2de3575d42ea45e8722f8f28497a6e14a1cfe", "0xb22486c2f5b51d72335ce819bbafb7fa25eb1c28a378a658f13f9fc79cd20083a7e573248d911231b45a5cf23b561ca7", "0x89d1201d1dbd6921867341471488b4d2fd0fc773ae1d4d074c78ae2eb779a59b64c00452c2a0255826fca6b3d03be2b1", "0xa2998977c91c7a53dc6104f5bc0a5b675e5350f835e2f0af69825db8af4aeb68435bdbcc795f3dd1f55e1dd50bc0507f", "0xb0be4937a925b3c05056ed621910d535ccabf5ab99fd3b9335080b0e51d9607d0fd36cb5781ff340018f6acfca4a9736", "0xaea145a0f6e0ba9df8e52e84bb9c9de2c2dc822f70d2724029b153eb68ee9c17de7d35063dcd6a39c37c59fdd12138f7", "0x91cb4545d7165ee8ffbc74c874baceca11fdebbc7387908d1a25877ca3c57f2c5def424dab24148826832f1e880bede0", "0xb3b579cb77573f19c571ad5eeeb21f65548d7dff9d298b8d7418c11f3e8cd3727c5b467f013cb87d6861cfaceee0d2e3", "0xb98a1eeec2b19fecc8378c876d73645aa52fb99e4819903735b2c7a885b242787a30d1269a04bfb8573d72d9bbc5f0f0", "0x940c1f01ed362bd588b950c27f8cc1d52276c71bb153d47f07ec85b038c11d9a8424b7904f424423e714454d5e80d1cd", "0xaa343a8ecf09ce11599b8cf22f7279cf80f06dbf9f6d62cb05308dbbb39c46fd0a4a1240b032665fbb488a767379b91b", "0x87c3ac72084aca5974599d3232e11d416348719e08443acaba2b328923af945031f86432e170dcdd103774ec92e988c9", "0x91d6486eb5e61d2b9a9e742c20ec974a47627c6096b3da56209c2b4e4757f007e793ebb63b2b246857c9839b64dc0233", "0xaebcd3257d295747dd6fc4ff910d839dd80c51c173ae59b8b2ec937747c2072fa85e3017f9060aa509af88dfc7529481", "0xb3075ba6668ca04eff19efbfa3356b92f0ab12632dcda99cf8c655f35b7928c304218e0f9799d68ef9f809a1492ff7db", "0x93ba7468bb325639ec2abd4d55179c69fd04eaaf39fc5340709227bbaa4ad0a54ea8b480a1a3c8d44684e3be0f8d1980", "0xa6aef86c8c0d92839f38544d91b767c582568b391071228ff5a5a6b859c87bf4f81a7d926094a4ada1993ddbd677a920", "0x91dcd6d14207aa569194aa224d1e5037b999b69ade52843315ca61ba26abe9a76412c9e88259bc5cf5d7b95b97d9c3bc", "0xb3b483d31c88f78d49bd065893bc1e3d2aa637e27dedb46d9a7d60be7660ce7a10aaaa7deead362284a52e6d14021178", "0x8e5730070acf8371461ef301cc4523e8e672aa0e3d945d438a0e0aa6bdf8cb9c685dcf38df429037b0c8aff3955c6f5b", "0xb8c6d769890a8ee18dc4f9e917993315877c97549549b34785a92543cbeec96a08ae3a28d6e809c4aacd69de356c0012", "0x95ca86cd384eaceaa7c077c5615736ca31f36824bd6451a16142a1edc129fa42b50724aeed7c738f08d7b157f78b569e", "0x94df609c6d71e8eee7ab74226e371ccc77e01738fe0ef1a6424435b4570fe1e5d15797b66ed0f64eb88d4a3a37631f0e", "0x89057b9783212add6a0690d6bb99097b182738deff2bd9e147d7fd7d6c8eacb4c219923633e6309ad993c24572289901", "0x83a0f9f5f265c5a0e54defa87128240235e24498f20965009fef664f505a360b6fb4020f2742565dfc7746eb185bcec0", "0x91170da5306128931349bc3ed50d7df0e48a68b8cc8420975170723ac79d8773e4fa13c5f14dc6e3fafcad78379050b1", "0xb7178484d1b55f7e56a4cc250b6b2ec6040437d96bdfddfa7b35ed27435860f3855c2eb86c636f2911b012eb83b00db8", "0xac0b00c4322d1e4208e09cd977b4e54d221133ff09551f75b32b0b55d0e2be80941dda26257b0e288c162e63c7e9cf68", "0x9690ed9e7e53ed37ff362930e4096b878b12234c332fd19d5d064824084245952eda9f979e0098110d6963e468cf513e", "0xb6fa547bb0bb83e5c5be0ed462a8783fba119041c136a250045c09d0d2af330c604331e7de960df976ff76d67f8000cd", "0x814603907c21463bcf4e59cfb43066dfe1a50344ae04ef03c87c0f61b30836c3f4dea0851d6fa358c620045b7f9214c8", "0x9495639e3939fad2a3df00a88603a5a180f3c3a0fe4d424c35060e2043e0921788003689887b1ed5be424d9a89bb18bb", "0xaba4c02d8d57f2c92d5bc765885849e9ff8393d6554f5e5f3e907e5bfac041193a0d8716d7861104a4295d5a03c36b03", "0x8ead0b56c1ca49723f94a998ba113b9058059321da72d9e395a667e6a63d5a9dac0f5717cec343f021695e8ced1f72af", "0xb43037f7e3852c34ed918c5854cd74e9d5799eeddfe457d4f93bb494801a064735e326a76e1f5e50a339844a2f4a8ec9", "0x99db8422bb7302199eb0ff3c3d08821f8c32f53a600c5b6fb43e41205d96adae72be5b460773d1280ad1acb806af9be8", "0x8a9be08eae0086c0f020838925984df345c5512ff32e37120b644512b1d9d4fecf0fd30639ca90fc6cf334a86770d536", "0x81b43614f1c28aa3713a309a88a782fb2bdfc4261dd52ddc204687791a40cf5fd6a263a8179388596582cccf0162efc2", "0xa9f3a8b76912deb61d966c75daf5ddb868702ebec91bd4033471c8e533183df548742a81a2671de5be63a502d827437d", "0x902e2415077f063e638207dc7e14109652e42ab47caccd6204e2870115791c9defac5425fd360b37ac0f7bd8fe7011f8", "0xaa18e4fdc1381b59c18503ae6f6f2d6943445bd00dd7d4a2ad7e5adad7027f2263832690be30d456e6d772ad76f22350", "0xa348b40ba3ba7d81c5d4631f038186ebd5e5f314f1ea737259151b07c3cc8cf0c6ed4201e71bcc1c22fefda81a20cde6", "0xaa1306f7ac1acbfc47dc6f7a0cb6d03786cec8c8dc8060388ccda777bca24bdc634d03e53512c23dba79709ff64f8620", "0x818ccfe46e700567b7f3eb400e5a35f6a5e39b3db3aa8bc07f58ace35d9ae5a242faf8dbccd08d9a9175bbce15612155", "0xb7e3da2282b65dc8333592bb345a473f03bd6df69170055fec60222de9897184536bf22b9388b08160321144d0940279", "0xa4d976be0f0568f4e57de1460a1729129252b44c552a69fceec44e5b97c96c711763360d11f9e5bf6d86b4976bf40d69", "0x85d185f0397c24c2b875b09b6328a23b87982b84ee880f2677a22ff4c9a1ba9f0fea000bb3f7f66375a00d98ebafce17", "0xb4ccbb8c3a2606bd9b87ce022704663af71d418351575f3b350d294f4efc68c26f9a2ce49ff81e6ff29c3b63d746294e", "0x93ffd3265fddb63724dfde261d1f9e22f15ecf39df28e4d89e9fea03221e8e88b5dd9b77628bacaa783c6f91802d47cc", "0xb1fd0f8d7a01378e693da98d03a2d2fda6b099d03454b6f2b1fa6472ff6bb092751ce6290059826b74ac0361eab00e1e", "0xa89f440c71c561641589796994dd2769616b9088766e983c873fae0716b95c386c8483ab8a4f367b6a68b72b7456dd32", "0xaf4fe92b01d42d03dd5d1e7fa55e96d4bbcb7bf7d4c8c197acd16b3e0f3455807199f683dcd263d74547ef9c244b35cc", "0xa8227f6e0a344dfe76bfbe7a1861be32c4f4bed587ccce09f9ce2cf481b2dda8ae4f566154bc663d15f962f2d41761bd", "0xa7b361663f7495939ed7f518ba45ea9ff576c4e628995b7aea026480c17a71d63fc2c922319f0502eb7ef8f14a406882", "0x8ddcf382a9f39f75777160967c07012cfa89e67b19714a7191f0c68eaf263935e5504e1104aaabd0899348c972a8d3c6", "0x98c95b9f6f5c91f805fb185eedd06c6fc4457d37dd248d0be45a6a168a70031715165ea20606245cbdf8815dc0ac697f", "0x805b44f96e001e5909834f70c09be3efcd3b43632bcac5b6b66b6d227a03a758e4b1768ce2a723045681a1d34562aaeb", "0xb0e81b07cdc45b3dca60882676d9badb99f25c461b7efe56e3043b80100bb62d29e1873ae25eb83087273160ece72a55", "0xb0c53f0abe78ee86c7b78c82ae1f7c070bb0b9c45c563a8b3baa2c515d482d7507bb80771e60b38ac13f78b8af92b4a9", "0xa7838ef6696a9e4d2e5dfd581f6c8d6a700467e8fd4e85adabb5f7a56f514785dd4ab64f6f1b48366f7d94728359441b", "0x88c76f7700a1d23c30366a1d8612a796da57b2500f97f88fdf2d76b045a9d24e7426a8ffa2f4e86d3046937a841dad58", "0xad8964baf98c1f02e088d1d9fcb3af6b1dfa44cdfe0ed2eae684e7187c33d3a3c28c38e8f4e015f9c04d451ed6f85ff6", "0x90e9d00a098317ececaa9574da91fc149eda5b772dedb3e5a39636da6603aa007804fa86358550cfeff9be5a2cb7845e", "0xa56ff4ddd73d9a6f5ab23bb77efa25977917df63571b269f6a999e1ad6681a88387fcc4ca3b26d57badf91b236503a29", "0x97ad839a6302c410a47e245df84c01fb9c4dfef86751af3f9340e86ff8fc3cd52fa5ff0b9a0bd1d9f453e02ca80658a6", "0xa4c8c44cbffa804129e123474854645107d1f0f463c45c30fd168848ebea94880f7c0c5a45183e9eb837f346270bdb35", "0xa72e53d0a1586d736e86427a93569f52edd2f42b01e78aee7e1961c2b63522423877ae3ac1227a2cf1e69f8e1ff15bc3", "0x8559f88a7ef13b4f09ac82ae458bbae6ab25671cfbf52dae7eac7280d6565dd3f0c3286aec1a56a8a16dc3b61d78ce47", "0x8221503f4cdbed550876c5dc118a3f2f17800c04e8be000266633c83777b039a432d576f3a36c8a01e8fd18289ebc10b", "0x99bfbe5f3e46d4d898a578ba86ed26de7ed23914bd3bcdf3c791c0bcd49398a52419077354a5ab75cea63b6c871c6e96", "0xaa134416d8ff46f2acd866c1074af67566cfcf4e8be8d97329dfa0f603e1ff208488831ce5948ac8d75bfcba058ddcaa", "0xb02609d65ebfe1fe8e52f21224a022ea4b5ea8c1bd6e7b9792eed8975fc387cdf9e3b419b8dd5bcce80703ab3a12a45f", "0xa4f14798508698fa3852e5cac42a9db9797ecee7672a54988aa74037d334819aa7b2ac7b14efea6b81c509134a6b7ad2", "0x884f01afecbcb987cb3e7c489c43155c416ed41340f61ecb651d8cba884fb9274f6d9e7e4a46dd220253ae561614e44c", "0xa05523c9e71dce1fe5307cc71bd721feb3e1a0f57a7d17c7d1c9fb080d44527b7dbaa1f817b1af1c0b4322e37bc4bb1e", "0x8560aec176a4242b39f39433dd5a02d554248c9e49d3179530815f5031fee78ba9c71a35ceeb2b9d1f04c3617c13d8f0", "0x996aefd402748d8472477cae76d5a2b92e3f092fc834d5222ae50194dd884c9fb8b6ed8e5ccf8f6ed483ddbb4e80c747", "0x8fd09900320000cbabc40e16893e2fcf08815d288ec19345ad7b6bb22f7d78a52b6575a3ca1ca2f8bc252d2eafc928ec", "0x939e51f73022bc5dc6862a0adf8fb8a3246b7bfb9943cbb4b27c73743926cc20f615a036c7e5b90c80840e7f1bfee0e7", "0xa0a6258700cadbb9e241f50766573bf9bdb7ad380b1079dc3afb4054363d838e177b869cad000314186936e40359b1f2", "0x972699a4131c8ed27a2d0e2104d54a65a7ff1c450ad9da3a325c662ab26869c21b0a84d0700b98c8b5f6ce3b746873d7", "0xa454c7fe870cb8aa6491eafbfb5f7872d6e696033f92e4991d057b59d70671f2acdabef533e229878b60c7fff8f748b1", "0xa167969477214201f09c79027b10221e4707662e0c0fde81a0f628249f2f8a859ce3d30a7dcc03b8ecca8f7828ad85c7", "0x8ff6b7265175beb8a63e1dbf18c9153fb2578c207c781282374f51b40d57a84fd2ef2ea2b9c6df4a54646788a62fd17f", "0xa3d7ebeccde69d73d8b3e76af0da1a30884bb59729503ff0fb0c3bccf9221651b974a6e72ea33b7956fc3ae758226495", "0xb71ef144c9a98ce5935620cb86c1590bd4f48e5a2815d25c0cdb008fde628cf628c31450d3d4f67abbfeb16178a74cfd", "0xb5e0a16d115134f4e2503990e3f2035ed66b9ccf767063fe6747870d97d73b10bc76ed668550cb82eedc9a2ca6f75524", "0xb30ffaaf94ee8cbc42aa2c413175b68afdb207dbf351fb20be3852cb7961b635c22838da97eaf43b103aff37e9e725cc", "0x98aa7d52284f6c1f22e272fbddd8c8698cf8f5fbb702d5de96452141fafb559622815981e50b87a72c2b1190f59a7deb", "0x81fbacda3905cfaf7780bb4850730c44166ed26a7c8d07197a5d4dcd969c09e94a0461638431476c16397dd7bdc449f9", "0x95e47021c1726eac2e5853f570d6225332c6e48e04c9738690d53e07c6b979283ebae31e2af1fc9c9b3e59f87e5195b1", "0xac024a661ba568426bb8fce21780406537f518075c066276197300841e811860696f7588188bc01d90bace7bc73d56e3", "0xa4ebcaf668a888dd404988ab978594dee193dad2d0aec5cdc0ccaf4ec9a7a8228aa663db1da8ddc52ec8472178e40c32", "0xa20421b8eaf2199d93b083f2aff37fb662670bd18689d046ae976d1db1fedd2c2ff897985ecc6277b396db7da68bcb27", "0x8bc33d4b40197fd4d49d1de47489d10b90d9b346828f53a82256f3e9212b0cbc6930b895e879da9cec9fedf026aadb3e", "0xaaafdd1bec8b757f55a0433eddc0a39f818591954fd4e982003437fcceb317423ad7ee74dbf17a2960380e7067a6b4e2", "0xaad34277ebaed81a6ec154d16736866f95832803af28aa5625bf0461a71d02b1faba02d9d9e002be51c8356425a56867", "0x976e9c8b150d08706079945bd0e84ab09a648ecc6f64ded9eb5329e57213149ae409ae93e8fbd8eda5b5c69f5212b883", "0x8097fae1653247d2aed4111533bc378171d6b2c6d09cbc7baa9b52f188d150d645941f46d19f7f5e27b7f073c1ebd079", "0x83905f93b250d3184eaba8ea7d727c4464b6bdb027e5cbe4f597d8b9dc741dcbea709630bd4fd59ce24023bec32fc0f3", "0x8095030b7045cff28f34271386e4752f9a9a0312f8df75de4f424366d78534be2b8e1720a19cb1f9a2d21105d790a225", "0xa7b7b73a6ae2ed1009c49960374b0790f93c74ee03b917642f33420498c188a169724945a975e5adec0a1e83e07fb1b2", "0x856a41c54df393b6660b7f6354572a4e71c8bfca9cabaffb3d4ef2632c015e7ee2bc10056f3eccb3dbed1ad17d939178", "0xa8f7a55cf04b38cd4e330394ee6589da3a07dc9673f74804fdf67b364e0b233f14aec42e783200a2e4666f7c5ff62490", "0x82c529f4e543c6bca60016dc93232c115b359eaee2798a9cf669a654b800aafe6ab4ba58ea8b9cdda2b371c8d62fa845", "0x8caab020c1baddce77a6794113ef1dfeafc5f5000f48e97f4351b588bf02f1f208101745463c480d37f588d5887e6d8c", "0x8fa91b3cc400f48b77b6fd77f3b3fbfb3f10cdff408e1fd22d38f77e087b7683adad258804409ba099f1235b4b4d6fea", "0x8aa02787663d6be9a35677d9d8188b725d5fcd770e61b11b64e3def8808ea5c71c0a9afd7f6630c48634546088fcd8e2", "0xb5635b7b972e195cab878b97dea62237c7f77eb57298538582a330b1082f6207a359f2923864630136d8b1f27c41b9aa", "0x8257bb14583551a65975946980c714ecd6e5b629672bb950b9caacd886fbd22704bc9e3ba7d30778adab65dc74f0203a", "0xab5fe1cd12634bfa4e5c60d946e2005cbd38f1063ec9a5668994a2463c02449a0a185ef331bd86b68b6e23a8780cb3ba", "0xa7d3487da56cda93570cc70215d438204f6a2709bfb5fda6c5df1e77e2efc80f4235c787e57fbf2c74aaff8cbb510a14", "0xb61cff7b4c49d010e133319fb828eb900f8a7e55114fc86b39c261a339c74f630e1a7d7e1350244ada566a0ff3d46c4b", "0x8d4d1d55d321d278db7a85522ccceca09510374ca81d4d73e3bb5249ace7674b73900c35a531ec4fa6448fabf7ad00dc", "0x966492248aee24f0f56c8cfca3c8ec6ba3b19abb69ae642041d4c3be8523d22c65c4dafcab4c58989ccc4e0bd2f77919", "0xb20c320a90cb220b86e1af651cdc1e21315cd215da69f6787e28157172f93fc8285dcd59b039c626ed8ca4633cba1a47", "0xaae9e6b22f018ceb5c0950210bb8182cb8cb61014b7e14581a09d36ebd1bbfebdb2b82afb7fdb0cf75e58a293d9c456d", "0x875547fb67951ad37b02466b79f0c9b985ccbc500cfb431b17823457dc79fb9597ec42cd9f198e15523fcd88652e63a4", "0x92afce49773cb2e20fb21e4f86f18e0959ebb9c33361547ddb30454ee8e36b1e234019cbdca0e964cb292f7f77df6b90", "0x8af85343dfe1821464c76ba11c216cbef697b5afc69c4d821342e55afdac047081ec2e3f7b09fc14b518d9a23b78c003", "0xb7de4a1648fd63f3a918096ea669502af5357438e69dac77cb8102b6e6c15c76e033cfaa80dafc806e535ede5c1a20aa", "0xac80e9b545e8bd762951d96c9ce87f629d01ffcde07efc2ef7879ca011f1d0d8a745abf26c9d452541008871304fac00", "0xa4cf0f7ed724e481368016c38ea5816698a5f68eb21af4d3c422d2ba55f96a33e427c2aa40de1b56a7cfac7f7cf43ab0", "0x899b0a678bb2db2cae1b44e75a661284844ebcdd87abf308fedeb2e4dbe5c5920c07db4db7284a7af806a2382e8b111a", "0xaf0588a2a4afce2b1b13c1230816f59e8264177e774e4a341b289a101dcf6af813638fed14fb4d09cb45f35d5d032609", "0xa4b8df79e2be76e9f5fc5845f06fe745a724cf37c82fcdb72719b77bdebea3c0e763f37909373e3a94480cc5e875cba0", "0x83e42c46d88930c8f386b19fd999288f142d325e2ebc86a74907d6d77112cb0d449bc511c95422cc810574031a8cbba9", "0xb5e39534070de1e5f6e27efbdd3dc917d966c2a9b8cf2d893f964256e95e954330f2442027dc148c776d63a95bcde955", "0x958607569dc28c075e658cd4ae3927055c6bc456eef6212a6fea8205e48ed8777a8064f584cda38fe5639c371e2e7fba", "0x812adf409fa63575113662966f5078a903212ffb65c9b0bbe62da0f13a133443a7062cb8fd70f5e5dd5559a32c26d2c8", "0xa679f673e5ce6a3cce7fa31f22ee3785e96bcb55e5a776e2dd3467bef7440e3555d1a9b87cb215e86ee9ed13a090344b", "0xafedbb34508b159eb25eb2248d7fe328f86ef8c7d84c62d5b5607d74aae27cc2cc45ee148eb22153b09898a835c58df4", "0xb75505d4f6b67d31e665cfaf5e4acdb5838ae069166b7fbcd48937c0608a59e40a25302fcc1873d2e81c1782808c70f0", "0xb62515d539ec21a155d94fc00ea3c6b7e5f6636937bce18ed5b618c12257fb82571886287fd5d1da495296c663ebc512", "0xab8e1a9446bbdd588d1690243b1549d230e6149c28f59662b66a8391a138d37ab594df38e7720fae53217e5c3573b5be", "0xb31e8abf4212e03c3287bb2c0a153065a7290a16764a0bac8f112a72e632185a654bb4e88fdd6053e6c7515d9719fadb", "0xb55165477fe15b6abd2d0f4fddaa9c411710dcc4dd712daba3d30e303c9a3ee5415c256f9dc917ecf18c725b4dbab059", "0xa0939d4f57cacaae549b78e87cc234de4ff6a35dc0d9cd5d7410abc30ebcd34c135e008651c756e5a9d2ca79c40ef42b", "0x8cf10e50769f3443340844aad4d56ec790850fed5a41fcbd739abac4c3015f0a085a038fbe7fae9f5ad899cce5069f6b", "0x924055e804d82a99ea4bb160041ea4dc14b568abf379010bc1922fde5d664718c31d103b8b807e3a1ae809390e708c73", "0x8ec0f9d26f71b0f2e60a179e4fd1778452e2ffb129d50815e5d7c7cb9415fa69ae5890578086e8ef6bfde35ad2a74661", "0x98c7f12b15ec4426b59f737f73bf5faea4572340f4550b7590dfb7f7ffedb2372e3e555977c63946d579544c53210ad0", "0x8a935f7a955c78f69d66f18eee0092e5e833fa621781c9581058e219af4d7ceee48b84e472e159dda6199715fb2f9acf", "0xb78d4219f95a2dbfaa7d0c8a610c57c358754f4f43c2af312ab0fe8f10a5f0177e475332fb8fd23604e474fc2abeb051", "0x8d086a14803392b7318c28f1039a17e3cfdcece8abcaca3657ec3d0ac330842098a85c0212f889fabb296dfb133ce9aa", "0xa53249f417aac82f2c2a50c244ce21d3e08a5e5a8bd33bec2a5ab0d6cd17793e34a17edfa3690899244ce201e2fb9986", "0x8619b0264f9182867a1425be514dc4f1ababc1093138a728a28bd7e4ecc99b9faaff68c23792264bc6e4dce5f52a5c52", "0x8c171edbbbde551ec19e31b2091eb6956107dd9b1f853e1df23bff3c10a3469ac77a58335eee2b79112502e8e163f3de", "0xa9d19ec40f0ca07c238e9337c6d6a319190bdba2db76fb63902f3fb459aeeb50a1ac30db5b25ee1b4201f3ca7164a7f4", "0xb9c6ec14b1581a03520b8d2c1fbbc31fb8ceaef2c0f1a0d0080b6b96e18442f1734bea7ef7b635d787c691de4765d469", "0x8cb437beb4cfa013096f40ccc169a713dc17afee6daa229a398e45fd5c0645a9ad2795c3f0cd439531a7151945d7064d", "0xa6e8740cc509126e146775157c2eb278003e5bb6c48465c160ed27888ca803fa12eee1f6a8dd7f444f571664ed87fdc1", "0xb75c1fecc85b2732e96b3f23aefb491dbd0206a21d682aee0225838dc057d7ed3b576176353e8e90ae55663f79e986e4", "0xad8d249b0aea9597b08358bce6c77c1fd552ef3fbc197d6a1cfe44e5e6f89b628b12a6fb04d5dcfcbacc51f46e4ae7bb", "0xb998b2269932cbd58d04b8e898d373ac4bb1a62e8567484f4f83e224061bc0f212459f1daae95abdbc63816ae6486a55", "0x827988ef6c1101cddc96b98f4a30365ff08eea2471dd949d2c0a9b35c3bbfa8c07054ad1f4c88c8fbf829b20bb5a9a4f", "0x8692e638dd60babf7d9f2f2d2ce58e0ac689e1326d88311416357298c6a2bffbfebf55d5253563e7b3fbbf5072264146", "0xa685d75b91aea04dbc14ab3c1b1588e6de96dae414c8e37b8388766029631b28dd860688079b12d09cd27f2c5af11adf", "0xb57eced93eec3371c56679c259b34ac0992286be4f4ff9489d81cf9712403509932e47404ddd86f89d7c1c3b6391b28c", "0xa1c8b4e42ebcbd8927669a97f1b72e236fb19249325659e72be7ddaaa1d9e81ca2abb643295d41a8c04a2c01f9c0efd7", "0x877c33de20d4ed31674a671ba3e8f01a316581e32503136a70c9c15bf0b7cb7b1cba6cd4eb641fad165fb3c3c6c235fd", "0xa2a469d84ec478da40838f775d11ad38f6596eb41caa139cc190d6a10b5108c09febae34ffdafac92271d2e73c143693", "0x972f817caedb254055d52e963ed28c206848b6c4cfdb69dbc961c891f8458eaf582a6d4403ce1177d87bc2ea410ef60a", "0xaccbd739e138007422f28536381decc54bb6bd71d93edf3890e54f9ef339f83d2821697d1a4ac1f5a98175f9a9ecb9b5", "0x8940f8772e05389f823b62b3adc3ed541f91647f0318d7a0d3f293aeeb421013de0d0a3664ea53dd24e5fbe02d7efef6", "0x8ecce20f3ef6212edef07ec4d6183fda8e0e8cad2c6ccd0b325e75c425ee1faba00b5c26b4d95204238931598d78f49d", "0x97cc72c36335bd008afbed34a3b0c7225933faba87f7916d0a6d2161e6f82e0cdcda7959573a366f638ca75d30e9dab1", "0x9105f5de8699b5bdb6bd3bb6cc1992d1eac23929c29837985f83b22efdda92af64d9c574aa9640475087201bbbe5fd73", "0x8ffb33c4f6d05c413b9647eb6933526a350ed2e4278ca2ecc06b0e8026d8dbe829c476a40e45a6df63a633090a3f82ef", "0x8bfc6421fdc9c2d2aaa68d2a69b1a2728c25b84944cc3e6a57ff0c94bfd210d1cbf4ff3f06702d2a8257024d8be7de63", "0xa80e1dc1dddfb41a70220939b96dc6935e00b32fb8be5dff4eed1f1c650002ff95e4af481c43292e3827363b7ec4768a", "0x96f714ebd54617198bd636ba7f7a7f8995a61db20962f2165078d9ed8ee764d5946ef3cbdc7ebf8435bb8d5dd4c1deac", "0x8cdb0890e33144d66391d2ae73f5c71f5a861f72bc93bff6cc399fc25dd1f9e17d8772592b44593429718784802ac377", "0x8ccf9a7f80800ee770b92add734ed45a73ecc31e2af0e04364eefc6056a8223834c7c0dc9dfc52495bdec6e74ce69994", "0xaa0875f423bd68b5f10ba978ddb79d3b96ec093bfbac9ff366323193e339ed7c4578760fb60f60e93598bdf1e5cc4995", "0xa9214f523957b59c7a4cb61a40251ad72aba0b57573163b0dc0f33e41d2df483fb9a1b85a5e7c080e9376c866790f8cb", "0xb6224b605028c6673a536cc8ff9aeb94e7a22e686fda82cf16068d326469172f511219b68b2b3affb7933af0c1f80d07", "0xb6d58968d8a017c6a34e24c2c09852f736515a2c50f37232ac6b43a38f8faa7572cc31dade543b594b61b5761c4781d0", "0x8a97cefe5120020c38deeb861d394404e6c993c6cbd5989b6c9ebffe24f46ad11b4ba6348e2991cbf3949c28cfc3c99d", "0x95bf046f8c3a9c0ce2634be4de3713024daec3fc4083e808903b25ce3ac971145af90686b451efcc72f6b22df0216667", "0xa6a4e2f71b8fa28801f553231eff2794c0f10d12e7e414276995e21195abc9c2983a8997e41af41e78d19ff6fbb2680b", "0x8e5e62a7ca9c2f58ebaab63db2ff1fb1ff0877ae94b7f5e2897f273f684ae639dff44cc65718f78a9c894787602ab26a", "0x8542784383eec4f565fcb8b9fc2ad8d7a644267d8d7612a0f476fc8df3aff458897a38003d506d24142ad18f93554f2b", "0xb7db68ba4616ea072b37925ec4fb39096358c2832cc6d35169e032326b2d6614479f765ae98913c267105b84afcb9bf2", "0x8b31dbb9457d23d416c47542c786e07a489af35c4a87dadb8ee91bea5ac4a5315e65625d78dad2cf8f9561af31b45390", "0xa8545a1d91ac17257732033d89e6b7111db8242e9c6ebb0213a88906d5ef407a2c6fdb444e29504b06368b6efb4f4839", "0xb1bd85d29ebb28ccfb05779aad8674906b267c2bf8cdb1f9a0591dd621b53a4ee9f2942687ee3476740c0b4a7621a3ae", "0xa2b54534e152e46c50d91fff03ae9cd019ff7cd9f4168b2fe7ac08ef8c3bbc134cadd3f9d6bd33d20ae476c2a8596c8a", "0xb19b571ff4ae3e9f5d95acda133c455e72c9ea9973cae360732859836c0341c4c29ab039224dc5bc3deb824e031675d8", "0x940b5f80478648bac025a30f3efeb47023ce20ee98be833948a248bca6979f206bb28fc0f17b90acf3bb4abd3d14d731", "0x8f106b40588586ac11629b96d57808ad2808915d89539409c97414aded90b4ff23286a692608230a52bff696055ba5d6", "0xae6bda03aa10da3d2abbc66d764ca6c8d0993e7304a1bdd413eb9622f3ca1913baa6da1e9f4f9e6cf847f14f44d6924d", "0xa18e7796054a340ef826c4d6b5a117b80927afaf2ebd547794c400204ae2caf277692e2eabb55bc2f620763c9e9da66d", "0x8d2d25180dc2c65a4844d3e66819ccfcf48858f0cc89e1c77553b463ec0f7feb9a4002ce26bc618d1142549b9850f232", "0x863f413a394de42cc8166c1c75d513b91d545fff1de6b359037a742c70b008d34bf8e587afa2d62c844d0c6f0ea753e7", "0x83cd0cf62d63475e7fcad18a2e74108499cdbf28af2113cfe005e3b5887794422da450b1944d0a986eb7e1f4c3b18f25", "0xb4f8b350a6d88fea5ab2e44715a292efb12eb52df738c9b2393da3f1ddee68d0a75b476733ccf93642154bceb208f2b8", "0xb3f52aaa4cd4221cb9fc45936cc67fd3864bf6d26bf3dd86aa85aa55ecfc05f5e392ecce5e7cf9406b4b1c4fce0398c8", "0xb33137084422fb643123f40a6df2b498065e65230fc65dc31791c330e898c51c3a65ff738930f32c63d78f3c9315f85b", "0x91452bfa75019363976bb7337fe3a73f1c10f01637428c135536b0cdc7da5ce558dae3dfc792aa55022292600814a8ef", "0xad6ba94c787cd4361ca642c20793ea44f1f127d4de0bb4a77c7fbfebae0fcadbf28e2cb6f0c12c12a07324ec8c19761d", "0x890aa6248b17f1501b0f869c556be7bf2b1d31a176f9978bb97ab7a6bd4138eed32467951c5ef1871944b7f620542f43", "0x82111db2052194ee7dd22ff1eafffac0443cf969d3762cceae046c9a11561c0fdce9c0711f88ac01d1bed165f8a7cee3", "0xb1527b71df2b42b55832f72e772a466e0fa05743aacc7814f4414e4bcc8d42a4010c9e0fd940e6f254cafedff3cd6543", "0x922370fa49903679fc565f09c16a5917f8125e72acfeb060fcdbadbd1644eb9f4016229756019c93c6d609cda5d5d174", "0xaa4c7d98a96cab138d2a53d4aee8ebff6ef903e3b629a92519608d88b3bbd94de5522291a1097e6acf830270e64c8ee1", "0xb3dc21608a389a72d3a752883a382baaafc61ecc44083b832610a237f6a2363f24195acce529eb4aed4ef0e27a12b66e", "0x94619f5de05e07b32291e1d7ab1d8b7337a2235e49d4fb5f3055f090a65e932e829efa95db886b32b153bdd05a53ec8c", "0xade1e92722c2ffa85865d2426fb3d1654a16477d3abf580cfc45ea4b92d5668afc9d09275d3b79283e13e6b39e47424d", "0xb7201589de7bed094911dd62fcd25c459a8e327ac447b69f541cdba30233063e5ddffad0b67e9c3e34adcffedfd0e13d", "0x809d325310f862d6549e7cb40f7e5fc9b7544bd751dd28c4f363c724a0378c0e2adcb5e42ec8f912f5f49f18f3365c07", "0xa79c20aa533de7a5d671c99eb9eb454803ba54dd4f2efa3c8fec1a38f8308e9905c71e9282955225f686146388506ff6", "0xa85eeacb5e8fc9f3ed06a3fe2dc3108ab9f8c5877b148c73cf26e4e979bf5795edbe2e63a8d452565fd1176ed40402b2", "0x97ef55662f8a1ec0842b22ee21391227540adf7708f491436044f3a2eb18c471525e78e1e14fa292507c99d74d7437c6", "0x93110d64ed5886f3d16ce83b11425576a3a7a9bb831cd0de3f9a0b0f2270a730d68136b4ef7ff035ede004358f419b5c", "0xac9ed0a071517f0ae4f61ce95916a90ba9a77a3f84b0ec50ef7298acdcd44d1b94525d191c39d6bd1bb68f4471428760", "0x98abd6a02c7690f5a339adf292b8c9368dfc12e0f8069cf26a5e0ce54b4441638f5c66ea735142f3c28e00a0024267e6", "0xb51efb73ba6d44146f047d69b19c0722227a7748b0e8f644d0fc9551324cf034c041a2378c56ce8b58d06038fb8a78de", "0x8f115af274ef75c1662b588b0896b97d71f8d67986ae846792702c4742ab855952865ce236b27e2321967ce36ff93357", "0xb3c4548f14d58b3ab03c222da09e4381a0afe47a72d18d50a94e0008797f78e39e99990e5b4757be62310d400746e35a", "0xa9b1883bd5f31f909b8b1b6dcb48c1c60ed20aa7374b3ffa7f5b2ed036599b5bef33289d23c80a5e6420d191723b92f7", "0x85d38dffd99487ae5bb41ab4a44d80a46157bbbe8ef9497e68f061721f74e4da513ccc3422936b059575975f6787c936", "0xadf870fcb96e972c033ab7a35d28ae79ee795f82bc49c3bd69138f0e338103118d5529c53f2d72a9c0d947bf7d312af2", "0xab4c7a44e2d9446c6ff303eb49aef0e367a58b22cc3bb27b4e69b55d1d9ee639c9234148d2ee95f9ca8079b1457d5a75", "0xa386420b738aba2d7145eb4cba6d643d96bda3f2ca55bb11980b318d43b289d55a108f4bc23a9606fb0bccdeb3b3bb30", "0x847020e0a440d9c4109773ecca5d8268b44d523389993b1f5e60e541187f7c597d79ebd6e318871815e26c96b4a4dbb1", "0xa530aa7e5ca86fcd1bec4b072b55cc793781f38a666c2033b510a69e110eeabb54c7d8cbcb9c61fee531a6f635ffa972", "0x87364a5ea1d270632a44269d686b2402da737948dac27f51b7a97af80b66728b0256547a5103d2227005541ca4b7ed04", "0x8816fc6e16ea277de93a6d793d0eb5c15e9e93eb958c5ef30adaf8241805adeb4da8ce19c3c2167f971f61e0b361077d", "0x8836a72d301c42510367181bb091e4be377777aed57b73c29ef2ce1d475feedd7e0f31676284d9a94f6db01cc4de81a2", "0xb0d9d8b7116156d9dde138d28aa05a33e61f8a85839c1e9071ccd517b46a5b4b53acb32c2edd7150c15bc1b4bd8db9e3", "0xae931b6eaeda790ba7f1cd674e53dc87f6306ff44951fa0df88d506316a5da240df9794ccbd7215a6470e6b31c5ea193", "0x8c6d5bdf87bd7f645419d7c6444e244fe054d437ed1ba0c122fde7800603a5fadc061e5b836cb22a6cfb2b466f20f013", "0x90d530c6d0cb654999fa771b8d11d723f54b8a8233d1052dc1e839ea6e314fbed3697084601f3e9bbb71d2b4eaa596df", "0xb0d341a1422588c983f767b1ed36c18b141774f67ef6a43cff8e18b73a009da10fc12120938b8bba27f225bdfd3138f9", "0xa131b56f9537f460d304e9a1dd75702ace8abd68cb45419695cb8dee76998139058336c87b7afd6239dc20d7f8f940cc", "0xaa6c51fa28975f709329adee1bbd35d49c6b878041841a94465e8218338e4371f5cb6c17f44a63ac93644bf28f15d20f", "0x88440fb584a99ebd7f9ea04aaf622f6e44e2b43bbb49fb5de548d24a238dc8f26c8da2ccf03dd43102bda9f16623f609", "0x9777b8695b790e702159a4a750d5e7ff865425b95fa0a3c15495af385b91c90c00a6bd01d1b77bffe8c47d01baae846f", "0x8b9d764ece7799079e63c7f01690c8eff00896a26a0d095773dea7a35967a8c40db7a6a74692f0118bf0460c26739af4", "0x85808c65c485520609c9e61fa1bb67b28f4611d3608a9f7a5030ee61c3aa3c7e7dc17fff48af76b4aecee2cb0dbd22ac", "0xad2783a76f5b3db008ef5f7e67391fda4e7e36abde6b3b089fc4835b5c339370287935af6bd53998bed4e399eda1136d", "0x96f18ec03ae47c205cc4242ca58e2eff185c9dca86d5158817e2e5dc2207ab84aadda78725f8dc080a231efdc093b940", "0x97de1ab6c6cc646ae60cf7b86df73b9cf56cc0cd1f31b966951ebf79fc153531af55ca643b20b773daa7cab784b832f7", "0x870ba266a9bfa86ef644b1ef025a0f1b7609a60de170fe9508de8fd53170c0b48adb37f19397ee8019b041ce29a16576", "0xad990e888d279ac4e8db90619d663d5ae027f994a3992c2fbc7d262b5990ae8a243e19157f3565671d1cb0de17fe6e55", "0x8d9d5adcdd94c5ba3be4d9a7428133b42e485f040a28d16ee2384758e87d35528f7f9868de9bd23d1a42a594ce50a567", "0x85a33ed75d514ece6ad78440e42f7fcdb59b6f4cff821188236d20edae9050b3a042ce9bc7d2054296e133d033e45022", "0x92afd2f49a124aaba90de59be85ff269457f982b54c91b06650c1b8055f9b4b0640fd378df02a00e4fc91f7d226ab980", "0x8c0ee09ec64bd831e544785e3d65418fe83ed9c920d9bb4d0bf6dd162c1264eb9d6652d2def0722e223915615931581c", "0x8369bedfa17b24e9ad48ebd9c5afea4b66b3296d5770e09b00446c5b0a8a373d39d300780c01dcc1c6752792bccf5fd0", "0x8b9e960782576a59b2eb2250d346030daa50bbbec114e95cdb9e4b1ba18c3d34525ae388f859708131984976ca439d94", "0xb682bface862008fea2b5a07812ca6a28a58fd151a1d54c708fc2f8572916e0d678a9cb8dc1c10c0470025c8a605249e", "0xa38d5e189bea540a824b36815fc41e3750760a52be0862c4cac68214febdc1a754fb194a7415a8fb7f96f6836196d82a", "0xb9e7fbda650f18c7eb8b40e42cc42273a7298e65e8be524292369581861075c55299ce69309710e5b843cb884de171bd", "0xb6657e5e31b3193874a1bace08f42faccbd3c502fb73ad87d15d18a1b6c2a146f1baa929e6f517db390a5a47b66c0acf", "0xae15487312f84ed6265e4c28327d24a8a0f4d2d17d4a5b7c29b974139cf93223435aaebe3af918f5b4bb20911799715f", "0x8bb4608beb06bc394e1a70739b872ce5a2a3ffc98c7547bf2698c893ca399d6c13686f6663f483894bccaabc3b9c56ad", "0xb58ac36bc6847077584308d952c5f3663e3001af5ecf2e19cb162e1c58bd6c49510205d453cffc876ca1dc6b8e04a578", "0x924f65ced61266a79a671ffb49b300f0ea44c50a0b4e3b02064faa99fcc3e4f6061ea8f38168ab118c5d47bd7804590e", "0x8d67d43b8a06b0ff4fafd7f0483fa9ed1a9e3e658a03fb49d9d9b74e2e24858dc1bed065c12392037b467f255d4e5643", "0xb4d4f87813125a6b355e4519a81657fa97c43a6115817b819a6caf4823f1d6a1169683fd68f8d025cdfa40ebf3069acb", "0xa7fd4d2c8e7b59b8eed3d4332ae94b77a89a2616347402f880bc81bde072220131e6dbec8a605be3a1c760b775375879", "0x8d4a7d8fa6f55a30df37bcf74952e2fa4fd6676a2e4606185cf154bdd84643fd01619f8fb8813a564f72e3f574f8ce30", "0x8086fb88e6260e9a9c42e9560fde76315ff5e5680ec7140f2a18438f15bc2cc7d7d43bfb5880b180b738c20a834e6134", "0x916c4c54721de03934fee6f43de50bb04c81f6f8dd4f6781e159e71c40c60408aa54251d457369d133d4ba3ed7c12cb4", "0x902e5bf468f11ed9954e2a4a595c27e34abe512f1d6dc08bbca1c2441063f9af3dc5a8075ab910a10ff6c05c1c644a35", "0xa1302953015e164bf4c15f7d4d35e3633425a78294406b861675667eec77765ff88472306531e5d3a4ec0a2ff0dd6a9e", "0x87874461df3c9aa6c0fa91325576c0590f367075f2f0ecfeb34afe162c04c14f8ce9d608c37ac1adc8b9985bc036e366", "0x84b50a8a61d3cc609bfb0417348133e698fe09a6d37357ce3358de189efcf35773d78c57635c2d26c3542b13cc371752", "0xacaed2cff8633d12c1d12bb7270c54d65b0b0733ab084fd47f81d0a6e1e9b6f300e615e79538239e6160c566d8bb8d29", "0x889e6a0e136372ca4bac90d1ab220d4e1cad425a710e8cdd48b400b73bb8137291ceb36a39440fa84305783b1d42c72f", "0x90952e5becec45b2b73719c228429a2c364991cf1d5a9d6845ae5b38018c2626f4308daa322cab1c72e0f6c621bb2b35", "0x8f5a97a801b6e9dcd66ccb80d337562c96f7914e7169e8ff0fda71534054c64bf2a9493bb830623d612cfe998789be65", "0x84f3df8b9847dcf1d63ca470dc623154898f83c25a6983e9b78c6d2d90a97bf5e622445be835f32c1e55e6a0a562ea78", "0x91d12095cd7a88e7f57f254f02fdb1a1ab18984871dead2f107404bcf8069fe68258c4e6f6ebd2477bddf738135400bb", "0xb771a28bc04baef68604d4723791d3712f82b5e4fe316d7adc2fc01b935d8e644c06d59b83bcb542afc40ebafbee0683", "0x872f6341476e387604a7e93ae6d6117e72d164e38ebc2b825bc6df4fcce815004d7516423c190c1575946b5de438c08d", "0x90d6b4aa7d40a020cdcd04e8b016d041795961a8e532a0e1f4041252131089114a251791bf57794cadb7d636342f5d1c", "0x899023ba6096a181448d927fed7a0fe858be4eac4082a42e30b3050ee065278d72fa9b9d5ce3bc1372d4cbd30a2f2976", "0xa28f176571e1a9124f95973f414d5bdbf5794d41c3839d8b917100902ac4e2171eb940431236cec93928a60a77ede793", "0x838dbe5bcd29c4e465d02350270fa0036cd46f8730b13d91e77afb7f5ed16525d0021d3b2ae173a76c378516a903e0cb", "0x8e105d012dd3f5d20f0f1c4a7e7f09f0fdd74ce554c3032e48da8cce0a77260d7d47a454851387770f5c256fa29bcb88", "0x8f4df0f9feeb7a487e1d138d13ea961459a6402fd8f8cabb226a92249a0d04ded5971f3242b9f90d08da5ff66da28af6", "0xad1cfda4f2122a20935aa32fb17c536a3653a18617a65c6836700b5537122af5a8206befe9eaea781c1244c43778e7f1", "0x832c6f01d6571964ea383292efc8c8fa11e61c0634a25fa180737cc7ab57bc77f25e614aac9a2a03d98f27b3c1c29de2", "0x903f89cc13ec6685ac7728521898781fecb300e9094ef913d530bf875c18bcc3ceed7ed51e7b482d45619ab4b025c2e9", "0xa03c474bb915aad94f171e8d96f46abb2a19c9470601f4c915512ec8b9e743c3938450a2a5b077b4618b9df8809e1dc1", "0x83536c8456f306045a5f38ae4be2e350878fa7e164ea408d467f8c3bc4c2ee396bd5868008c089183868e4dfad7aa50b", "0x88f26b4ea1b236cb326cd7ad7e2517ec8c4919598691474fe15d09cabcfc37a8d8b1b818f4d112432ee3a716b0f37871", "0xa44324e3fe96e9c12b40ded4f0f3397c8c7ee8ff5e96441118d8a6bfad712d3ac990b2a6a23231a8f691491ac1fd480f", "0xb0de4693b4b9f932191a21ee88629964878680152a82996c0019ffc39f8d9369bbe2fe5844b68d6d9589ace54af947e4", "0x8e5d8ba948aea5fd26035351a960e87f0d23efddd8e13236cc8e4545a3dda2e9a85e6521efb8577e03772d3637d213d9", "0x93efc82d2017e9c57834a1246463e64774e56183bb247c8fc9dd98c56817e878d97b05f5c8d900acf1fbbbca6f146556", "0x8731176363ad7658a2862426ee47a5dce9434216cef60e6045fa57c40bb3ce1e78dac4510ae40f1f31db5967022ced32", "0xb10c9a96745722c85bdb1a693100104d560433d45b9ac4add54c7646a7310d8e9b3ca9abd1039d473ae768a18e489845", "0xa2ac374dfbb464bf850b4a2caf15b112634a6428e8395f9c9243baefd2452b4b4c61b0cb2836d8eae2d57d4900bf407e", "0xb69fe3ded0c4f5d44a09a0e0f398221b6d1bf5dbb8bc4e338b93c64f1a3cac1e4b5f73c2b8117158030ec03787f4b452", "0x8852cdbaf7d0447a8c6f211b4830711b3b5c105c0f316e3a6a18dcfbb9be08bd6f4e5c8ae0c3692da08a2dfa532f9d5c", "0x93bbf6d7432a7d98ade3f94b57bf9f4da9bc221a180a370b113066dd42601bb9e09edd79e2e6e04e00423399339eebda", "0xa80941c391f1eeafc1451c59e4775d6a383946ff22997aeaadf806542ba451d3b0f0c6864eeba954174a296efe2c1550", "0xa045fe2bb011c2a2f71a0181a8f457a3078470fb74c628eab8b59aef69ffd0d649723bf74d6885af3f028bc5a104fb39", "0xb9d8c35911009c4c8cad64692139bf3fc16b78f5a19980790cb6a7aea650a25df4231a4437ae0c351676a7e42c16134f", "0x94c79501ded0cfcbab99e1841abe4a00a0252b3870e20774c3da16c982d74c501916ec28304e71194845be6e3113c7ab", "0x900a66418b082a24c6348d8644ddb1817df5b25cb33044a519ef47cc8e1f7f1e38d2465b7b96d32ed472d2d17f8414c6", "0xb26f45d393b8b2fcb29bdbb16323dc7f4b81c09618519ab3a39f8ee5bd148d0d9f3c0b5dfab55b5ce14a1cb9206d777b", "0xaa1a87735fc493a80a96a9a57ca40a6d9c32702bfcaa9869ce1a116ae65d69cefe2f3e79a12454b4590353e96f8912b4", "0xa922b188d3d0b69b4e4ea2a2aa076566962844637da12c0832105d7b31dea4a309eee15d12b7a336be3ea36fcbd3e3b7", "0x8f3841fcf4105131d8c4d9885e6e11a46c448226401cf99356c291fadb864da9fa9d30f3a73c327f23f9fd99a11d633e", "0x9791d1183fae270e226379af6c497e7da803ea854bb20afa74b253239b744c15f670ee808f708ede873e78d79a626c9a", "0xa4cad52e3369491ada61bf28ada9e85de4516d21c882e5f1cd845bea9c06e0b2887b0c5527fcff6fc28acd3c04f0a796", "0xb9ac86a900899603452bd11a7892a9bfed8054970bfcbeaa8c9d1930db891169e38d6977f5258c25734f96c8462eee3b", "0xa3a154c28e5580656a859f4efc2f5ebfa7eaa84ca40e3f134fa7865e8581586db74992dbfa4036aa252fba103773ddde", "0x95cc2a0c1885a029e094f5d737e3ecf4d26b99036453a8773c77e360101f9f98676ee246f6f732a377a996702d55691f", "0x842651bbe99720438d8d4b0218feb60481280c05beb17750e9ca0d8c0599a60f873b7fbdcc7d8835ba9a6d57b16eec03", "0x81ee54699da98f5620307893dcea8f64670609fa20e5622265d66283adeac122d458b3308c5898e6c57c298db2c8b24f", "0xb97868b0b2bc98032d68352a535a1b341b9ff3c7af4e3a7f3ebc82d3419daa1b5859d6aedc39994939623c7cd878bd9b", "0xb60325cd5d36461d07ef253d826f37f9ee6474a760f2fff80f9873d01fd2b57711543cdc8d7afa1c350aa753c2e33dea", "0x8c205326c11d25a46717b780c639d89714c7736c974ae71287e3f4b02e6605ac2d9b4928967b1684f12be040b7bf2dd3", "0x95a392d82db51e26ade6c2ccd3396d7e40aff68fa570b5951466580d6e56dda51775dce5cf3a74a7f28c3cb2eb551c4d", "0x8f2cc8071eb56dffb70bda6dd433b556221dc8bba21c53353c865f00e7d4d86c9e39f119ea9a8a12ef583e9a55d9a6b6", "0x9449a71af9672aaf8856896d7e3d788b22991a7103f75b08c0abbcc2bfe60fda4ed8ce502cea4511ff0ea52a93e81222", "0x857090ab9fdb7d59632d068f3cc8cf27e61f0d8322d30e6b38e780a1f05227199b4cd746aac1311c36c659ef20931f28", "0x98a891f4973e7d9aaf9ac70854608d4f7493dffc7e0987d7be9dd6029f6ea5636d24ef3a83205615ca1ff403750058e1", "0xa486e1365bbc278dd66a2a25d258dc82f46b911103cb16aab3945b9c95ae87b386313a12b566df5b22322ede0afe25ad", "0xa9a1eb399ed95d396dccd8d1ac718043446f8b979ec62bdce51c617c97a312f01376ab7fb87d27034e5f5570797b3c33", "0xb7abc3858d7a74bb446218d2f5a037e0fae11871ed9caf44b29b69c500c1fa1dcfad64c9cdccc9d80d5e584f06213deb", "0x8cfb09fe2e202faa4cebad932b1d35f5ca204e1c2a0c740a57812ac9a6792130d1312aabd9e9d4c58ca168bfebd4c177", "0xa90a305c2cd0f184787c6be596fa67f436afd1f9b93f30e875f817ac2aae8bdd2e6e656f6be809467e6b3ad84adb86b1", "0x80a9ef993c2b009ae172cc8f7ec036f5734cf4f4dfa06a7db4d54725e7fbfae5e3bc6f22687bdbb6961939d6f0c87537", "0x848ade1901931e72b955d7db1893f07003e1708ff5d93174bac5930b9a732640f0578839203e9b77eb27965c700032d3", "0x93fdf4697609c5ae9c33b9ca2f5f1af44abeb2b98dc4fdf732cf7388de086f410730dc384d9b7a7f447bb009653c8381", "0x89ce3fb805aea618b5715c0d22a9f46da696b6fa86794f56fdf1d44155a33d42daf1920bcbe36cbacf3cf4c92df9cbc7", "0x829ce2c342cf82aa469c65f724f308f7a750bd1494adc264609cd790c8718b8b25b5cab5858cf4ee2f8f651d569eea67", "0xaf2f0cee7bf413204be8b9df59b9e4991bc9009e0d6dbe6815181df0ec2ca93ab8f4f3135b1c14d8f53d74bff0bd6f27", "0xb87998cecf7b88cde93d1779f10a521edd5574a2fbd240102978639ec57433ba08cdb53849038a329cebbe74657268d2", "0xa64542a1261a6ed3d720c2c3a802303aad8c4c110c95d0f12e05c1065e66f42da494792b6bfc5b9272363f3b1d457f58", "0x86a6fd042e4f282fadf07a4bfee03fc96a3aea49f7a00f52bf249a20f1ec892326855410e61f37fbb27d9305eb2fc713", "0x967ea5bc403b6db269682f7fd0df90659350d7e1aa66bc4fab4c9dfcd75ed0bba4b52f1cebc5f34dc8ba810793727629", "0xa52990f9f3b8616ce3cdc2c74cd195029e6a969753dcf2d1630438700e7d6ebde36538532b3525ac516f5f2ce9dd27a3", "0xa64f7ff870bab4a8bf0d4ef6f5c744e9bf1021ed08b4c80903c7ad318e80ba1817c3180cc45cb5a1cae1170f0241655f", "0xb00f706fa4de1f663f021e8ad3d155e84ce6084a409374b6e6cd0f924a0a0b51bebaaaf1d228c77233a73b0a5a0df0e9", "0x8b882cc3bff3e42babdb96df95fb780faded84887a0a9bab896bef371cdcf169d909f5658649e93006aa3c6e1146d62e", "0x9332663ef1d1dcf805c3d0e4ce7a07d9863fb1731172e766b3cde030bf81682cc011e26b773fb9c68e0477b4ae2cfb79", "0xa8aa8151348dbd4ef40aaeb699b71b4c4bfd3218560c120d85036d14f678f6736f0ec68e80ce1459d3d35feccc575164", "0xa16cd8b729768f51881c213434aa28301fa78fcb554ddd5f9012ee1e4eae7b5cb3dd88d269d53146dea92d10790faf0b", "0x86844f0ef9d37142faf3b1e196e44fbe280a3ba4189aa05c356778cb9e3b388a2bff95eed305ada8769935c9974e4c57", "0xae2eec6b328fccf3b47bcdac32901ac2744a51beb410b04c81dea34dee4912b619466a4f5e2780d87ecefaebbe77b46d", "0x915df4c38d301c8a4eb2dc5b1ba0ffaad67cbb177e0a80095614e9c711f4ef24a4cef133f9d982a63d2a943ba6c8669d", "0xae6a2a4dedfc2d1811711a8946991fede972fdf2a389b282471280737536ffc0ac3a6d885b1f8bda0366eb0b229b9979", "0xa9b628c63d08b8aba6b1317f6e91c34b2382a6c85376e8ef2410a463c6796740ae936fc4e9e0737cb9455d1daa287bd8", "0x848e30bf7edf2546670b390d5cf9ab71f98fcb6add3c0b582cb34996c26a446dee5d1bde4fdcde4fc80c10936e117b29", "0x907d6096c7c8c087d1808dd995d5d2b9169b3768c3f433475b50c2e2bd4b082f4d543afd8b0b0ddffa9c66222a72d51d", "0xa59970a2493b07339124d763ac9d793c60a03354539ecbcf6035bc43d1ea6e35718202ae6d7060b7d388f483d971573c", "0xb9cfef2af9681b2318f119d8611ff6d9485a68d8044581b1959ab1840cbca576dbb53eec17863d2149966e9feb21122f", "0xad47271806161f61d3afa45cdfe2babceef5e90031a21779f83dc8562e6076680525b4970b2f11fe9b2b23c382768323", "0x8e425a99b71677b04fe044625d338811fbb8ee32368a424f6ab2381c52e86ee7a6cecedf777dc97181519d41c351bc22", "0x86b55b54d7adefc12954a9252ee23ae83efe8b5b4b9a7dc307904413e5d69868c7087a818b2833f9b004213d629be8ad", "0xa14fda6b93923dd11e564ae4457a66f397741527166e0b16a8eb91c6701c244fd1c4b63f9dd3515193ec88fa6c266b35", "0xa9b17c36ae6cd85a0ed7f6cabc5b47dc8f80ced605db327c47826476dc1fb8f8669aa7a7dc679fbd4ee3d8e8b4bd6a6f", "0x82a0829469c1458d959c821148f15dacae9ea94bf56c59a6ab2d4dd8b3d16d73e313b5a3912a6c1f131d73a8f06730c4", "0xb22d56d549a53eaef549595924bdb621ff807aa4513feedf3fdcbf7ba8b6b9cfa4481c2f67fc642db397a6b794a8b63a", "0x974c59c24392e2cb9294006cbe3c52163e255f3bd0c2b457bdc68a6338e6d5b6f87f716854492f8d880a6b896ccf757c", "0xb70d247ba7cad97c50b57f526c2ba915786e926a94e8f8c3eebc2e1be6f4255411b9670e382060049c8f4184302c40b2", "0xad80201fe75ef21c3ddbd98cf23591e0d7a3ba1036dfe77785c32f44755a212c31f0ceb0a0b6f5ee9b6dc81f358d30c3", "0x8c656e841f9bb90b9a42d425251f3fdbc022a604d75f5845f479ed4be23e02aaf9e6e56cde351dd7449c50574818a199", "0x8b88dd3fa209d3063b7c5b058f7249ee9900fbc2287d16da61a0704a0a1d71e45d9c96e1cda7fdf9654534ec44558b22", "0x961da00cc8750bd84d253c08f011970ae1b1158ad6778e8ed943d547bceaf52d6d5a212a7de3bf2706688c4389b827d2", "0xa5dd379922549a956033e3d51a986a4b1508e575042b8eaa1df007aa77cf0b8c2ab23212f9c075702788fa9c53696133", "0xac8fcfde3a349d1e93fc8cf450814e842005c545c4844c0401bc80e6b96cdb77f29285a14455e167c191d4f312e866cd", "0xac63d79c799783a8466617030c59dd5a8f92ee6c5204676fd8d881ce5f7f8663bdbeb0379e480ea9b6340ab0dc88e574", "0x805874fde19ce359041ae2bd52a39e2841acabfd31f965792f2737d7137f36d4e4722ede8340d8c95afa6af278af8acb", "0x8d2f323a228aa8ba7b7dc1399138f9e6b41df1a16a7069003ab8104b8b68506a45141bc5fe66acf430e23e13a545190b", "0xa1610c721a2d9af882bb6b39bea97cff1527a3aea041d25934de080214ae77c959e79957164440686d15ab301e897d4d", "0xaba16d29a47fc36f12b654fde513896723e2c700c4190f11b26aa4011da57737ad717daa02794aa3246e4ae5f0b0cc3a", "0xa406db2f15fdd135f346cc4846623c47edd195e80ba8c7cb447332095314d565e4040694ca924696bb5ee7f8996ea0ba", "0x8b30e2cd9b47d75ba57b83630e40f832249af6c058d4f490416562af451993eec46f3e1f90bc4d389e4c06abd1b32a46", "0xaacf9eb7036e248e209adbfc3dd7ce386569ea9b312caa4b240726549db3c68c4f1c8cbf8ed5ea9ea60c7e57c9df3b8e", "0xb20fcac63bf6f5ee638a42d7f89be847f348c085ddcbec3fa318f4323592d136c230495f188ef2022aa355cc2b0da6f9", "0x811eff750456a79ec1b1249d76d7c1547065b839d8d4aaad860f6d4528eb5b669473dcceeeea676cddbc3980b68461b7", "0xb52d14ae33f4ab422f953392ae76a19c618cc31afc96290bd3fe2fb44c954b5c92c4789f3f16e8793f2c0c1691ade444", "0xa7826dafeeba0db5b66c4dfcf2b17fd7b40507a5a53ac2e42942633a2cb30b95ba1739a6e9f3b7a0e0f1ec729bf274e2", "0x8acfd83ddf7c60dd7c8b20c706a3b972c65d336b8f9b3d907bdd8926ced271430479448100050b1ef17578a49c8fa616", "0xaf0c69f65184bb06868029ad46f8465d75c36814c621ac20a5c0b06a900d59305584f5a6709683d9c0e4b6cd08d650a6", "0xb6cc8588191e00680ee6c3339bd0f0a17ad8fd7f4be57d5d7075bede0ea593a19e67f3d7c1a20114894ee5bfcab71063", "0xa82fd4f58635129dbb6cc3eb9391cf2d28400018b105fc41500fbbd12bd890b918f97d3d359c29dd3b4c4e34391dfab0", "0x92fc544ed65b4a3625cf03c41ddff7c039bc22d22c0d59dcc00efd5438401f2606adb125a1d5de294cca216ec8ac35a3", "0x906f67e4a32582b71f15940523c0c7ce370336935e2646bdaea16a06995256d25e99df57297e39d6c39535e180456407", "0x97510337ea5bbd5977287339197db55c60533b2ec35c94d0a460a416ae9f60e85cee39be82abeeacd5813cf54df05862", "0x87e6894643815c0ea48cb96c607266c5ee4f1f82ba5fe352fb77f9b6ed14bfc2b8e09e80a99ac9047dfcf62b2ae26795", "0xb6fd55dd156622ad7d5d51b7dde75e47bd052d4e542dd6449e72411f68275775c846dde301e84613312be8c7bce58b07", "0xb98461ac71f554b2f03a94e429b255af89eec917e208a8e60edf5fc43b65f1d17a20de3f31d2ce9f0cb573c25f2f4d98", "0x96f0dea40ca61cefbee41c4e1fe9a7d81fbe1f49bb153d083ab70f5d0488a1f717fd28cedcf6aa18d07cce2c62801898", "0x8d7c3ab310184f7dc34b6ce4684e4d29a31e77b09940448ea4daac730b7eb308063125d4dd229046cf11bfd521b771e0", "0x96f0564898fe96687918bbf0a6adead99cf72e3a35ea3347e124af9d006221f8e82e5a9d2fe80094d5e8d48e610f415e", "0xad50fcb92c2675a398cf07d4c40a579e44bf8d35f27cc330b57e54d5ea59f7d898af0f75dccfe3726e5471133d70f92b", "0x828beed62020361689ae7481dd8f116902b522fb0c6c122678e7f949fdef70ead011e0e6bffd25678e388744e17cdb69", "0x8349decac1ca16599eee2efc95bcaabf67631107da1d34a2f917884bd70dfec9b4b08ab7bc4379d6c73b19c0b6e54fb8", "0xb2a6a2e50230c05613ace9e58bb2e98d94127f196f02d9dddc53c43fc68c184549ca12d713cb1b025d8260a41e947155", "0x94ff52181aadae832aed52fc3b7794536e2a31a21fc8be3ea312ca5c695750d37f08002f286b33f4023dba1e3253ecfa", "0xa21d56153c7e5972ee9a319501be4faff199fdf09bb821ea9ce64aa815289676c00f105e6f00311b3a5b627091b0d0fc", "0xa27a60d219f1f0c971db73a7f563b371b5c9fc3ed1f72883b2eac8a0df6698400c9954f4ca17d7e94e44bd4f95532afb", "0xa2fc56fae99b1f18ba5e4fe838402164ce82f8a7f3193d0bbd360c2bac07c46f9330c4c7681ffb47074c6f81ee6e7ac6", "0xb748e530cd3afb96d879b83e89c9f1a444f54e55372ab1dcd46a0872f95ce8f49cf2363fc61be82259e04f555937ed16", "0x8bf8993e81080c7cbba1e14a798504af1e4950b2f186ab3335b771d6acaee4ffe92131ae9c53d74379d957cb6344d9cd", "0x96774d0ef730d22d7ab6d9fb7f90b9ead44285219d076584a901960542756700a2a1603cdf72be4708b267200f6c36a9", "0xb47703c2ab17be1e823cc7bf3460db1d6760c0e33862c90ca058845b2ff234b0f9834ddba2efb2ee1770eb261e7d8ffd", "0x84319e67c37a9581f8b09b5e4d4ae88d0a7fb4cbb6908971ab5be28070c3830f040b1de83ee663c573e0f2f6198640e4", "0x96811875fa83133e0b3c0e0290f9e0e28bca6178b77fdf5350eb19344d453dbd0d71e55a0ef749025a5a2ca0ad251e81", "0x81a423423e9438343879f2bfd7ee9f1c74ebebe7ce3cfffc8a11da6f040cc4145c3b527bd3cf63f9137e714dbcb474ef", "0xb8c3535701ddbeec2db08e17a4fa99ba6752d32ece5331a0b8743676f421fcb14798afc7c783815484f14693d2f70db8", "0x81aee980c876949bf40782835eec8817d535f6f3f7e00bf402ddd61101fdcd60173961ae90a1cf7c5d060339a18c959d", "0x87e67b928d97b62c49dac321ce6cb680233f3a394d4c9a899ac2e8db8ccd8e00418e66cdfd68691aa3cb8559723b580c", "0x8eac204208d99a2b738648df96353bbb1b1065e33ee4f6bba174b540bbbd37d205855e1f1e69a6b7ff043ca377651126", "0x848e6e7a54ad64d18009300b93ea6f459ce855971dddb419b101f5ac4c159215626fadc20cc3b9ab1701d8f6dfaddd8b", "0x88aa123d9e0cf309d46dddb6acf634b1ade3b090a2826d6e5e78669fa1220d6df9a6697d7778cd9b627db17eea846126", "0x9200c2a629b9144d88a61151b661b6c4256cc5dadfd1e59a8ce17a013c2d8f7e754aabe61663c3b30f1bc47784c1f8cf", "0xb6e1a2827c3bdda91715b0e1b1f10dd363cef337e7c80cac1f34165fc0dea7c8b69747e310563db5818390146ce3e231", "0x92c333e694f89f0d306d54105b2a5dcc912dbe7654d9e733edab12e8537350815be472b063e56cfde5286df8922fdecb", "0xa6fac04b6d86091158ebb286586ccfec2a95c9786e14d91a9c743f5f05546073e5e3cc717635a0c602cad8334e922346", "0xa581b4af77feebc1fb897d49b5b507c6ad513d8f09b273328efbb24ef0d91eb740d01b4d398f2738125dacfe550330cd", "0x81c4860cccf76a34f8a2bc3f464b7bfd3e909e975cce0d28979f457738a56e60a4af8e68a3992cf273b5946e8d7f76e2", "0x8d1eaa09a3180d8af1cbaee673db5223363cc7229a69565f592fa38ba0f9d582cedf91e15dabd06ebbf2862fc0feba54", "0x9832f49b0147f4552402e54593cfa51f99540bffada12759b71fcb86734be8e500eea2d8b3d036710bdf04c901432de9", "0x8bdb0e8ec93b11e5718e8c13cb4f5de545d24829fd76161216340108098dfe5148ed25e3b57a89a516f09fa79043734d", "0xab96f06c4b9b0b2c0571740b24fca758e6976315053a7ecb20119150a9fa416db2d3a2e0f8168b390bb063f0c1caf785", "0xab777f5c52acd62ecf4d1f168b9cc8e1a9b45d4ec6a8ff52c583e867c2239aba98d7d3af977289b367edce03d9c2dfb1", "0xa09d3ce5e748da84802436951acc3d3ea5d8ec1d6933505ed724d6b4b0d69973ab0930daec9c6606960f6e541e4a3ce2", "0x8ef94f7be4d85d5ad3d779a5cf4d7b2fc3e65c52fb8e1c3c112509a4af77a0b5be994f251e5e40fabeeb1f7d5615c22b", "0xa7406a5bf5708d9e10922d3c5c45c03ef891b8d0d74ec9f28328a72be4cdc05b4f2703fa99366426659dfca25d007535", "0xb7f52709669bf92a2e070bfe740f422f0b7127392c5589c7f0af71bb5a8428697c762d3c0d74532899da24ea7d8695c2", "0xb9dfb0c8df84104dbf9239ccefa4672ef95ddabb8801b74997935d1b81a78a6a5669a3c553767ec19a1281f6e570f4ff", "0xae4d5c872156061ce9195ac640190d8d71dd406055ee43ffa6f9893eb24b870075b74c94d65bc1d5a07a6573282b5520", "0xafe6bd3eb72266d333f1807164900dcfa02a7eb5b1744bb3c86b34b3ee91e3f05e38fa52a50dc64eeb4bdb1dd62874b8", "0x948043cf1bc2ef3c01105f6a78dc06487f57548a3e6ef30e6ebc51c94b71e4bf3ff6d0058c72b6f3ecc37efd7c7fa8c0", "0xa22fd17c2f7ffe552bb0f23fa135584e8d2d8d75e3f742d94d04aded2a79e22a00dfe7acbb57d44e1cdb962fb22ae170", "0x8cd0f4e9e4fb4a37c02c1bde0f69359c43ab012eb662d346487be0c3758293f1ca560122b059b091fddce626383c3a8f", "0x90499e45f5b9c81426f3d735a52a564cafbed72711d9279fdd88de8038e953bc48c57b58cba85c3b2e4ce56f1ddb0e11", "0x8c30e4c034c02958384564cac4f85022ef36ab5697a3d2feaf6bf105049675bbf23d01b4b6814711d3d9271abff04cac", "0x81f7999e7eeea30f3e1075e6780bbf054f2fb6f27628a2afa4d41872a385b4216dd5f549da7ce6cf39049b2251f27fb7", "0xb36a7191f82fc39c283ffe53fc1f5a9a00b4c64eee7792a8443475da9a4d226cf257f226ea9d66e329af15d8f04984ec", "0xaad4da528fdbb4db504f3041c747455baff5fcd459a2efd78f15bdf3aea0bdb808343e49df88fe7a7c8620009b7964a3", "0x99ebd8c6dd5dd299517fb6381cfc2a7f443e6e04a351440260dd7c2aee3f1d8ef06eb6c18820b394366ecdfd2a3ce264", "0x8873725b81871db72e4ec3643084b1cdce3cbf80b40b834b092767728605825c19b6847ad3dcf328438607e8f88b4410", "0xb008ee2f895daa6abd35bd39b6f7901ae4611a11a3271194e19da1cdcc7f1e1ea008fe5c5440e50d2c273784541ad9c5", "0x9036feafb4218d1f576ef89d0e99124e45dacaa6d816988e34d80f454d10e96809791d5b78f7fd65f569e90d4d7238c5", "0x92073c1d11b168e4fa50988b0288638b4868e48bbc668c5a6dddf5499875d53be23a285acb5e4bad60114f6cf6c556e9", "0x88c87dfcb8ba6cbfe7e1be081ccfadbd589301db2cb7c99f9ee5d7db90aa297ed1538d5a867678a763f2deede5fd219a", "0xb42a562805c661a50f5dea63108002c0f27c0da113da6a9864c9feb5552225417c0356c4209e8e012d9bcc9d182c7611", "0x8e6317d00a504e3b79cd47feb4c60f9df186467fe9ca0f35b55c0364db30528f5ff071109dabb2fc80bb9cd4949f0c24", "0xb7b1ea6a88694f8d2f539e52a47466695e39e43a5eb9c6f23bca15305fe52939d8755cc3ac9d6725e60f82f994a3772f", "0xa3cd55161befe795af93a38d33290fb642b8d80da8b786c6e6fb02d393ea308fbe87f486994039cbd7c7b390414594b6", "0xb416d2d45b44ead3b1424e92c73c2cf510801897b05d1724ff31cbd741920cd858282fb5d6040fe1f0aa97a65bc49424", "0x950ee01291754feace97c2e933e4681e7ddfbc4fcd079eb6ff830b0e481d929c93d0c7fb479c9939c28ca1945c40da09", "0x869bd916aee8d86efe362a49010382674825d49195b413b4b4018e88ce43fe091b475d0b863ff0ba2259400f280c2b23", "0x9782f38cd9c9d3385ec286ebbc7cba5b718d2e65a5890b0a5906b10a89dc8ed80d417d71d7c213bf52f2af1a1f513ea7", "0x91cd33bc2628d096269b23faf47ee15e14cb7fdc6a8e3a98b55e1031ea0b68d10ba30d97e660f7e967d24436d40fad73", "0x8becc978129cc96737034c577ae7225372dd855da8811ae4e46328e020c803833b5bdbc4a20a93270e2b8bd1a2feae52", "0xa36b1d8076783a9522476ce17f799d78008967728ce920531fdaf88303321bcaf97ecaa08e0c01f77bc32e53c5f09525", "0xb4720e744943f70467983aa34499e76de6d59aa6fadf86f6b787fdce32a2f5b535b55db38fe2da95825c51002cfe142d", "0x91ad21fc502eda3945f6de874d1b6bf9a9a7711f4d61354f9e5634fc73f9c06ada848de15ab0a75811d3250be862827d", "0x84f78e2ebf5fc077d78635f981712daf17e2475e14c2a96d187913006ad69e234746184a51a06ef510c9455b38acb0d7", "0x960aa7906e9a2f11db64a26b5892ac45f20d2ccb5480f4888d89973beb6fa0dfdc06d68d241ff5ffc7f1b82b1aac242d", "0xa99365dcd1a00c66c9db6924b97c920f5c723380e823b250db85c07631b320ec4e92e586f7319e67a522a0578f7b6d6c", "0xa25d92d7f70cf6a88ff317cfec071e13774516da664f5fac0d4ecaa65b8bf4eb87a64a4d5ef2bd97dfae98d388dbf5cc", "0xa7af47cd0041295798f9779020a44653007444e8b4ef0712982b06d0dcdd434ec4e1f7c5f7a049326602cb605c9105b7", "0xaefe172eac5568369a05980931cc476bebd9dea573ba276d59b9d8c4420784299df5a910033b7e324a6c2dfc62e3ef05", "0xb69bc9d22ffa645baa55e3e02522e9892bb2daa7fff7c15846f13517d0799766883ee09ae0869df4139150c5b843ca8a", "0x95a10856140e493354fdd12722c7fdded21b6a2ffbc78aa2697104af8ad0c8e2206f44b0bfee077ef3949d46bbf7c16b", "0x891f2fcd2c47cbea36b7fa715968540c233313f05333f09d29aba23c193f462ed490dd4d00969656e89c53155fdfe710", "0xa6c33e18115e64e385c843dde34e8a228222795c7ca90bc2cc085705d609025f3351d9be61822c69035a49fb3e48f2d5", "0xb87fb12f12c0533b005adad0487f03393ff682e13575e3cb57280c3873b2c38ba96a63c49eef7a442753d26b7005230b", "0xb905c02ba451bfd411c135036d92c27af3b0b1c9c2f1309d6948544a264b125f39dd41afeff4666b12146c545adc168a", "0x8b29c513f43a78951cf742231cf5457a6d9d55edf45df5481a0f299a418d94effef561b15d2c1a01d1b8067e7153fda9", "0xb9941cccd51dc645920d2781c81a317e5a33cb7cf76427b60396735912cb6d2ca9292bb4d36b6392467d390d2c58d9f3", "0xa8546b627c76b6ef5c93c6a98538d8593dbe21cb7673fd383d5401b0c935eea0bdeeefeb1af6ad41bad8464fb87bbc48", "0xaa286b27de2812de63108a1aec29d171775b69538dc6198640ac1e96767c2b83a50391f49259195957d457b493b667c9", "0xa932fb229f641e9abbd8eb2bd874015d97b6658ab6d29769fc23b7db9e41dd4f850382d4c1f08af8f156c5937d524473", "0xa1412840fcc86e2aeec175526f2fb36e8b3b8d21a78412b7266daf81e51b3f68584ed8bd42a66a43afdd8c297b320520", "0x89c78be9efb624c97ebca4fe04c7704fa52311d183ffd87737f76b7dadc187c12c982bd8e9ed7cd8beb48cdaafd2fd01", "0xa3f5ddec412a5bec0ce15e3bcb41c6214c2b05d4e9135a0d33c8e50a78eaba71e0a5a6ea8b45854dec5c2ed300971fc2", "0x9721f9cec7a68b7758e3887548790de49fa6a442d0396739efa20c2f50352a7f91d300867556d11a703866def2d5f7b5", "0xa23764e140a87e5991573521af039630dd28128bf56eed2edbed130fd4278e090b60cf5a1dca9de2910603d44b9f6d45", "0xa1a6494a994215e48ab55c70efa8ffdddce6e92403c38ae7e8dd2f8288cad460c6c7db526bbdf578e96ca04d9fe12797", "0xb1705ea4cb7e074efe0405fc7b8ee2ec789af0426142f3ec81241cacd4f7edcd88e39435e4e4d8e7b1df64f3880d6613", "0x85595d061d677116089a6064418b93eb44ff79e68d12bd9625078d3bbc440a60d0b02944eff6054433ee34710ae6fbb4", "0x9978d5e30bedb7526734f9a1febd973a70bfa20890490e7cc6f2f9328feab1e24f991285dbc3711d892514e2d7d005ad", "0xaf30243c66ea43b9f87a061f947f7bce745f09194f6e95f379c7582b9fead920e5d6957eaf05c12ae1282ada4670652f", "0xa1930efb473f88001e47aa0b2b2a7566848cccf295792e4544096ecd14ee5d7927c173a8576b405bfa2eec551cd67eb5", "0xb0446d1c590ee5a45f7e22d269c044f3848c97aec1d226b44bfd0e94d9729c28a38bccddc3a1006cc5fe4e3c24f001f2", "0xb8a8380172df3d84b06176df916cf557966d4f2f716d3e9437e415d75b646810f79f2b2b71d857181b7fc944018883a3", "0xa563afec25b7817bfa26e19dc9908bc00aa8fc3d19be7d6de23648701659009d10e3e4486c28e9c6b13d48231ae29ac5", "0xa5a8e80579de886fb7d6408f542791876885947b27ad6fa99a8a26e381f052598d7b4e647b0115d4b5c64297e00ce28e", "0x8f87afcc7ad33c51ac719bade3cd92da671a37a82c14446b0a2073f4a0a23085e2c8d31913ed2d0be928f053297de8f6", "0xa43c455ce377e0bc434386c53c752880687e017b2f5ae7f8a15c044895b242dffde4c92fb8f8bb50b18470b17351b156", "0x8368f8b12a5bceb1dba25adb3a2e9c7dc9b1a77a1f328e5a693f5aec195cd1e06b0fe9476b554c1c25dac6c4a5b640a3", "0x919878b27f3671fc78396f11531c032f3e2bd132d04cc234fa4858676b15fb1db3051c0b1db9b4fc49038216f11321ce", "0xb48cd67fb7f1242696c1f877da4bdf188eac676cd0e561fbac1a537f7b8229aff5a043922441d603a26aae56a15faee4", "0xa3e0fdfd4d29ea996517a16f0370b54787fefe543c2fe73bfc6f9e560c1fd30dad8409859e2d7fa2d44316f24746c712", "0x8bb156ade8faf149df7bea02c140c7e392a4742ae6d0394d880a849127943e6f26312033336d3b9fdc0092d71b5efe87", "0x8845e5d5cc555ca3e0523244300f2c8d7e4d02aaebcb5bd749d791208856c209a6f84dd99fd55968c9f0ab5f82916707", "0xa3e90bb5c97b07789c2f32dff1aec61d0a2220928202f5ad5355ae71f8249237799d6c8a22602e32e572cb12eabe0c17", "0xb150bcc391884c996149dc3779ce71f15dda63a759ee9cc05871f5a8379dcb62b047098922c0f26c7bd04deb394c33f9", "0x95cd4ad88d51f0f2efcfd0c2df802fe252bb9704d1afbf9c26a248df22d55da87bdfaf41d7bc6e5df38bd848f0b13f42", "0xa05a49a31e91dff6a52ac8b9c2cfdd646a43f0d488253f9e3cfbce52f26667166bbb9b608fc358763a65cbf066cd6d05", "0xa59c3c1227fdd7c2e81f5e11ef5c406da44662987bac33caed72314081e2eed66055d38137e01b2268e58ec85dd986c0", "0xb7020ec3bd73a99861f0f1d88cf5a19abab1cbe14b7de77c9868398c84bb8e18dbbe9831838a96b6d6ca06e82451c67b", "0x98d1ff2525e9718ee59a21d8900621636fcd873d9a564b8dceb4be80a194a0148daf1232742730b3341514b2e5a5436c", "0x886d97b635975fc638c1b6afc493e5998ca139edba131b75b65cfe5a8e814f11bb678e0eeee5e6e5cd913ad3f2fefdfc", "0x8fb9fd928d38d5d813b671c924edd56601dd7163b686c13f158645c2f869d9250f3859aa5463a39258c90fef0f41190a", "0xaac35e1cd655c94dec3580bb3800bd9c2946c4a9856f7d725af15fbea6a2d8ca51c8ad2772abed60ee0e3fb9cb24046b", "0xb8d71fa0fa05ac9e443c9b4929df9e7f09a919be679692682e614d24227e04894bfc14a5c73a62fb927fedff4a0e4aa7", "0xa45a19f11fbbb531a704badbb813ed8088ab827c884ee4e4ebf363fa1132ff7cfa9d28be9c85b143e4f7cdbc94e7cf1a", "0x82b54703a4f295f5471b255ab59dce00f0fe90c9fb6e06b9ee48b15c91d43f4e2ef4a96c3118aeb03b08767be58181bb", "0x8283264c8e6d2a36558f0d145c18576b6600ff45ff99cc93eca54b6c6422993cf392668633e5df396b9331e873d457e5", "0x8c549c03131ead601bc30eb6b9537b5d3beb7472f5bb1bcbbfd1e9f3704477f7840ab3ab7f7dc13bbbbcdff886a462d4", "0xafbb0c520ac1b5486513587700ad53e314cb74bfbc12e0b5fbdcfdaac36d342e8b59856196a0d84a25cff6e6e1d17e76", "0x89e4c22ffb51f2829061b3c7c1983c5c750cad158e3a825d46f7cf875677da5d63f653d8a297022b5db5845c9271b32b", "0xafb27a86c4c2373088c96b9adf4433f2ebfc78ac5c526e9f0510670b6e4e5e0057c0a4f75b185e1a30331b9e805c1c15", "0xa18e16b57445f88730fc5d3567bf5a176861dc14c7a08ed2996fe80eed27a0e7628501bcb78a1727c5e9ac55f29c12c4", "0x93d61bf88b192d6825cf4e1120af1c17aa0f994d158b405e25437eaeefae049f7b721a206e7cc8a04fdc29d3c42580a1", "0xa99f2995a2e3ed2fd1228d64166112038de2f516410aa439f4c507044e2017ea388604e2d0f7121256fadf7fbe7023d1", "0x914fd91cffc23c32f1c6d0e98bf660925090d873367d543034654389916f65f552e445b0300b71b61b721a72e9a5983c", "0xb42a578a7787b71f924e7def425d849c1c777156b1d4170a8ee7709a4a914e816935131afd9a0412c4cb952957b20828", "0x82fb30590e84b9e45db1ec475a39971cf554dc01bcc7050bc89265740725c02e2be5a972168c5170c86ae83e5b0ad2c0", "0xb14f8d8e1e93a84976289e0cf0dfa6f3a1809e98da16ee5c4932d0e1ed6bf8a07697fdd4dd86a3df84fb0003353cdcc0", "0x85d7a2f4bda31aa2cb208b771fe03291a4ebdaf6f1dc944c27775af5caec412584c1f45bc741fca2a6a85acb3f26ad7d", "0xaf02e56ce886ff2253bc0a68faad76f25ead84b2144e5364f3fb9b648f03a50ee9dc0b2c33ebacf7c61e9e43201ef9ef", "0x87e025558c8a0b0abd06dfc350016847ea5ced7af2d135a5c9eec9324a4858c4b21510fb0992ec52a73447f24945058e", "0x80fff0bafcd058118f5e7a4d4f1ae0912efeb281d2cbe4d34ba8945cc3dbe5d8baf47fb077343b90b8d895c90b297aca", "0xb6edcf3a40e7b1c3c0148f47a263cd819e585a51ef31c2e35a29ce6f04c53e413f743034c0d998d9c00a08ba00166f31", "0xabb87ed86098c0c70a76e557262a494ff51a30fb193f1c1a32f8e35eafa34a43fcc07aa93a3b7a077d9e35afa07b1a3d", "0xa280214cd3bb0fb7ecd2d8bcf518cbd9078417f2b91d2533ec2717563f090fb84f2a5fcfdbbeb2a2a1f8a71cc5aa5941", "0xa63083ca7238ea2b57d15a475963cf1d4f550d8cd76db290014a0461b90351f1f26a67d674c837b0b773b330c7c3d534", "0xa8fa39064cb585ece5263e2f42f430206476bf261bd50f18d2b694889bd79d04d56410664cecad62690e5c5a20b3f6ff", "0x85ba52ce9d700a5dcf6c5b00559acbe599d671ce5512467ff4b6179d7fad550567ce2a9c126a50964e3096458ea87920", "0xb913501e1008f076e5eac6d883105174f88b248e1c9801e568fefaffa1558e4909364fc6d9512aa4d125cbd7cc895f05", "0x8eb33b5266c8f2ed4725a6ad147a322e44c9264cf261c933cbbe230a43d47fca0f29ec39756b20561dabafadd5796494", "0x850ebc8b661a04318c9db5a0515066e6454fa73865aa4908767a837857ecd717387f614acb614a88e075d4edc53a2f5a", "0xa08d6b92d866270f29f4ce23a3f5d99b36b1e241a01271ede02817c8ec3f552a5c562db400766c07b104a331835c0c64", "0x8131804c89bb3e74e9718bfc4afa547c1005ff676bd4db9604335032b203390cfa54478d45c6c78d1fe31a436ed4be9f", "0x9106d94f23cc1eacec8316f16d6f0a1cc160967c886f51981fdb9f3f12ee1182407d2bb24e5b873de58cb1a3ee915a6b", "0xa13806bfc3eae7a7000c9d9f1bd25e10218d4e67f59ae798b145b098bca3edad2b1040e3fc1e6310e612fb8818f459ac", "0x8c69fbca502046cb5f6db99900a47b34117aef3f4b241690cdb3b84ca2a2fc7833e149361995dc41fa78892525bce746", "0x852c473150c91912d58ecb05769222fa18312800c3f56605ad29eec9e2d8667b0b81c379048d3d29100ed2773bb1f3c5", "0xb1767f6074426a00e01095dbb1795beb4e4050c6411792cbad6537bc444c3165d1058bafd1487451f9c5ddd209e0ae7e", "0x80c600a5fe99354ce59ff0f84c760923dc8ff66a30bf47dc0a086181785ceb01f9b951c4e66df800ea6d705e8bc47055", "0xb5cf19002fbc88a0764865b82afcb4d64a50196ea361e5c71dff7de084f4dcbbc34ec94a45cc9e0247bd51da565981aa", "0x93e67a254ea8ce25e112d93cc927fadaa814152a2c4ec7d9a56eaa1ed47aec99b7e9916b02e64452cc724a6641729bbb", "0xace70b32491bda18eee4a4d041c3bc9effae9340fe7e6c2f5ad975ee0874c17f1a7da7c96bd85fccff9312c518fac6e9", "0xab4cfa02065017dd7f1aadc66f2c92f78f0f11b8597c03a5d69d82cb2eaf95a4476a836ac102908f137662472c8d914b", "0xa40b8cd8deb8ae503d20364d64cab7c2801b7728a9646ed19c65edea6a842756a2f636283494299584ad57f4bb12cd0b", "0x8594e11d5fc2396bcd9dbf5509ce4816dbb2b7305168021c426171fb444d111da5a152d6835ad8034542277011c26c0e", "0x8024de98c26b4c994a66628dc304bb737f4b6859c86ded552c5abb81fd4c6c2e19d5a30beed398a694b9b2fdea1dd06a", "0x8843f5872f33f54df8d0e06166c1857d733995f67bc54abb8dfa94ad92407cf0179bc91b0a50bbb56cdc2b350d950329", "0xb8bab44c7dd53ef9edf497dcb228e2a41282c90f00ba052fc52d57e87b5c8ab132d227af1fcdff9a12713d1f980bcaae", "0x982b4d7b29aff22d527fd82d2a52601d95549bfb000429bb20789ed45e5abf1f4b7416c7b7c4b79431eb3574b29be658", "0x8eb1f571b6a1878e11e8c1c757e0bc084bab5e82e897ca9be9b7f4b47b91679a8190bf0fc8f799d9b487da5442415857", "0xa6e74b588e5af935c8b243e888582ef7718f8714569dd4992920740227518305eb35fab674d21a5551cca44b3e511ef2", "0xa30fc2f3a4cb4f50566e82307de73cd7bd8fe2c1184e9293c136a9b9e926a018d57c6e4f308c95b9eb8299e94d90a2a1", "0xa50c5869ca5d2b40722c056a32f918d47e0b65ca9d7863ca7d2fb4a7b64fe523fe9365cf0573733ceaadebf20b48fff8", "0x83bbdd32c04d17581418cf360749c7a169b55d54f2427390defd9f751f100897b2d800ce6636c5bbc046c47508d60c8c", "0xa82904bdf614de5d8deaff688c8a5e7ac5b3431687acbcda8fa53960b7c417a39c8b2e462d7af91ce6d79260f412db8e", "0xa4362e31ff4b05d278b033cf5eebea20de01714ae16d4115d04c1da4754269873afc8171a6f56c5104bfd7b0db93c3e7", "0xb5b8daa63a3735581e74a021b684a1038cea77168fdb7fdf83c670c2cfabcfc3ab2fc7359069b5f9048188351aef26b5", "0xb48d723894b7782d96ac8433c48faca1bdfa5238019c451a7f47d958097cce3ae599b876cf274269236b9d6ff8b6d7ca", "0x98ffff6a61a3a6205c7820a91ca2e7176fab5dba02bc194c4d14942ac421cb254183c705506ab279e4f8db066f941c6c", "0xae7db24731da2eaa6efc4f7fcba2ecc26940ddd68038dce43acf2cee15b72dc4ef42a7bfdd32946d1ed78786dd7696b3", "0xa656db14f1de9a7eb84f6301b4acb2fbf78bfe867f48a270e416c974ab92821eb4df1cb881b2d600cfed0034ac784641", "0xaa315f8ecba85a5535e9a49e558b15f39520fce5d4bf43131bfbf2e2c9dfccc829074f9083e8d49f405fb221d0bc4c3c", "0x90bffba5d9ff40a62f6c8e9fc402d5b95f6077ed58d030c93e321b8081b77d6b8dac3f63a92a7ddc01585cf2c127d66c", "0xabdd733a36e0e0f05a570d0504e73801bf9b5a25ff2c78786f8b805704997acb2e6069af342538c581144d53149fa6d3", "0xb4a723bb19e8c18a01bd449b1bb3440ddb2017f10bb153da27deb7a6a60e9bb37619d6d5435fbb1ba617687838e01dd0", "0x870016b4678bab3375516db0187a2108b2e840bae4d264b9f4f27dbbc7cc9cac1d7dc582d7a04d6fd1ed588238e5e513", "0x80d33d2e20e8fc170aa3cb4f69fffb72aeafb3b5bb4ea0bc79ab55da14142ca19b2d8b617a6b24d537366e3b49cb67c3", "0xa7ee76aec273aaae03b3b87015789289551969fb175c11557da3ab77e39ab49d24634726f92affae9f4d24003050d974", "0x8415ea4ab69d779ebd42d0fe0c6aef531d6a465a5739e429b1fcf433ec45aa8296c527e965a20f0ec9f340c9273ea3cf", "0x8c7662520794e8b4405d0b33b5cac839784bc86a5868766c06cbc1fa306dbe334978177417b31baf90ce7b0052a29c56", "0x902b2abecc053a3dbdea9897ee21e74821f3a1b98b2d560a514a35799f4680322550fd3a728d4f6d64e1de98033c32b8", "0xa05e84ed9ecab8d508d670c39f2db61ad6e08d2795ec32a3c9d0d3737ef3801618f4fc2a95f90ec2f068606131e076c5", "0x8b9208ff4d5af0c2e3f53c9375da666773ac57197dfabb0d25b1c8d0588ba7f3c15ee9661bb001297f322ea2fbf6928b", "0xa3c827741b34a03254d4451b5ab74a96f2b9f7fb069e2f5adaf54fd97cc7a4d516d378db5ca07da87d8566d6eef13726", "0x8509d8a3f4a0ed378e0a1e28ea02f6bf1d7f6c819c6c2f5297c7df54c895b848f841653e32ba2a2c22c2ff739571acb8", "0xa0ce988b7d3c40b4e496aa83a09e4b5472a2d98679622f32bea23e6d607bc7de1a5374fb162bce0549a67dad948519be", "0xaa8a3dd12bd60e3d2e05f9c683cdcb8eab17fc59134815f8d197681b1bcf65108cba63ac5c58ee632b1e5ed6bba5d474", "0x8b955f1d894b3aefd883fb4b65f14cd37fc2b9db77db79273f1700bef9973bf3fd123897ea2b7989f50003733f8f7f21", "0xac79c00ddac47f5daf8d9418d798d8af89fc6f1682e7e451f71ea3a405b0d36af35388dd2a332af790bc83ca7b819328", "0xa0d44dd2a4438b809522b130d0938c3fe7c5c46379365dbd1810a170a9aa5818e1c783470dd5d0b6d4ac7edbb7330910", "0xa30b69e39ad43dd540a43c521f05b51b5f1b9c4eed54b8162374ae11eac25da4f5756e7b70ce9f3c92c2eeceee7431ed", "0xac43220b762c299c7951222ea19761ab938bf38e4972deef58ed84f4f9c68c230647cf7506d7cbfc08562fcca55f0485", "0xb28233b46a8fb424cfa386a845a3b5399d8489ceb83c8f3e05c22c934798d639c93718b7b68ab3ce24c5358339e41cbb", "0xac30d50ee8ce59a10d4b37a3a35e62cdb2273e5e52232e202ca7d7b8d09d28958ee667fae41a7bb6cdc6fe8f6e6c9c85", "0xb199842d9141ad169f35cc7ff782b274cbaa645fdb727761e0a89edbf0d781a15f8218b4bf4eead326f2903dd88a9cc1", "0x85e018c7ddcad34bb8285a737c578bf741ccd547e68c734bdb3808380e12c5d4ef60fc896b497a87d443ff9abd063b38", "0x8c856e6ba4a815bdb891e1276f93545b7072f6cb1a9aa6aa5cf240976f29f4dee01878638500a6bf1daf677b96b54343", "0xb8a47555fa8710534150e1a3f13eab33666017be6b41005397afa647ea49708565f2b86b77ad4964d140d9ced6b4d585", "0x8cd1f1db1b2f4c85a3f46211599caf512d5439e2d8e184663d7d50166fd3008f0e9253272f898d81007988435f715881", "0xb1f34b14612c973a3eceb716dc102b82ab18afef9de7630172c2780776679a7706a4874e1df3eaadf541fb009731807f", "0xb25464af9cff883b55be2ff8daf610052c02df9a5e147a2cf4df6ce63edcdee6dc535c533590084cc177da85c5dc0baa", "0x91c3c4b658b42d8d3448ae1415d4541d02379a40dc51e36a59bd6e7b9ba3ea51533f480c7c6e8405250ee9b96a466c29", "0x86dc027b95deb74c36a58a1333a03e63cb5ae22d3b29d114cfd2271badb05268c9d0c819a977f5e0c6014b00c1512e3a", "0xae0e6ff58eb5fa35da5107ebeacf222ab8f52a22bb1e13504247c1dfa65320f40d97b0e6b201cb6613476687cb2f0681", "0x8f13415d960b9d7a1d93ef28afc2223e926639b63bdefce0f85e945dfc81670a55df288893a0d8b3abe13c5708f82f91", "0x956f67ca49ad27c1e3a68c1faad5e7baf0160c459094bf6b7baf36b112de935fdfd79fa4a9ea87ea8de0ac07272969f4", "0x835e45e4a67df9fb51b645d37840b3a15c171d571a10b03a406dd69d3c2f22df3aa9c5cbe1e73f8d767ce01c4914ea9a", "0x919b938e56d4b32e2667469d0bdccb95d9dda3341aa907683ee70a14bbbe623035014511c261f4f59b318b610ac90aa3", "0x96b48182121ccd9d689bf1dfdc228175564cd68dc904a99c808a7f0053a6f636c9d953e12198bdf2ea49ea92772f2e18", "0xac5e5a941d567fa38fdbcfa8cf7f85bb304e3401c52d88752bcd516d1fa9bac4572534ea2205e38423c1df065990790f", "0xac0bd594fb85a8d4fc26d6df0fa81f11919401f1ecf9168b891ec7f061a2d9368af99f7fd8d9b43b2ce361e7b8482159", "0x83d92c69ca540d298fe80d8162a1c7af3fa9b49dfb69e85c1d136a3ec39fe419c9fa78e0bb6d96878771fbd37fe92e40", "0xb35443ae8aa66c763c2db9273f908552fe458e96696b90e41dd509c17a5c04ee178e3490d9c6ba2dc0b8f793c433c134", "0x923b2d25aa45b2e580ffd94cbb37dc8110f340f0f011217ee1bd81afb0714c0b1d5fb4db86006cdd2457563276f59c59", "0x96c9125d38fca1a61ac21257b696f8ac3dae78def50285e44d90ea293d591d1c58f703540a7e4e99e070afe4646bbe15", "0xb57946b2332077fbcdcb406b811779aefd54473b5559a163cd65cb8310679b7e2028aa55c12a1401fdcfcac0e6fae29a", "0x845daedc5cf972883835d7e13c937b63753c2200324a3b8082a6c4abb4be06c5f7c629d4abe4bfaf1d80a1f073eb6ce6", "0x91a55dfd0efefcd03dc6dacc64ec93b8d296cb83c0ee72400a36f27246e7f2a60e73b7b70ba65819e9cfb73edb7bd297", "0x8874606b93266455fe8fdd25df9f8d2994e927460af06f2e97dd4d2d90db1e6b06d441b72c2e76504d753badca87fb37", "0x8ee99e6d231274ff9252c0f4e84549da173041299ad1230929c3e3d32399731c4f20a502b4a307642cac9306ccd49d3c", "0x8836497714a525118e20849d6933bb8535fb6f72b96337d49e3133d936999c90a398a740f42e772353b5f1c63581df6d", "0xa6916945e10628f7497a6cdc5e2de113d25f7ade3e41e74d3de48ccd4fce9f2fa9ab69645275002e6f49399b798c40af", "0x9597706983107eb23883e0812e1a2c58af7f3499d50c6e29b455946cb9812fde1aa323d9ed30d1c0ffd455abe32303cd", "0xa24ee89f7f515cc33bdbdb822e7d5c1877d337f3b2162303cfc2dae028011c3a267c5cb4194afa63a4856a6e1c213448", "0x8cd25315e4318801c2776824ae6e7d543cb85ed3bc2498ba5752df2e8142b37653cf9e60104d674be3aeb0a66912e97a", "0xb5085ecbe793180b40dbeb879f4c976eaaccaca3a5246807dced5890e0ed24d35f3f86955e2460e14fb44ff5081c07ba", "0x960188cc0b4f908633a6840963a6fa2205fc42c511c6c309685234911c5304ef4c304e3ae9c9c69daa2fb6a73560c256", "0xa32d0a70bf15d569b4cda5aebe3e41e03c28bf99cdd34ffa6c5d58a097f322772acca904b3a47addb6c7492a7126ebac", "0x977f72d06ad72d4aa4765e0f1f9f4a3231d9f030501f320fe7714cc5d329d08112789fa918c60dd7fdb5837d56bb7fc6", "0x99fa038bb0470d45852bb871620d8d88520adb701712fcb1f278fed2882722b9e729e6cdce44c82caafad95e37d0e6f7", "0xb855e8f4fc7634ada07e83b6c719a1e37acb06394bc8c7dcab7747a8c54e5df3943915f021364bd019fdea103864e55f", "0x88bc2cd7458532e98c596ef59ea2cf640d7cc31b4c33cef9ed065c078d1d4eb49677a67de8e6229cc17ea48bace8ee5a", "0xaaa78a3feaa836d944d987d813f9b9741afb076e6aca1ffa42682ab06d46d66e0c07b8f40b9dbd63e75e81efa1ef7b08", "0xb7b080420cc4d808723b98b2a5b7b59c81e624ab568ecdfdeb8bf3aa151a581b6f56e983ef1b6f909661e25db40b0c69", "0xabee85c462ac9a2c58e54f06c91b3e5cd8c5f9ab5b5deb602b53763c54826ed6deb0d6db315a8d7ad88733407e8d35e2", "0x994d075c1527407547590df53e9d72dd31f037c763848d1662eebd4cefec93a24328c986802efa80e038cb760a5300f5", "0xab8777640116dfb6678e8c7d5b36d01265dfb16321abbfc277da71556a34bb3be04bc4ae90124ed9c55386d2bfb3bda0", "0x967e3a828bc59409144463bcf883a3a276b5f24bf3cbfdd7a42343348cba91e00b46ac285835a9b91eef171202974204", "0x875a9f0c4ffe5bb1d8da5e3c8e41d0397aa6248422a628bd60bfae536a651417d4e8a7d2fb98e13f2dad3680f7bd86d3", "0xacaa330c3e8f95d46b1880126572b238dbb6d04484d2cd4f257ab9642d8c9fc7b212188b9c7ac9e0fd135c520d46b1bf", "0xaceb762edbb0f0c43dfcdb01ea7a1ac5918ca3882b1e7ebc4373521742f1ed5250d8966b498c00b2b0f4d13212e6dd0b", "0x81d072b4ad258b3646f52f399bced97c613b22e7ad76373453d80b1650c0ca87edb291a041f8253b649b6e5429bb4cff", "0x980a47d27416ac39c7c3a0ebe50c492f8c776ea1de44d5159ac7d889b6d554357f0a77f0e5d9d0ff41aae4369eba1fc2", "0x8b4dfd5ef5573db1476d5e43aacfb5941e45d6297794508f29c454fe50ea622e6f068b28b3debe8635cf6036007de2e3", "0xa60831559d6305839515b68f8c3bc7abbd8212cc4083502e19dd682d56ca37c9780fc3ce4ec2eae81ab23b221452dc57", "0x951f6b2c1848ced9e8a2339c65918e00d3d22d3e59a0a660b1eca667d18f8430d737884e9805865ef3ed0fe1638a22d9", "0xb02e38fe790b492aa5e89257c4986c9033a8b67010fa2add9787de857d53759170fdd67715ca658220b4e14b0ca48124", "0xa51007e4346060746e6b0e4797fc08ef17f04a34fe24f307f6b6817edbb8ce2b176f40771d4ae8a60d6152cbebe62653", "0xa510005b05c0b305075b27b243c9d64bcdce85146b6ed0e75a3178b5ff9608213f08c8c9246f2ca6035a0c3e31619860", "0xaaff4ef27a7a23be3419d22197e13676d6e3810ceb06a9e920d38125745dc68a930f1741c9c2d9d5c875968e30f34ab5", "0x864522a9af9857de9814e61383bebad1ba9a881696925a0ea6bfc6eff520d42c506bbe5685a9946ed710e889765be4a0", "0xb63258c080d13f3b7d5b9f3ca9929f8982a6960bdb1b0f8676f4dca823971601672f15e653917bf5d3746bb220504913", "0xb51ce0cb10869121ae310c7159ee1f3e3a9f8ad498827f72c3d56864808c1f21fa2881788f19ece884d3f705cd7bd0c5", "0x95d9cecfc018c6ed510e441cf84c712d9909c778c16734706c93222257f64dcd2a9f1bd0b400ca271e22c9c487014274", "0x8beff4d7d0140b86380ff4842a9bda94c2d2be638e20ac68a4912cb47dbe01a261857536375208040c0554929ced1ddc", "0x891ff49258749e2b57c1e9b8e04b12c77d79c3308b1fb615a081f2aacdfb4b39e32d53e069ed136fdbd43c53b87418fa", "0x9625cad224e163d387738825982d1e40eeff35fe816d10d7541d15fdc4d3eee48009090f3faef4024b249205b0b28f72", "0x8f3947433d9bd01aa335895484b540a9025a19481a1c40b4f72dd676bfcf332713714fd4010bde936eaf9470fd239ed0", "0xa00ec2d67789a7054b53f0e858a8a232706ccc29a9f3e389df7455f1a51a2e75801fd78469a13dbc25d28399ae4c6182", "0xa3f65884506d4a62b8775a0ea0e3d78f5f46bc07910a93cd604022154eabdf1d73591e304d61edc869e91462951975e1", "0xa14eef4fd5dfac311713f0faa9a60415e3d30b95a4590cbf95f2033dffb4d16c02e7ceff3dcd42148a4e3bc49cce2dd4", "0x8afa11c0eef3c540e1e3460bc759bb2b6ea90743623f88e62950c94e370fe4fd01c22b6729beba4dcd4d581198d9358f", "0xafb05548a69f0845ffcc5f5dc63e3cdb93cd270f5655173b9a950394b0583663f2b7164ba6df8d60c2e775c1d9f120af", "0x97f179e01a947a906e1cbeafa083960bc9f1bade45742a3afee488dfb6011c1c6e2db09a355d77f5228a42ccaa7bdf8e", "0x8447fca4d35f74b3efcbd96774f41874ca376bf85b79b6e66c92fa3f14bdd6e743a051f12a7fbfd87f319d1c6a5ce217", "0xa57ca39c23617cd2cf32ff93b02161bd7baf52c4effb4679d9d5166406e103bc8f3c6b5209e17c37dbb02deb8bc72ddd", "0x9667c7300ff80f0140be002b0e36caab07aaee7cce72679197c64d355e20d96196acaf54e06e1382167d081fe6f739c1", "0x828126bb0559ce748809b622677267ca896fa2ee76360fd2c02990e6477e06a667241379ca7e65d61a5b64b96d7867de", "0x8b8835dea6ba8cf61c91f01a4b3d2f8150b687a4ee09b45f2e5fc8f80f208ae5d142d8e3a18153f0722b90214e60c5a7", "0xa98e8ff02049b4da386e3ee93db23bbb13dfeb72f1cfde72587c7e6d962780b7671c63e8ac3fbaeb1a6605e8d79e2f29", "0x87a4892a0026d7e39ef3af632172b88337cb03669dea564bcdb70653b52d744730ebb5d642e20cb627acc9dbb547a26b", "0x877352a22fc8052878a57effc159dac4d75fe08c84d3d5324c0bab6d564cdf868f33ceee515eee747e5856b62cfa0cc7", "0x8b801ba8e2ff019ee62f64b8cb8a5f601fc35423eb0f9494b401050103e1307dc584e4e4b21249cd2c686e32475e96c3", "0xa9e7338d6d4d9bfec91b2af28a8ed13b09415f57a3a00e5e777c93d768fdb3f8e4456ae48a2c6626b264226e911a0e28", "0x99c05fedf40ac4726ed585d7c1544c6e79619a0d3fb6bda75a08c7f3c0008e8d5e19ed4da48de3216135f34a15eba17c", "0xa61cce8a1a8b13a4a650fdbec0eeea8297c352a8238fb7cac95a0df18ed16ee02a3daa2de108fa122aca733bd8ad7855", "0xb97f37da9005b440b4cb05870dd881bf8491fe735844f2d5c8281818583b38e02286e653d9f2e7fa5e74c3c3eb616540", "0xa72164a8554da8e103f692ac5ebb4aece55d5194302b9f74b6f2a05335b6e39beede0bf7bf8c5bfd4d324a784c5fb08c", "0xb87e8221c5341cd9cc8bb99c10fe730bc105550f25ed4b96c0d45e6142193a1b2e72f1b3857373a659b8c09be17b3d91", "0xa41fb1f327ef91dcb7ac0787918376584890dd9a9675c297c45796e32d6e5985b12f9b80be47fc3a8596c245f419d395", "0x90dafa3592bdbb3465c92e2a54c2531822ba0459d45d3e7a7092fa6b823f55af28357cb51896d4ec2d66029c82f08e26", "0xa0a9adc872ebc396557f484f1dd21954d4f4a21c4aa5eec543f5fa386fe590839735c01f236574f7ff95407cd12de103", "0xb8c5c940d58be7538acf8672852b5da3af34f82405ef2ce8e4c923f1362f97fc50921568d0fd2fe846edfb0823e62979", "0x85aaf06a8b2d0dac89dafd00c28533f35dbd074978c2aaa5bef75db44a7b12aeb222e724f395513b9a535809a275e30b", "0x81f3cbe82fbc7028c26a6c1808c604c63ba023a30c9f78a4c581340008dbda5ec07497ee849a2183fcd9124f7936af32", "0xa11ac738de75fd60f15a34209d3825d5e23385796a4c7fc5931822f3f380af977dd0f7b59fbd58eed7777a071e21b680", "0x85a279c493de03db6fa6c3e3c1b1b29adc9a8c4effc12400ae1128da8421954fa8b75ad19e5388fe4543b76fb0812813", "0x83a217b395d59ab20db6c4adb1e9713fc9267f5f31a6c936042fe051ce8b541f579442f3dcf0fa16b9e6de9fd3518191", "0x83a0b86e7d4ed8f9ccdc6dfc8ff1484509a6378fa6f09ed908e6ab9d1073f03011dc497e14304e4e3d181b57de06a5ab", "0xa63ad69c9d25704ce1cc8e74f67818e5ed985f8f851afa8412248b2df5f833f83b95b27180e9e7273833ed0d07113d3b", "0x99b1bc2021e63b561fe44ddd0af81fcc8627a91bfeecbbc989b642bc859abc0c8d636399701aad7bbaf6a385d5f27d61", "0xb53434adb66f4a807a6ad917c6e856321753e559b1add70824e5c1e88191bf6993fccb9b8b911fc0f473fb11743acacd", "0x97ed3b9e6fb99bf5f945d4a41f198161294866aa23f2327818cdd55cb5dc4c1a8eff29dd8b8d04902d6cd43a71835c82", "0xb1e808260e368a18d9d10bdea5d60223ba1713b948c782285a27a99ae50cc5fc2c53d407de07155ecc16fb8a36d744a0", "0xa3eb4665f18f71833fec43802730e56b3ee5a357ea30a888ad482725b169d6f1f6ade6e208ee081b2e2633079b82ba7d", "0xab8beb2c8353fc9f571c18fdd02bdb977fc883313469e1277b0372fbbb33b80dcff354ca41de436d98d2ed710faa467e", "0xaa9071cfa971e4a335a91ad634c98f2be51544cb21f040f2471d01bb97e1df2277ae1646e1ea8f55b7ba9f5c8c599b39", "0x80b7dbfdcaf40f0678012acc634eba44ea51181475180d9deb2050dc4f2de395289edd0223018c81057ec79b04b04c49", "0x89623d7f6cb17aa877af14de842c2d4ab7fd576d61ddd7518b5878620a01ded40b6010de0da3cdf31d837eecf30e9847", "0xa773bb024ae74dd24761f266d4fb27d6fd366a8634febe8235376b1ae9065c2fe12c769f1d0407867dfbe9f5272c352f", "0x8455a561c3aaa6ba64c881a5e13921c592b3a02e968f4fb24a2243c36202795d0366d9cc1a24e916f84d6e158b7aeac7", "0x81d8bfc4b283cf702a40b87a2b96b275bdbf0def17e67d04842598610b67ea08c804d400c3e69fa09ea001eaf345b276", "0xb8f8f82cb11fea1c99467013d7e167ff03deb0c65a677fab76ded58826d1ba29aa7cf9fcd7763615735ea3ad38e28719", "0x89a6a04baf9cccc1db55179e1650b1a195dd91fb0aebc197a25143f0f393524d2589975e3fbfc2547126f0bced7fd6f2", "0xb81b2162df045390f04df07cbd0962e6b6ca94275a63edded58001a2f28b2ae2af2c7a6cba4ecd753869684e77e7e799", "0xa3757f722776e50de45c62d9c4a2ee0f5655a512344c4cbec542d8045332806568dd626a719ef21a4eb06792ca70f204", "0x8c5590df96ec22179a4e8786de41beb44f987a1dcc508eb341eecbc0b39236fdfad47f108f852e87179ccf4e10091e59", "0x87502f026ed4e10167419130b88c3737635c5b9074c364e1dd247cef5ef0fc064b4ae99b187e33301e438bbd2fe7d032", "0xaf925a2165e980ced620ff12289129fe17670a90ae0f4db9d4b39bd887ccb1f5d2514ac9ecf910f6390a8fc66bd5be17", "0x857fca899828cf5c65d26e3e8a6e658542782fc72762b3b9c73514919f83259e0f849a9d4838b40dc905fe43024d0d23", "0x87ffebdbfb69a9e1007ebac4ffcb4090ff13705967b73937063719aa97908986effcb7262fdadc1ae0f95c3690e3245d", "0xa9ff6c347ac6f4c6ab993b748802e96982eaf489dc69032269568412fc9a79e7c2850dfc991b28211b3522ee4454344b", "0xa65b3159df4ec48bebb67cb3663cd744027ad98d970d620e05bf6c48f230fa45bf17527fe726fdf705419bb7a1bb913e", "0x84b97b1e6408b6791831997b03cd91f027e7660fd492a93d95daafe61f02427371c0e237c75706412f442991dfdff989", "0xab761c26527439b209af0ae6afccd9340bbed5fbe098734c3145b76c5d2cd7115d9227b2eb523882b7317fbb09180498", "0xa0479a8da06d7a69c0b0fee60df4e691c19c551f5e7da286dab430bfbcabf31726508e20d26ea48c53365a7f00a3ad34", "0xa732dfc9baa0f4f40b5756d2e8d8937742999623477458e0bc81431a7b633eefc6f53b3b7939fe0a020018549c954054", "0x901502436a1169ba51dc479a5abe7c8d84e0943b16bc3c6a627b49b92cd46263c0005bc324c67509edd693f28e612af1", "0xb627aee83474e7f84d1bab9b7f6b605e33b26297ac6bbf52d110d38ba10749032bd551641e73a383a303882367af429b", "0x95108866745760baef4a46ef56f82da6de7e81c58b10126ebd2ba2cd13d339f91303bf2fb4dd104a6956aa3b13739503", "0x899ed2ade37236cec90056f3569bc50f984f2247792defafcceb49ad0ca5f6f8a2f06573705300e07f0de0c759289ff5", "0xa9f5eee196d608efe4bcef9bf71c646d27feb615e21252cf839a44a49fd89da8d26a758419e0085a05b1d59600e2dc42", "0xb36c6f68fed6e6c85f1f4a162485f24817f2843ec5cbee45a1ebfa367d44892e464949c6669f7972dc7167af08d55d25", "0xaaaede243a9a1b6162afbc8f571a52671a5a4519b4062e3f26777664e245ba873ed13b0492c5dbf0258c788c397a0e9e", "0x972b4fb39c31cbe127bf9a32a5cc10d621ebdd9411df5e5da3d457f03b2ab2cd1f6372d8284a4a9400f0b06ecdbfd38e", "0x8f6ca1e110e959a4b1d9a5ce5f212893cec21db40d64d5ac4d524f352d72198f923416a850bf845bc5a22a79c0ea2619", "0xa0f3c93b22134f66f04b2553a53b738644d1665ceb196b8494b315a4c28236fb492017e4a0de4224827c78e42f9908b7", "0x807fb5ee74f6c8735b0b5ca07e28506214fe4047dbeb00045d7c24f7849e98706aea79771241224939cb749cf1366c7d", "0x915eb1ff034224c0b645442cdb7d669303fdc00ca464f91aaf0b6fde0b220a3a74ff0cb043c26c9f3a5667b3fdaa9420", "0x8fda6cef56ed33fefffa9e6ac8e6f76b1af379f89761945c63dd448801f7bb8ca970504a7105fac2f74f652ccff32327", "0x87380cffdcffb1d0820fa36b63cc081e72187f86d487315177d4d04da4533eb19a0e2ff6115ceab528887819c44a5164", "0x8cd89e03411a18e7f16f968b89fb500c36d47d229f6487b99e62403a980058db5925ce249206743333538adfad168330", "0x974451b1df33522ce7056de9f03e10c70bf302c44b0741a59df3d6877d53d61a7394dcee1dd46e013d7cb9d73419c092", "0x98c35ddf645940260c490f384a49496a7352bb8e3f686feed815b1d38f59ded17b1ad6e84a209e773ed08f7b8ff1e4c2", "0x963f386cf944bb9b2ddebb97171b64253ea0a2894ac40049bdd86cda392292315f3a3d490ca5d9628c890cfb669f0acb", "0x8d507712152babd6d142ee682638da8495a6f3838136088df9424ef50d5ec28d815a198c9a4963610b22e49b4cdf95e9", "0x83d4bc6b0be87c8a4f1e9c53f257719de0c73d85b490a41f7420e777311640937320557ff2f1d9bafd1daaa54f932356", "0x82f5381c965b7a0718441131c4d13999f4cdce637698989a17ed97c8ea2e5bdb5d07719c5f7be8688edb081b23ede0f4", "0xa6ebecab0b72a49dfd01d69fa37a7f74d34fb1d4fef0aa10e3d6fceb9eccd671225c230af89f6eb514250e41a5f91f52", "0x846d185bdad6e11e604df7f753b7a08a28b643674221f0e750ebdb6b86ec584a29c869e131bca868972a507e61403f6a", "0x85a98332292acb744bd1c0fd6fdcf1f889a78a2c9624d79413ffa194cc8dfa7821a4b60cde8081d4b5f71f51168dd67f", "0x8f7d97c3b4597880d73200d074eb813d95432306e82dafc70b580b8e08cb8098b70f2d07b4b3ac6a4d77e92d57035031", "0x8185439c8751e595825d7053518cbe121f191846a38d4dbcb558c3f9d7a3104f3153401adaaaf27843bbe2edb504bfe3", "0xb3c00d8ece1518fca6b1215a139b0a0e26d9cba1b3a424f7ee59f30ce800a5db967279ed60958dd1f3ee69cf4dd1b204", "0xa2e6cb6978e883f9719c3c0d44cfe8de0cc6f644b98f98858433bea8bbe7b612c8aca5952fccce4f195f9d54f9722dc2", "0x99663087e3d5000abbec0fbda4e7342ec38846cc6a1505191fb3f1a337cb369455b7f8531a6eb8b0f7b2c4baf83cbe2b", "0xab0836c6377a4dbc7ca6a4d6cf021d4cd60013877314dd05f351706b128d4af6337711ed3443cb6ca976f40d74070a9a", "0x87abfd5126152fd3bac3c56230579b489436755ea89e0566aa349490b36a5d7b85028e9fb0710907042bcde6a6f5d7e3", "0x974ba1033f75f60e0cf7c718a57ae1da3721cf9d0fb925714c46f027632bdd84cd9e6de4cf4d00bc55465b1c5ebb7384", "0xa607b49d73689ac64f25cec71221d30d53e781e1100d19a2114a21da6507a60166166369d860bd314acb226596525670", "0xa7c2b0b915d7beba94954f2aa7dd08ec075813661e2a3ecca5d28a0733e59583247fed9528eb28aba55b972cdbaf06eb", "0xb8b3123e44128cc8efbe3270f2f94e50ca214a4294c71c3b851f8cbb70cb67fe9536cf07d04bf7fe380e5e3a29dd3c15", "0xa59a07e343b62ad6445a0859a32b58c21a593f9ddbfe52049650f59628c93715aa1f4e1f45b109321756d0eeec8a5429", "0x94f51f8a4ed18a6030d0aaa8899056744bd0e9dc9ac68f62b00355cddab11da5da16798db75f0bfbce0e5bdfe750c0b6", "0x97460a97ca1e1fa5ce243b81425edc0ec19b7448e93f0b55bc9785eedeeafe194a3c8b33a61a5c72990edf375f122777", "0x8fa859a089bc17d698a7ee381f37ce9beadf4e5b44fce5f6f29762bc04f96faff5d58c48c73631290325f05e9a1ecf49", "0xabdf38f3b20fc95eff31de5aa9ef1031abfa48f1305ee57e4d507594570401503476d3bcc493838fc24d6967a3082c7f", "0xb8914bfb82815abb86da35c64d39ab838581bc0bf08967192697d9663877825f2b9d6fbdcf9b410463482b3731361aef", "0xa8187f9d22b193a5f578999954d6ec9aa9b32338ccadb8a3e1ce5bad5ea361d69016e1cdfac44e9d6c54e49dd88561b9", "0xaac262cb7cba7fd62c14daa7b39677cabc1ef0947dd06dd89cac8570006a200f90d5f0353e84f5ff03179e3bebe14231", "0xa630ef5ece9733b8c46c0a2df14a0f37647a85e69c63148e79ffdcc145707053f9f9d305c3f1cf3c7915cb46d33abd07", "0xb102c237cb2e254588b6d53350dfda6901bd99493a3fbddb4121d45e0b475cf2663a40d7b9a75325eda83e4ba1e68cb3", "0x86a930dd1ddcc16d1dfa00aa292cb6c2607d42c367e470aa920964b7c17ab6232a7108d1c2c11fc40fb7496547d0bbf8", "0xa832fdc4500683e72a96cce61e62ac9ee812c37fe03527ad4cf893915ca1962cee80e72d4f82b20c8fc0b764376635a1", "0x88ad985f448dabb04f8808efd90f273f11f5e6d0468b5489a1a6a3d77de342992a73eb842d419034968d733f101ff683", "0x98a8538145f0d86f7fbf9a81c9140f6095c5bdd8960b1c6f3a1716428cd9cca1bf8322e6d0af24e6169abcf7df2b0ff6", "0x9048c6eba5e062519011e177e955a200b2c00b3a0b8615bdecdebc217559d41058d3315f6d05617be531ef0f6aef0e51", "0x833bf225ab6fc68cdcacf1ec1b50f9d05f5410e6cdcd8d56a3081dc2be8a8d07b81534d1ec93a25c2e270313dfb99e3b", "0xa84bcd24c3da5e537e64a811b93c91bfc84d7729b9ead7f79078989a6eb76717d620c1fad17466a0519208651e92f5ff", "0xb7cdd0a3fbd79aed93e1b5a44ca44a94e7af5ed911e4492f332e3a5ed146c7286bde01b52276a2fcc02780d2109874dd", "0x8a19a09854e627cb95750d83c20c67442b66b35896a476358f993ba9ac114d32c59c1b3d0b8787ee3224cf3888b56c64", "0xa9abd5afb8659ee52ada8fa5d57e7dd355f0a7350276f6160bec5fbf70d5f99234dd179eb221c913e22a49ec6d267846", "0x8c13c4274c0d30d184e73eaf812200094bbbd57293780bdadbceb262e34dee5b453991e7f37c7333a654fc71c69d6445", "0xa4320d73296ff8176ce0127ca1921c450e2a9c06eff936681ebaffb5a0b05b17fded24e548454de89aca2dcf6d7a9de4", "0xb2b8b3e15c1f645f07783e5628aba614e60157889db41d8161d977606788842b67f83f361eae91815dc0abd84e09abd5", "0xad26c3aa35ddfddc15719b8bb6c264aaec7065e88ac29ba820eb61f220fef451609a7bb037f3722d022e6c86e4f1dc88", "0xb8615bf43e13ae5d7b8dd903ce37190800cd490f441c09b22aa29d7a29ed2c0417b7a08ead417868f1de2589deaadd80", "0x8d3425e1482cd1e76750a76239d33c06b3554c3c3c87c15cb7ab58b1cee86a4c5c4178b44e23f36928365a1b484bde02", "0x806893a62e38c941a7dd6f249c83af16596f69877cc737d8f73f6b8cd93cbc01177a7a276b2b8c6b0e5f2ad864db5994", "0x86618f17fa4b0d65496b661bbb5ba3bc3a87129d30a4b7d4f515b904f4206ca5253a41f49fd52095861e5e065ec54f21", "0x9551915da1304051e55717f4c31db761dcdcf3a1366c89a4af800a9e99aca93a357bf928307f098e62b44a02cb689a46", "0x8f79c4ec0ec1146cb2a523b52fe33def90d7b5652a0cb9c2d1c8808a32293e00aec6969f5b1538e3a94cd1efa3937f86", "0xa0c03e329a707300081780f1e310671315b4c6a4cedcb29697aedfabb07a9d5df83f27b20e9c44cf6b16e39d9ded5b98", "0x86a7cfa7c8e7ce2c01dd0baec2139e97e8e090ad4e7b5f51518f83d564765003c65968f85481bbb97cb18f005ccc7d9f", "0xa33811770c6dfda3f7f74e6ad0107a187fe622d61b444bbd84fd7ef6e03302e693b093df76f6ab39bb4e02afd84a575a", "0x85480f5c10d4162a8e6702b5e04f801874d572a62a130be94b0c02b58c3c59bdcd48cd05f0a1c2839f88f06b6e3cd337", "0x8e181011564b17f7d787fe0e7f3c87f6b62da9083c54c74fd6c357a1f464c123c1d3d8ade3cf72475000b464b14e2be3", "0x8ee178937294b8c991337e0621ab37e9ffa4ca2bdb3284065c5e9c08aad6785d50cf156270ff9daf9a9127289710f55b", "0x8bd1e8e2d37379d4b172f1aec96f2e41a6e1393158d7a3dbd9a95c8dd4f8e0b05336a42efc11a732e5f22b47fc5c271d", "0x8f3da353cd487c13136a85677de8cedf306faae0edec733cf4f0046f82fa4639db4745b0095ff33a9766aba50de0cbcf", "0x8d187c1e97638df0e4792b78e8c23967dac43d98ea268ca4aabea4e0fa06cb93183fd92d4c9df74118d7cc27bf54415e", "0xa4c992f08c2f8bac0b74b3702fb0c75c9838d2ce90b28812019553d47613c14d8ce514d15443159d700b218c5a312c49", "0xa6fd1874034a34c3ea962a316c018d9493d2b3719bb0ec4edbc7c56b240802b2228ab49bee6f04c8a3e9f6f24a48c1c2", "0xb2efed8e799f8a15999020900dc2c58ece5a3641c90811b86a5198e593d7318b9d53b167818ccdfbe7df2414c9c34011", "0x995ff7de6181ddf95e3ead746089c6148da3508e4e7a2323c81785718b754d356789b902e7e78e2edc6b0cbd4ff22c78", "0x944073d24750a9068cbd020b834afc72d2dde87efac04482b3287b40678ad07588519a4176b10f2172a2c463d063a5cd", "0x99db4b1bb76475a6fd75289986ef40367960279524378cc917525fb6ba02a145a218c1e9caeb99332332ab486a125ac0", "0x89fce4ecd420f8e477af4353b16faabb39e063f3f3c98fde2858b1f2d1ef6eed46f0975a7c08f233b97899bf60ccd60a", "0x8c09a4f07a02b80654798bc63aada39fd638d3e3c4236ccd8a5ca280350c31e4a89e5f4c9aafb34116e71da18c1226b8", "0x85325cfa7ded346cc51a2894257eab56e7488dbff504f10f99f4cd2b630d913003761a50f175ed167e8073f1b6b63fb0", "0xb678b4fbec09a8cc794dcbca185f133578f29e354e99c05f6d07ac323be20aecb11f781d12898168e86f2e0f09aca15e", "0xa249cfcbca4d9ba0a13b5f6aac72bf9b899adf582f9746bb2ad043742b28915607467eb794fca3704278f9136f7642be", "0x9438e036c836a990c5e17af3d78367a75b23c37f807228362b4d13e3ddcb9e431348a7b552d09d11a2e9680704a4514f", "0x925ab70450af28c21a488bfb5d38ac994f784cf249d7fd9ad251bb7fd897a23e23d2528308c03415074d43330dc37ef4", "0xa290563904d5a8c0058fc8330120365bdd2ba1fdbaef7a14bc65d4961bb4217acfaed11ab82669e359531f8bf589b8db", "0xa7e07a7801b871fc9b981a71e195a3b4ba6b6313bc132b04796a125157e78fe5c11a3a46cf731a255ac2d78a4ae78cd0", "0xb26cd2501ee72718b0eebab6fb24d955a71f363f36e0f6dff0ab1d2d7836dab88474c0cef43a2cc32701fca7e82f7df3", "0xa1dc3b6c968f3de00f11275092290afab65b2200afbcfa8ddc70e751fa19dbbc300445d6d479a81bda3880729007e496", "0xa9bc213e28b630889476a095947d323b9ac6461dea726f2dc9084473ae8e196d66fb792a21905ad4ec52a6d757863e7d", "0xb25d178df8c2df8051e7c888e9fa677fde5922e602a95e966db9e4a3d6b23ce043d7dc48a5b375c6b7c78e966893e8c3", "0xa1c8d88d72303692eaa7adf68ea41de4febec40cc14ae551bb4012afd786d7b6444a3196b5d9d5040655a3366d96b7cd", "0xb22bd44f9235a47118a9bbe2ba5a2ba9ec62476061be2e8e57806c1a17a02f9a51403e849e2e589520b759abd0117683", "0xb8add766050c0d69fe81d8d9ea73e1ed05f0135d093ff01debd7247e42dbb86ad950aceb3b50b9af6cdc14ab443b238f", "0xaf2cf95f30ef478f018cf81d70d47d742120b09193d8bb77f0d41a5d2e1a80bfb467793d9e2471b4e0ad0cb2c3b42271", "0x8af5ef2107ad284e246bb56e20fef2a255954f72de791cbdfd3be09f825298d8466064f3c98a50496c7277af32b5c0bc", "0x85dc19558572844c2849e729395a0c125096476388bd1b14fa7f54a7c38008fc93e578da3aac6a52ff1504d6ca82db05", "0xae8c9b43c49572e2e166d704caf5b4b621a3b47827bb2a3bcd71cdc599bba90396fd9a405261b13e831bb5d44c0827d7", "0xa7ba7efede25f02e88f6f4cbf70643e76784a03d97e0fbd5d9437c2485283ad7ca3abb638a5f826cd9f6193e5dec0b6c", "0x94a9d122f2f06ef709fd8016fd4b712d88052245a65a301f5f177ce22992f74ad05552b1f1af4e70d1eac62cef309752", "0x82d999b3e7cf563833b8bc028ff63a6b26eb357dfdb3fd5f10e33a1f80a9b2cfa7814d871b32a7ebfbaa09e753e37c02", "0xaec6edcde234df502a3268dd2c26f4a36a2e0db730afa83173f9c78fcb2b2f75510a02b80194327b792811caefda2725", "0x94c0bfa66c9f91d462e9194144fdd12d96f9bbe745737e73bab8130607ee6ea9d740e2cfcbbd00a195746edb6369ee61", "0xab7573dab8c9d46d339e3f491cb2826cabe8b49f85f1ede78d845fc3995537d1b4ab85140b7d0238d9c24daf0e5e2a7e", "0x87e8b16832843251fe952dadfd01d41890ed4bb4b8fa0254550d92c8cced44368225eca83a6c3ad47a7f81ff8a80c984", "0x9189d2d9a7c64791b19c0773ad4f0564ce6bea94aa275a917f78ad987f150fdb3e5e26e7fef9982ac184897ecc04683f", "0xb3661bf19e2da41415396ae4dd051a9272e8a2580b06f1a1118f57b901fa237616a9f8075af1129af4eabfefedbe2f1c", "0xaf43c86661fb15daf5d910a4e06837225e100fb5680bd3e4b10f79a2144c6ec48b1f8d6e6b98e067d36609a5d038889a", "0x82ac0c7acaa83ddc86c5b4249aae12f28155989c7c6b91e5137a4ce05113c6cbc16f6c44948b0efd8665362d3162f16a", "0x8f268d1195ab465beeeb112cd7ffd5d5548559a8bc01261106d3555533fc1971081b25558d884d552df0db1cddda89d8", "0x8ef7caa5521f3e037586ce8ac872a4182ee20c7921c0065ed9986c047e3dda08294da1165f385d008b40d500f07d895f", "0x8c2f98f6880550573fad46075d3eba26634b5b025ce25a0b4d6e0193352c8a1f0661064027a70fe8190b522405f9f4e3", "0xb7653f353564feb164f0f89ec7949da475b8dad4a4d396d252fc2a884f6932d027b7eb2dc4d280702c74569319ed701a", "0xa026904f4066333befd9b87a8fad791d014096af60cdd668ef919c24dbe295ff31f7a790e1e721ba40cf5105abca67f4", "0x988f982004ada07a22dd345f2412a228d7a96b9cae2c487de42e392afe1e35c2655f829ce07a14629148ce7079a1f142", "0x9616add009067ed135295fb74d5b223b006b312bf14663e547a0d306694ff3a8a7bb9cfc466986707192a26c0bce599f", "0xad4c425de9855f6968a17ee9ae5b15e0a5b596411388cf976df62ecc6c847a6e2ddb2cea792a5f6e9113c2445dba3e5c", "0xb698ac9d86afa3dc69ff8375061f88e3b0cff92ff6dfe747cebaf142e813c011851e7a2830c10993b715e7fd594604a9", "0xa386fa189847bb3b798efca917461e38ead61a08b101948def0f82cd258b945ed4d45b53774b400af500670149e601b7", "0x905c95abda2c68a6559d8a39b6db081c68cef1e1b4be63498004e1b2f408409be9350b5b5d86a30fd443e2b3e445640a", "0x9116dade969e7ce8954afcdd43e5cab64dc15f6c1b8da9d2d69de3f02ba79e6c4f6c7f54d6bf586d30256ae405cd1e41", "0xa3084d173eacd08c9b5084a196719b57e47a0179826fda73466758235d7ecdb87cbcf097bd6b510517d163a85a7c7edd", "0x85bb00415ad3c9be99ff9ba83672cc59fdd24356b661ab93713a3c8eab34e125d8867f628a3c3891b8dc056e69cd0e83", "0x8d58541f9f39ed2ee4478acce5d58d124031338ec11b0d55551f00a5a9a6351faa903a5d7c132dc5e4bb026e9cbd18e4", "0xa622adf72dc250e54f672e14e128c700166168dbe0474cecb340da175346e89917c400677b1bc1c11fcc4cc26591d9db", "0xb3f865014754b688ca8372e8448114fff87bf3ca99856ab9168894d0c4679782c1ced703f5b74e851b370630f5e6ee86", "0xa7e490b2c40c2446fcd91861c020da9742c326a81180e38110558bb5d9f2341f1c1885e79b364e6419023d1cbdc47380", "0xb3748d472b1062e54572badbb8e87ac36534407f74932e7fc5b8392d008e8e89758f1671d1e4d30ab0fa40551b13bb5e", "0x89898a5c5ec4313aabc607b0049fd1ebad0e0c074920cf503c9275b564d91916c2c446d3096491c950b7af3ac5e4b0ed", "0x8eb8c83fef2c9dd30ea44e286e9599ec5c20aba983f702e5438afe2e5b921884327ad8d1566c72395587efac79ca7d56", "0xb92479599e806516ce21fb0bd422a1d1d925335ebe2b4a0a7e044dd275f30985a72b97292477053ac5f00e081430da80", "0xa34ae450a324fe8a3c25a4d653a654f9580ed56bbea213b8096987bbad0f5701d809a17076435e18017fea4d69f414bc", "0x81381afe6433d62faf62ea488f39675e0091835892ecc238e02acf1662669c6d3962a71a3db652f6fe3bc5f42a0e5dc5", "0xa430d475bf8580c59111103316fe1aa79c523ea12f1d47a976bbfae76894717c20220e31cf259f08e84a693da6688d70", "0xb842814c359754ece614deb7d184d679d05d16f18a14b288a401cef5dad2cf0d5ee90bad487b80923fc5573779d4e4e8", "0x971d9a2627ff2a6d0dcf2af3d895dfbafca28b1c09610c466e4e2bff2746f8369de7f40d65b70aed135fe1d72564aa88", "0x8f4ce1c59e22b1ce7a0664caaa7e53735b154cfba8d2c5cc4159f2385843de82ab58ed901be876c6f7fce69cb4130950", "0x86cc9dc321b6264297987000d344fa297ef45bcc2a4df04e458fe2d907ad304c0ea2318e32c3179af639a9a56f3263cf", "0x8229e0876dfe8f665c3fb19b250bd89d40f039bbf1b331468b403655be7be2e104c2fd07b9983580c742d5462ca39a43", "0x99299d73066e8eb128f698e56a9f8506dfe4bd014931e86b6b487d6195d2198c6c5bf15cccb40ccf1f8ddb57e9da44a2", "0xa3a3be37ac554c574b393b2f33d0a32a116c1a7cfeaf88c54299a4da2267149a5ecca71f94e6c0ef6e2f472b802f5189", "0xa91700d1a00387502cdba98c90f75fbc4066fefe7cc221c8f0e660994c936badd7d2695893fde2260c8c11d5bdcdd951", "0x8e03cae725b7f9562c5c5ab6361644b976a68bada3d7ca508abca8dfc80a469975689af1fba1abcf21bc2a190dab397d", "0xb01461ad23b2a8fa8a6d241e1675855d23bc977dbf4714add8c4b4b7469ccf2375cec20e80cedfe49361d1a30414ac5b", "0xa2673bf9bc621e3892c3d7dd4f1a9497f369add8cbaa3472409f4f86bd21ac67cfac357604828adfee6ada1835365029", "0xa042dff4bf0dfc33c178ba1b335e798e6308915128de91b12e5dbbab7c4ac8d60a01f6aea028c3a6d87b9b01e4e74c01", "0x86339e8a75293e4b3ae66b5630d375736b6e6b6b05c5cda5e73fbf7b2f2bd34c18a1d6cefede08625ce3046e77905cb8", "0xaf2ebe1b7d073d03e3d98bc61af83bf26f7a8c130fd607aa92b75db22d14d016481b8aa231e2c9757695f55b7224a27f", "0xa00ee882c9685e978041fd74a2c465f06e2a42ffd3db659053519925be5b454d6f401e3c12c746e49d910e4c5c9c5e8c", "0x978a781c0e4e264e0dad57e438f1097d447d891a1e2aa0d5928f79a9d5c3faae6f258bc94fdc530b7b2fa6a9932bb193", "0xaa4b7ce2e0c2c9e9655bf21e3e5651c8503bce27483017b0bf476be743ba06db10228b3a4c721219c0779747f11ca282", "0xb003d1c459dacbcf1a715551311e45d7dbca83a185a65748ac74d1800bbeaba37765d9f5a1a221805c571910b34ebca8", "0x95b6e531b38648049f0d19de09b881baa1f7ea3b2130816b006ad5703901a05da57467d1a3d9d2e7c73fb3f2e409363c", "0xa6cf9c06593432d8eba23a4f131bb7f72b9bd51ab6b4b772a749fe03ed72b5ced835a349c6d9920dba2a39669cb7c684", "0xaa3d59f6e2e96fbb66195bc58c8704e139fa76cd15e4d61035470bd6e305db9f98bcbf61ac1b95e95b69ba330454c1b3", "0xb57f97959c208361de6d7e86dff2b873068adb0f158066e646f42ae90e650079798f165b5cd713141cd3a2a90a961d9a", "0xa76ee8ed9052f6a7a8c69774bb2597be182942f08115baba03bf8faaeaee526feba86120039fe8ca7b9354c3b6e0a8e6", "0x95689d78c867724823f564627d22d25010f278674c6d2d0cdb10329169a47580818995d1d727ce46c38a1e47943ebb89", "0xab676d2256c6288a88e044b3d9ffd43eb9d5aaee00e8fc60ac921395fb835044c71a26ca948e557fed770f52d711e057", "0x96351c72785c32e5d004b6f4a1259fb8153d631f0c93fed172f18e8ba438fbc5585c1618deeabd0d6d0b82173c2e6170", "0x93dd8d3db576418e22536eba45ab7f56967c6c97c64260d6cddf38fb19c88f2ec5cd0e0156f50e70855eee8a2b879ffd", "0xad6ff16f40f6de3d7a737f8e6cebd8416920c4ff89dbdcd75eabab414af9a6087f83ceb9aff7680aa86bff98bd09c8cc", "0x84de53b11671abc9c38710e19540c5c403817562aeb22a88404cdaff792c1180f717dbdfe8f54940c062c4d032897429", "0x872231b9efa1cdd447b312099a5c164c560440a9441d904e70f5abfc3b2a0d16be9a01aca5e0a2599a61e19407587e3d", "0x88f44ac27094a2aa14e9dc40b099ee6d68f97385950f303969d889ee93d4635e34dff9239103bdf66a4b7cbba3e7eb7a", "0xa59afebadf0260e832f6f44468443562f53fbaf7bcb5e46e1462d3f328ac437ce56edbca617659ac9883f9e13261fad7", "0xb1990e42743a88de4deeacfd55fafeab3bc380cb95de43ed623d021a4f2353530bcab9594389c1844b1c5ea6634c4555", "0x85051e841149a10e83f56764e042182208591396d0ce78c762c4a413e6836906df67f38c69793e158d64fef111407ba3", "0x9778172bbd9b1f2ec6bbdd61829d7b39a7df494a818e31c654bf7f6a30139899c4822c1bf418dd4f923243067759ce63", "0x9355005b4878c87804fc966e7d24f3e4b02bed35b4a77369d01f25a3dcbff7621b08306b1ac85b76fe7b4a3eb5f839b1", "0x8f9dc6a54fac052e236f8f0e1f571ac4b5308a43acbe4cc8183bce26262ddaf7994e41cf3034a4cbeca2c505a151e3b1", "0x8cc59c17307111723fe313046a09e0e32ea0cce62c13814ab7c6408c142d6a0311d801be4af53fc9240523f12045f9ef", "0x8e6057975ed40a1932e47dd3ac778f72ee2a868d8540271301b1aa6858de1a5450f596466494a3e0488be4fbeb41c840", "0x812145efbd6559ae13325d56a15940ca4253b17e72a9728986b563bb5acc13ec86453796506ac1a8f12bd6f9e4a288c3", "0x911da0a6d6489eb3dab2ec4a16e36127e8a291ae68a6c2c9de33e97f3a9b1f00da57a94e270a0de79ecc5ecb45d19e83", "0xb72ea85973f4b2a7e6e71962b0502024e979a73c18a9111130e158541fa47bbaaf53940c8f846913a517dc69982ba9e1", "0xa7a56ad1dbdc55f177a7ad1d0af78447dc2673291e34e8ab74b26e2e2e7d8c5fe5dc89e7ef60f04a9508847b5b3a8188", "0xb52503f6e5411db5d1e70f5fb72ccd6463fa0f197b3e51ca79c7b5a8ab2e894f0030476ada72534fa4eb4e06c3880f90", "0xb51c7957a3d18c4e38f6358f2237b3904618d58b1de5dec53387d25a63772e675a5b714ad35a38185409931157d4b529", "0xb86b4266e719d29c043d7ec091547aa6f65bbf2d8d831d1515957c5c06513b72aa82113e9645ad38a7bc3f5383504fa6", "0xb95b547357e6601667b0f5f61f261800a44c2879cf94e879def6a105b1ad2bbf1795c3b98a90d588388e81789bd02681", "0xa58fd4c5ae4673fa350da6777e13313d5d37ed1dafeeb8f4f171549765b84c895875d9d3ae6a9741f3d51006ef81d962", "0x9398dc348d078a604aadc154e6eef2c0be1a93bb93ba7fe8976edc2840a3a318941338cc4d5f743310e539d9b46613d2", "0x902c9f0095014c4a2f0dccaaab543debba6f4cc82c345a10aaf4e72511725dbed7a34cd393a5f4e48a3e5142b7be84ed", "0xa7c0447849bb44d04a0393a680f6cd390093484a79a147dd238f5d878030d1c26646d88211108e59fe08b58ad20c6fbd", "0x80db045535d6e67a422519f5c89699e37098449d249698a7cc173a26ccd06f60238ae6cc7242eb780a340705c906790c", "0x8e52b451a299f30124505de2e74d5341e1b5597bdd13301cc39b05536c96e4380e7f1b5c7ef076f5b3005a868657f17c", "0x824499e89701036037571761e977654d2760b8ce21f184f2879fda55d3cda1e7a95306b8abacf1caa79d3cc075b9d27f", "0x9049b956b77f8453d2070607610b79db795588c0cec12943a0f5fe76f358dea81e4f57a4692112afda0e2c05c142b26f", "0x81911647d818a4b5f4990bfd4bc13bf7be7b0059afcf1b6839333e8569cdb0172fd2945410d88879349f677abaed5eb3", "0xad4048f19b8194ed45b6317d9492b71a89a66928353072659f5ce6c816d8f21e69b9d1817d793effe49ca1874daa1096", "0x8d22f7b2ddb31458661abd34b65819a374a1f68c01fc6c9887edeba8b80c65bceadb8f57a3eb686374004b836261ef67", "0x92637280c259bc6842884db3d6e32602a62252811ae9b019b3c1df664e8809ffe86db88cfdeb8af9f46435c9ee790267", "0xa2f416379e52e3f5edc21641ea73dc76c99f7e29ea75b487e18bd233856f4c0183429f378d2bfc6cd736d29d6cadfa49", "0x882cb6b76dbdc188615dcf1a8439eba05ffca637dd25197508156e03c930b17b9fed2938506fdd7b77567cb488f96222", "0xb68b621bb198a763fb0634eddb93ed4b5156e59b96c88ca2246fd1aea3e6b77ed651e112ac41b30cd361fadc011d385e", "0xa3cb22f6b675a29b2d1f827cacd30df14d463c93c3502ef965166f20d046af7f9ab7b2586a9c64f4eae4fad2d808a164", "0x8302d9ce4403f48ca217079762ce42cee8bc30168686bb8d3a945fbd5acd53b39f028dce757b825eb63af2d5ae41169d", "0xb2eef1fbd1a176f1f4cd10f2988c7329abe4eb16c7405099fb92baa724ab397bc98734ef7d4b24c0f53dd90f57520d04", "0xa1bbef0bd684a3f0364a66bde9b29326bac7aa3dde4caed67f14fb84fed3de45c55e406702f1495a3e2864d4ee975030", "0x976acdb0efb73e3a3b65633197692dedc2adaed674291ae3df76b827fc866d214e9cac9ca46baefc4405ff13f953d936", "0xb9fbf71cc7b6690f601f0b1c74a19b7d14254183a2daaafec7dc3830cba5ae173d854bbfebeca985d1d908abe5ef0cda", "0x90591d7b483598c94e38969c4dbb92710a1a894bcf147807f1bcbd8aa3ac210b9f2be65519aa829f8e1ccdc83ad9b8cf", "0xa30568577c91866b9c40f0719d46b7b3b2e0b4a95e56196ac80898a2d89cc67880e1229933f2cd28ee3286f8d03414d7", "0x97589a88c3850556b359ec5e891f0937f922a751ac7c95949d3bbc7058c172c387611c0f4cb06351ef02e5178b3dd9e4", "0x98e7bbe27a1711f4545df742f17e3233fbcc63659d7419e1ca633f104cb02a32c84f2fac23ca2b84145c2672f68077ab", "0xa7ddb91636e4506d8b7e92aa9f4720491bb71a72dadc47c7f4410e15f93e43d07d2b371951a0e6a18d1bd087aa96a5c4", "0xa7c006692227a06db40bceac3d5b1daae60b5692dd9b54772bedb5fea0bcc91cbcdb530cac31900ffc70c5b3ffadc969", "0x8d3ec6032778420dfa8be52066ba0e623467df33e4e1901dbadd586c5d750f4ccde499b5197e26b9ea43931214060f69", "0x8d9a8410518ea64f89df319bfd1fc97a0971cdb9ad9b11d1f8fe834042ea7f8dce4db56eeaf179ff8dda93b6db93e5ce", "0xa3c533e9b3aa04df20b9ff635cb1154ce303e045278fcf3f10f609064a5445552a1f93989c52ce852fd0bbd6e2b6c22e", "0x81934f3a7f8c1ae60ec6e4f212986bcc316118c760a74155d06ce0a8c00a9b9669ec4e143ca214e1b995e41271774fd9", "0xab8e2d01a71192093ef8fafa7485e795567cc9db95a93fb7cc4cf63a391ef89af5e2bfad4b827fffe02b89271300407f", "0x83064a1eaa937a84e392226f1a60b7cfad4efaa802f66de5df7498962f7b2649924f63cd9962d47906380b97b9fe80e1", "0xb4f5e64a15c6672e4b55417ee5dc292dcf93d7ea99965a888b1cc4f5474a11e5b6520eacbcf066840b343f4ceeb6bf33", "0xa63d278b842456ef15c278b37a6ea0f27c7b3ffffefca77c7a66d2ea06c33c4631eb242bbb064d730e70a8262a7b848a", "0x83a41a83dbcdf0d22dc049de082296204e848c453c5ab1ba75aa4067984e053acf6f8b6909a2e1f0009ed051a828a73b", "0x819485b036b7958508f15f3c19436da069cbe635b0318ebe8c014cf1ef9ab2df038c81161b7027475bcfa6fff8dd9faf", "0xaa40e38172806e1e045e167f3d1677ef12d5dcdc89b43639a170f68054bd196c4fae34c675c1644d198907a03f76ba57", "0x969bae484883a9ed1fbed53b26b3d4ee4b0e39a6c93ece5b3a49daa01444a1c25727dabe62518546f36b047b311b177c", "0x80a9e73a65da99664988b238096a090d313a0ee8e4235bc102fa79bb337b51bb08c4507814eb5baec22103ec512eaab0", "0x86604379aec5bddda6cbe3ef99c0ac3a3c285b0b1a15b50451c7242cd42ae6b6c8acb717dcca7917838432df93a28502", "0xa23407ee02a495bed06aa7e15f94cfb05c83e6d6fba64456a9bbabfa76b2b68c5c47de00ba169e710681f6a29bb41a22", "0x98cff5ecc73b366c6a01b34ac9066cb34f7eeaf4f38a5429bad2d07e84a237047e2a065c7e8a0a6581017dadb4695deb", "0x8de9f68a938f441f3b7ab84bb1f473c5f9e5c9e139e42b7ccee1d254bd57d0e99c2ccda0f3198f1fc5737f6023dd204e", "0xb0ce48d815c2768fb472a315cad86aa033d0e9ca506f146656e2941829e0acb735590b4fbc713c2d18d3676db0a954ac", "0x82f485cdefd5642a6af58ac6817991c49fac9c10ace60f90b27f1788cc026c2fe8afc83cf499b3444118f9f0103598a8", "0x82c24550ed512a0d53fc56f64cc36b553823ae8766d75d772dacf038c460f16f108f87a39ceef7c66389790f799dbab3", "0x859ffcf1fe9166388316149b9acc35694c0ea534d43f09dae9b86f4aa00a23b27144dda6a352e74b9516e8c8d6fc809c", "0xb8f7f353eec45da77fb27742405e5ad08d95ec0f5b6842025be9def3d9892f85eb5dd0921b41e6eff373618dba215bca", "0x8ccca4436f9017e426229290f5cd05eac3f16571a4713141a7461acfe8ae99cd5a95bf5b6df129148693c533966145da", "0xa2c67ecc19c0178b2994846fea4c34c327a5d786ac4b09d1d13549d5be5996d8a89021d63d65cb814923388f47cc3a03", "0xaa0ff87d676b418ec08f5cbf577ac7e744d1d0e9ebd14615b550eb86931eafd2a36d4732cc5d6fab1713fd7ab2f6f7c0", "0x8aef4730bb65e44efd6bb9441c0ae897363a2f3054867590a2c2ecf4f0224e578c7a67f10b40f8453d9f492ac15a9b2d", "0x86a187e13d8fba5addcfdd5b0410cedd352016c930f913addd769ee09faa6be5ca3e4b1bdb417a965c643a99bd92be42", "0xa0a4e9632a7a094b14b29b78cd9c894218cdf6783e61671e0203865dc2a835350f465fbaf86168f28af7c478ca17bc89", "0xa8c7b02d8deff2cd657d8447689a9c5e2cd74ef57c1314ac4d69084ac24a7471954d9ff43fe0907d875dcb65fd0d3ce5", "0x97ded38760aa7be6b6960b5b50e83b618fe413cbf2bcc1da64c05140bcc32f5e0e709cd05bf8007949953fac5716bad9", "0xb0d293835a24d64c2ae48ce26e550b71a8c94a0883103757fb6b07e30747f1a871707d23389ba2b2065fa6bafe220095", "0x8f9e291bf849feaa575592e28e3c8d4b7283f733d41827262367ea1c40f298c7bcc16505255a906b62bf15d9f1ba85fb", "0x998f4e2d12708b4fd85a61597ca2eddd750f73c9e0c9b3cf0825d8f8e01f1628fd19797dcaed3b16dc50331fc6b8b821", "0xb30d1f8c115d0e63bf48f595dd10908416774c78b3bbb3194192995154d80ea042d2e94d858de5f8aa0261b093c401fd", "0xb5d9c75bb41f964cbff3f00e96d9f1480c91df8913f139f0d385d27a19f57a820f838eb728e46823cbff00e21c660996", "0xa6edec90b5d25350e2f5f0518777634f9e661ec9d30674cf5b156c4801746d62517751d90074830ac0f4b09911c262f1", "0x82f98da1264b6b75b8fbeb6a4d96d6a05b25c24db0d57ba3a38efe3a82d0d4e331b9fc4237d6494ccfe4727206457519", "0xb89511843453cf4ecd24669572d6371b1e529c8e284300c43e0d5bb6b3aaf35aeb634b3cb5c0a2868f0d5e959c1d0772", "0xa82bf065676583e5c1d3b81987aaae5542f522ba39538263a944bb33ea5b514c649344a96c0205a3b197a3f930fcda6c", "0xa37b47ea527b7e06c460776aa662d9a49ff4149d3993f1a974b0dd165f7171770d189b0e2ea54fd5fccb6a14b116e68a", "0xa1017677f97dda818274d47556d09d0e4ccacb23a252f82a6cfe78c630ad46fb9806307445a59fb61262182de3a2b29c", "0xb01e9fcac239ba270e6877b79273ddd768bf8a51d2ed8a051b1c11e18eff3de5920e2fcbfbd26f06d381eddd3b1f1e1b", "0x82fcd53d803b1c8e4ed76adc339b7f3a5962d37042b9683aabac7513ac68775d4a566a9460183926a6a95dbe7d551a1f", "0xa763e78995d55cd21cdb7ef75d9642d6e1c72453945e346ab6690c20a4e1eeec61bb848ef830ae4b56182535e3c71d8f", "0xb769f4db602251d4b0a1186782799bdcef66de33c110999a5775c50b349666ffd83d4c89714c4e376f2efe021a5cfdb2", "0xa59cbd1b785efcfa6e83fc3b1d8cf638820bc0c119726b5368f3fba9dce8e3414204fb1f1a88f6c1ff52e87961252f97", "0x95c8c458fd01aa23ecf120481a9c6332ebec2e8bb70a308d0576926a858457021c277958cf79017ddd86a56cacc2d7db", "0x82eb41390800287ae56e77f2e87709de5b871c8bdb67c10a80fc65f3acb9f7c29e8fa43047436e8933f27449ea61d94d", "0xb3ec25e3545eb83aed2a1f3558d1a31c7edde4be145ecc13b33802654b77dc049b4f0065069dd9047b051e52ab11dcdd", "0xb78a0c715738f56f0dc459ab99e252e3b579b208142836b3c416b704ca1de640ca082f29ebbcee648c8c127df06f6b1e", "0xa4083149432eaaf9520188ebf4607d09cf664acd1f471d4fb654476e77a9eaae2251424ffda78d09b6cb880df35c1219", "0x8c52857d68d6e9672df3db2df2dbf46b516a21a0e8a18eec09a6ae13c1ef8f369d03233320dd1c2c0bbe00abfc1ea18b", "0x8c856089488803066bff3f8d8e09afb9baf20cecc33c8823c1c0836c3d45498c3de37e87c016b705207f60d2b00f8609", "0x831a3df39be959047b2aead06b4dcd3012d7b29417f642b83c9e8ce8de24a3dbbd29c6fdf55e2db3f7ea04636c94e403", "0xaed84d009f66544addabe404bf6d65af7779ce140dc561ff0c86a4078557b96b2053b7b8a43432ffb18cd814f143b9da", "0x93282e4d72b0aa85212a77b336007d8ba071eea17492da19860f1ad16c1ea8867ccc27ef5c37c74b052465cc11ea4f52", "0xa7b78b8c8d057194e8d68767f1488363f77c77bddd56c3da2bc70b6354c7aa76247c86d51f7371aa38a4aa7f7e3c0bb7", "0xb1c77283d01dcd1bde649b5b044eac26befc98ff57cbee379fb5b8e420134a88f2fc7f0bf04d15e1fbd45d29e7590fe6", "0xa4aa8de70330a73b2c6458f20a1067eed4b3474829b36970a8df125d53bbdda4f4a2c60063b7cccb0c80fc155527652f", "0x948a6c79ba1b8ad7e0bed2fae2f0481c4e41b4d9bbdd9b58164e28e9065700e83f210c8d5351d0212e0b0b68b345b3a5", "0x86a48c31dcbbf7b082c92d28e1f613a2378a910677d7db3a349dc089e4a1e24b12eee8e8206777a3a8c64748840b7387", "0x976adb1af21e0fc34148917cf43d933d7bfd3fd12ed6c37039dcd5a4520e3c6cf5868539ba5bf082326430deb8a4458d", "0xb93e1a4476f2c51864bb4037e7145f0635eb2827ab91732b98d49b6c07f6ac443111aa1f1da76d1888665cb897c3834e", "0x8afd46fb23bf869999fa19784b18a432a1f252d09506b8dbb756af900518d3f5f244989b3d7c823d9029218c655d3dc6", "0x83f1e59e3abeed18cdc632921672673f1cb6e330326e11c4e600e13e0d5bc11bdc970ae12952e15103a706fe720bf4d6", "0x90ce4cc660714b0b673d48010641c09c00fc92a2c596208f65c46073d7f349dd8e6e077ba7dcef9403084971c3295b76", "0x8b09b0f431a7c796561ecf1549b85048564de428dac0474522e9558b6065fede231886bc108539c104ce88ebd9b5d1b0", "0x85d6e742e2fb16a7b0ba0df64bc2c0dbff9549be691f46a6669bca05e89c884af16822b85faefefb604ec48c8705a309", "0xa87989ee231e468a712c66513746fcf03c14f103aadca0eac28e9732487deb56d7532e407953ab87a4bf8961588ef7b0", "0xb00da10efe1c29ee03c9d37d5918e391ae30e48304e294696b81b434f65cf8c8b95b9d1758c64c25e534d045ba28696f", "0x91c0e1fb49afe46c7056400baa06dbb5f6e479db78ee37e2d76c1f4e88994357e257b83b78624c4ef6091a6c0eb8254d", "0x883fb797c498297ccbf9411a3e727c3614af4eccde41619b773dc7f3259950835ee79453debf178e11dec4d3ada687a0", "0xa14703347e44eb5059070b2759297fcfcfc60e6893c0373eea069388eba3950aa06f1c57cd2c30984a2d6f9e9c92c79e", "0xafebc7585b304ceba9a769634adff35940e89cd32682c78002822aab25eec3edc29342b7f5a42a56a1fec67821172ad5", "0xaea3ff3822d09dba1425084ca95fd359718d856f6c133c5fabe2b2eed8303b6e0ba0d8698b48b93136a673baac174fd9", "0xaf2456a09aa777d9e67aa6c7c49a1845ea5cdda2e39f4c935c34a5f8280d69d4eec570446998cbbe31ede69a91e90b06", "0x82cada19fed16b891ef3442bafd49e1f07c00c2f57b2492dd4ee36af2bd6fd877d6cb41188a4d6ce9ec8d48e8133d697", "0x82a21034c832287f616619a37c122cee265cc34ae75e881fcaea4ea7f689f3c2bc8150bbf7dbcfd123522bfb7f7b1d68", "0x86877217105f5d0ec3eeff0289fc2a70d505c9fdf7862e8159553ef60908fb1a27bdaf899381356a4ef4649072a9796c", "0x82b196e49c6e861089a427c0b4671d464e9d15555ffb90954cd0d630d7ae02eb3d98ceb529d00719c2526cd96481355a", "0xa29b41d0d43d26ce76d4358e0db2b77df11f56e389f3b084d8af70a636218bd3ac86b36a9fe46ec9058c26a490f887f7", "0xa4311c4c20c4d7dd943765099c50f2fd423e203ccfe98ff00087d205467a7873762510cac5fdce7a308913ed07991ed7", "0xb1f040fc5cc51550cb2c25cf1fd418ecdd961635a11f365515f0cb4ffb31da71f48128c233e9cc7c0cf3978d757ec84e", "0xa9ebae46f86d3bd543c5f207ed0d1aed94b8375dc991161d7a271f01592912072e083e2daf30c146430894e37325a1b9", "0x826418c8e17ad902b5fe88736323a47e0ca7a44bce4cbe27846ec8fe81de1e8942455dda6d30e192cdcc73e11df31256", "0x85199db563427c5edcbac21f3d39fec2357be91fb571982ddcdc4646b446ad5ced84410de008cb47b3477ee0d532daf8", "0xb7eed9cd400b2ca12bf1d9ae008214b8561fb09c8ad9ff959e626ffde00fee5ff2f5b6612e231f2a1a9b1646fcc575e3", "0x8b40bf12501dcbac78f5a314941326bfcddf7907c83d8d887d0bb149207f85d80cd4dfbd7935439ea7b14ea39a3fded7", "0x83e3041af302485399ba6cd5120e17af61043977083887e8d26b15feec4a6b11171ac5c06e6ad0971d4b58a81ff12af3", "0x8f5b9a0eecc589dbf8c35a65d5e996a659277ef6ea509739c0cb7b3e2da9895e8c8012de662e5b23c5fa85d4a8f48904", "0x835d71ed5e919d89d8e6455f234f3ff215462c4e3720c371ac8c75e83b19dfe3ae15a81547e4dc1138e5f5997f413cc9", "0x8b7d2e4614716b1db18e9370176ea483e6abe8acdcc3dcdf5fb1f4d22ca55d652feebdccc171c6de38398d9f7bfdec7a", "0x93eace72036fe57d019676a02acf3d224cf376f166658c1bf705db4f24295881d477d6fdd7916efcfceff8c7a063deda", "0xb1ac460b3d516879a84bc886c54f020a9d799e7c49af3e4d7de5bf0d2793c852254c5d8fe5616147e6659512e5ccb012", "0xacd0947a35cb167a48bcd9667620464b54ac0e78f9316b4aa92dcaab5422d7a732087e52e1c827faa847c6b2fe6e7766", "0x94ac33d21c3d12ff762d32557860e911cd94d666609ddcc42161b9c16f28d24a526e8b10bb03137257a92cec25ae637d", "0x832e02058b6b994eadd8702921486241f9a19e68ed1406dad545e000a491ae510f525ccf9d10a4bba91c68f2c53a0f58", "0x9471035d14f78ff8f463b9901dd476b587bb07225c351161915c2e9c6114c3c78a501379ab6fb4eb03194c457cbd22bf", "0xab64593e034c6241d357fcbc32d8ea5593445a5e7c24cac81ad12bd2ef01843d477a36dc1ba21dbe63b440750d72096a", "0x9850f3b30045e927ad3ec4123a32ed2eb4c911f572b6abb79121873f91016f0d80268de8b12e2093a4904f6e6cab7642", "0x987212c36b4722fe2e54fa30c52b1e54474439f9f35ca6ad33c5130cd305b8b54b532dd80ffd2c274105f20ce6d79f6e", "0x8b4d0c6abcb239b5ed47bef63bc17efe558a27462c8208fa652b056e9eae9665787cd1aee34fbb55beb045c8bfdb882b", "0xa9f3483c6fee2fe41312d89dd4355d5b2193ac413258993805c5cbbf0a59221f879386d3e7a28e73014f10e65dd503d9", "0xa2225da3119b9b7c83d514b9f3aeb9a6d9e32d9cbf9309cbb971fd53c4b2c001d10d880a8ad8a7c281b21d85ceca0b7c", "0xa050be52e54e676c151f7a54453bbb707232f849beab4f3bf504b4d620f59ed214409d7c2bd3000f3ff13184ccda1c35", "0xadbccf681e15b3edb6455a68d292b0a1d0f5a4cb135613f5e6db9943f02181341d5755875db6ee474e19ace1c0634a28", "0x8b6eff675632a6fad0111ec72aacc61c7387380eb87933fd1d098856387d418bd38e77d897e65d6fe35951d0627c550b", "0xaabe2328ddf90989b15e409b91ef055cb02757d34987849ae6d60bef2c902bf8251ed21ab30acf39e500d1d511e90845", "0x92ba4eb1f796bc3d8b03515f65c045b66e2734c2da3fc507fdd9d6b5d1e19ab3893726816a32141db7a31099ca817d96", "0x8a98b3cf353138a1810beb60e946183803ef1d39ac4ea92f5a1e03060d35a4774a6e52b14ead54f6794d5f4022b8685c", "0x909f8a5c13ec4a59b649ed3bee9f5d13b21d7f3e2636fd2bb3413c0646573fdf9243d63083356f12f5147545339fcd55", "0x9359d914d1267633141328ed0790d81c695fea3ddd2d406c0df3d81d0c64931cf316fe4d92f4353c99ff63e2aefc4e34", "0xb88302031681b54415fe8fbfa161c032ea345c6af63d2fb8ad97615103fd4d4281c5a9cae5b0794c4657b97571a81d3b", "0x992c80192a519038082446b1fb947323005b275e25f2c14c33cc7269e0ec038581cc43705894f94bad62ae33a8b7f965", "0xa78253e3e3eece124bef84a0a8807ce76573509f6861d0b6f70d0aa35a30a123a9da5e01e84969708c40b0669eb70aa6", "0x8d5724de45270ca91c94792e8584e676547d7ac1ac816a6bb9982ee854eb5df071d20545cdfd3771cd40f90e5ba04c8e", "0x825a6f586726c68d45f00ad0f5a4436523317939a47713f78fd4fe81cd74236fdac1b04ecd97c2d0267d6f4981d7beb1" ], "g2_monomial": [ "0x93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8", "0xb5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2", "0xb5337ba0ce5d37224290916e268e2060e5c14f3f9fc9e1ec3af5a958e7a0303122500ce18f1a4640bf66525bd10e763501fe986d86649d8d45143c08c3209db3411802c226e9fe9a55716ac4a0c14f9dcef9e70b2bb309553880dc5025eab3cc", "0xb3c1dcdc1f62046c786f0b82242ef283e7ed8f5626f72542aa2c7a40f14d9094dd1ebdbd7457ffdcdac45fd7da7e16c51200b06d791e5e43e257e45efdf0bd5b06cd2333beca2a3a84354eb48662d83aef5ecf4e67658c851c10b13d8d87c874", "0x954d91c7688983382609fca9e211e461f488a5971fd4e40d7e2892037268eacdfd495cfa0a7ed6eb0eb11ac3ae6f651716757e7526abe1e06c64649d80996fd3105c20c4c94bc2b22d97045356fe9d791f21ea6428ac48db6f9e68e30d875280", "0x88a6b6bb26c51cf9812260795523973bb90ce80f6820b6c9048ab366f0fb96e48437a7f7cb62aedf64b11eb4dfefebb0147608793133d32003cb1f2dc47b13b5ff45f1bb1b2408ea45770a08dbfaec60961acb8119c47b139a13b8641e2c9487", "0x85cd7be9728bd925d12f47fb04b32d9fad7cab88788b559f053e69ca18e463113ecc8bbb6dbfb024835f901b3a957d3108d6770fb26d4c8be0a9a619f6e3a4bf15cbfd48e61593490885f6cee30e4300c5f9cf5e1c08e60a2d5b023ee94fcad0", "0x80477dba360f04399821a48ca388c0fa81102dd15687fea792ee8c1114e00d1bc4839ad37ac58900a118d863723acfbe08126ea883be87f50e4eabe3b5e72f5d9e041db8d9b186409fd4df4a7dde38c0e0a3b1ae29b098e5697e7f110b6b27e4", "0xb7a6aec08715a9f8672a2b8c367e407be37e59514ac19dd4f0942a68007bba3923df22da48702c63c0d6b3efd3c2d04e0fe042d8b5a54d562f9f33afc4865dcbcc16e99029e25925580e87920c399e710d438ac1ce3a6dc9b0d76c064a01f6f7", "0xac1b001edcea02c8258aeffbf9203114c1c874ad88dae1184fadd7d94cd09053649efd0ca413400e6e9b5fa4eac33261000af88b6bd0d2abf877a4f0355d2fb4d6007adb181695201c5432e50b850b51b3969f893bddf82126c5a71b042b7686", "0x90043fda4de53fb364fab2c04be5296c215599105ecff0c12e4917c549257125775c29f2507124d15f56e30447f367db0596c33237242c02d83dfd058735f1e3c1ff99069af55773b6d51d32a68bf75763f59ec4ee7267932ae426522b8aaab6", "0xa8660ce853e9dc08271bf882e29cd53397d63b739584dda5263da4c7cc1878d0cf6f3e403557885f557e184700575fee016ee8542dec22c97befe1d10f414d22e84560741cdb3e74c30dda9b42eeaaf53e27822de2ee06e24e912bf764a9a533", "0x8fe3921a96d0d065e8aa8fce9aa42c8e1461ca0470688c137be89396dd05103606dab6cdd2a4591efd6addf72026c12e065da7be276dee27a7e30afa2bd81c18f1516e7f068f324d0bad9570b95f6bd02c727cd2343e26db0887c3e4e26dceda", "0x8ae1ad97dcb9c192c9a3933541b40447d1dc4eebf380151440bbaae1e120cc5cdf1bcea55180b128d8e180e3af623815191d063cc0d7a47d55fb7687b9d87040bf7bc1a7546b07c61db5ccf1841372d7c2fe4a5431ffff829f3c2eb590b0b710", "0x8c2fa96870a88150f7876c931e2d3cc2adeaaaf5c73ef5fa1cf9dfa0991ae4819f9321af7e916e5057d87338e630a2f21242c29d76963cf26035b548d2a63d8ad7bd6efefa01c1df502cbdfdfe0334fb21ceb9f686887440f713bf17a89b8081", "0xb9aa98e2f02bb616e22ee5dd74c7d1049321ac9214d093a738159850a1dbcc7138cb8d26ce09d8296368fd5b291d74fa17ac7cc1b80840fdd4ee35e111501e3fa8485b508baecda7c1ab7bd703872b7d64a2a40b3210b6a70e8a6ffe0e5127e3", "0x9292db67f8771cdc86854a3f614a73805bf3012b48f1541e704ea4015d2b6b9c9aaed36419769c87c49f9e3165f03edb159c23b3a49c4390951f78e1d9b0ad997129b17cdb57ea1a6638794c0cca7d239f229e589c5ae4f9fe6979f7f8cba1d7", "0x91cd9e86550f230d128664f7312591fee6a84c34f5fc7aed557bcf986a409a6de722c4330453a305f06911d2728626e611acfdf81284f77f60a3a1595053a9479964fd713117e27c0222cc679674b03bc8001501aaf9b506196c56de29429b46", "0xa9516b73f605cc31b89c68b7675dc451e6364595243d235339437f556cf22d745d4250c1376182273be2d99e02c10eee047410a43eff634d051aeb784e76cb3605d8e079b9eb6ad1957dfdf77e1cd32ce4a573c9dfcc207ca65af6eb187f6c3d", "0xa9667271f7d191935cc8ad59ef3ec50229945faea85bfdfb0d582090f524436b348aaa0183b16a6231c00332fdac2826125b8c857a2ed9ec66821cfe02b3a2279be2412441bc2e369b255eb98614e4be8490799c4df22f18d47d24ec70bba5f7", "0xa4371144d2aa44d70d3cb9789096d3aa411149a6f800cb46f506461ee8363c8724667974252f28aea61b6030c05930ac039c1ee64bb4bd56532a685cae182bf2ab935eee34718cffcb46cae214c77aaca11dbb1320faf23c47247db1da04d8dc", "0x89a7eb441892260b7e81168c386899cd84ffc4a2c5cad2eae0d1ab9e8b5524662e6f660fe3f8bfe4c92f60b060811bc605b14c5631d16709266886d7885a5eb5930097127ec6fb2ebbaf2df65909cf48f253b3d5e22ae48d3e9a2fd2b01f447e", "0x9648c42ca97665b5eccb49580d8532df05eb5a68db07f391a2340769b55119eaf4c52fe4f650c09250fa78a76c3a1e271799b8333cc2628e3d4b4a6a3e03da1f771ecf6516dd63236574a7864ff07e319a6f11f153406280d63af9e2b5713283", "0x9663bf6dd446ea7a90658ee458578d4196dc0b175ef7fcfa75f44d41670850774c2e46c5a6be132a2c072a3c0180a24f0305d1acac49d2d79878e5cda80c57feda3d01a6af12e78b5874e2a4b3717f11c97503b41a4474e2e95b179113726199", "0xb212aeb4814e0915b432711b317923ed2b09e076aaf558c3ae8ef83f9e15a83f9ea3f47805b2750ab9e8106cb4dc6ad003522c84b03dc02829978a097899c773f6fb31f7fe6b8f2d836d96580f216fec20158f1590c3e0d7850622e15194db05", "0x925f005059bf07e9ceccbe66c711b048e236ade775720d0fe479aebe6e23e8af281225ad18e62458dc1b03b42ad4ca290d4aa176260604a7aad0d9791337006fbdebe23746f8060d42876f45e4c83c3643931392fde1cd13ff8bddf8111ef974", "0x9553edb22b4330c568e156a59ef03b26f5c326424f830fe3e8c0b602f08c124730ffc40bc745bec1a22417adb22a1a960243a10565c2be3066bfdb841d1cd14c624cd06e0008f4beb83f972ce6182a303bee3fcbcabc6cfe48ec5ae4b7941bfc", "0x935f5a404f0a78bdcce709899eda0631169b366a669e9b58eacbbd86d7b5016d044b8dfc59ce7ed8de743ae16c2343b50e2f925e88ba6319e33c3fc76b314043abad7813677b4615c8a97eb83cc79de4fedf6ccbcfa4d4cbf759a5a84e4d9742", "0xa5b014ab936eb4be113204490e8b61cd38d71da0dec7215125bcd131bf3ab22d0a32ce645bca93e7b3637cf0c2db3d6601a0ddd330dc46f9fae82abe864ffc12d656c88eb50c20782e5bb6f75d18760666f43943abb644b881639083e122f557", "0x935b7298ae52862fa22bf03bfc1795b34c70b181679ae27de08a9f5b4b884f824ef1b276b7600efa0d2f1d79e4a470d51692fd565c5cf8343dd80e5d3336968fc21c09ba9348590f6206d4424eb229e767547daefa98bc3aa9f421158dee3f2a", "0x9830f92446e708a8f6b091cc3c38b653505414f8b6507504010a96ffda3bcf763d5331eb749301e2a1437f00e2415efb01b799ad4c03f4b02de077569626255ac1165f96ea408915d4cf7955047620da573e5c439671d1fa5c833fb11de7afe6", "0x840dcc44f673fff3e387af2bb41e89640f2a70bcd2b92544876daa92143f67c7512faf5f90a04b7191de01f3e2b1bde00622a20dc62ca23bbbfaa6ad220613deff43908382642d4d6a86999f662efd64b1df448b68c847cfa87630a3ffd2ec76", "0x92950c895ed54f7f876b2fda17ecc9c41b7accfbdd42c210cc5b475e0737a7279f558148531b5c916e310604a1de25a80940c94fe5389ae5d6a5e9c371be67bceea1877f5401725a6595bcf77ece60905151b6dfcb68b75ed2e708c73632f4fd", "0x8010246bf8e94c25fd029b346b5fbadb404ef6f44a58fd9dd75acf62433d8cc6db66974f139a76e0c26dddc1f329a88214dbb63276516cf325c7869e855d07e0852d622c332ac55609ba1ec9258c45746a2aeb1af0800141ee011da80af175d4", "0xb0f1bad257ebd187bdc3f37b23f33c6a5d6a8e1f2de586080d6ada19087b0e2bf23b79c1b6da1ee82271323f5bdf3e1b018586b54a5b92ab6a1a16bb3315190a3584a05e6c37d5ca1e05d702b9869e27f513472bcdd00f4d0502a107773097da", "0x9636d24f1ede773ce919f309448dd7ce023f424afd6b4b69cb98c2a988d849a283646dc3e469879daa1b1edae91ae41f009887518e7eb5578f88469321117303cd3ac2d7aee4d9cb5f82ab9ae3458e796dfe7c24284b05815acfcaa270ff22e2", "0xb373feb5d7012fd60578d7d00834c5c81df2a23d42794fed91aa9535a4771fde0341c4da882261785e0caca40bf83405143085e7f17e55b64f6c5c809680c20b050409bf3702c574769127c854d27388b144b05624a0e24a1cbcc4d08467005b", "0xb15680648949ce69f82526e9b67d9b55ce5c537dc6ab7f3089091a9a19a6b90df7656794f6edc87fb387d21573ffc847062623685931c2790a508cbc8c6b231dd2c34f4d37d4706237b1407673605a604bcf6a50cc0b1a2db20485e22b02c17e", "0x8817e46672d40c8f748081567b038a3165f87994788ec77ee8daea8587f5540df3422f9e120e94339be67f186f50952504cb44f61e30a5241f1827e501b2de53c4c64473bcc79ab887dd277f282fbfe47997a930dd140ac08b03efac88d81075", "0xa6e4ef6c1d1098f95aae119905f87eb49b909d17f9c41bcfe51127aa25fee20782ea884a7fdf7d5e9c245b5a5b32230b07e0dbf7c6743bf52ee20e2acc0b269422bd6cf3c07115df4aa85b11b2c16630a07c974492d9cdd0ec325a3fabd95044", "0x8634aa7c3d00e7f17150009698ce440d8e1b0f13042b624a722ace68ead870c3d2212fbee549a2c190e384d7d6ac37ce14ab962c299ea1218ef1b1489c98906c91323b94c587f1d205a6edd5e9d05b42d591c26494a6f6a029a2aadb5f8b6f67", "0x821a58092900bdb73decf48e13e7a5012a3f88b06288a97b855ef51306406e7d867d613d9ec738ebacfa6db344b677d21509d93f3b55c2ebf3a2f2a6356f875150554c6fff52e62e3e46f7859be971bf7dd9d5b3e1d799749c8a97c2e04325df", "0x8dba356577a3a388f782e90edb1a7f3619759f4de314ad5d95c7cc6e197211446819c4955f99c5fc67f79450d2934e3c09adefc91b724887e005c5190362245eec48ce117d0a94d6fa6db12eda4ba8dde608fbbd0051f54dcf3bb057adfb2493", "0xa32a690dc95c23ed9fb46443d9b7d4c2e27053a7fcc216d2b0020a8cf279729c46114d2cda5772fd60a97016a07d6c5a0a7eb085a18307d34194596f5b541cdf01b2ceb31d62d6b55515acfd2b9eec92b27d082fbc4dc59fc63b551eccdb8468", "0xa040f7f4be67eaf0a1d658a3175d65df21a7dbde99bfa893469b9b43b9d150fc2e333148b1cb88cfd0447d88fa1a501d126987e9fdccb2852ecf1ba907c2ca3d6f97b055e354a9789854a64ecc8c2e928382cf09dda9abde42bbdf92280cdd96", "0x864baff97fa60164f91f334e0c9be00a152a416556b462f96d7c43b59fe1ebaff42f0471d0bf264976f8aa6431176eb905bd875024cf4f76c13a70bede51dc3e47e10b9d5652d30d2663b3af3f08d5d11b9709a0321aba371d2ef13174dcfcaf", "0x95a46f32c994133ecc22db49bad2c36a281d6b574c83cfee6680b8c8100466ca034b815cfaedfbf54f4e75188e661df901abd089524e1e0eb0bf48d48caa9dd97482d2e8c1253e7e8ac250a32fd066d5b5cb08a8641bdd64ecfa48289dca83a3", "0xa2cce2be4d12144138cb91066e0cd0542c80b478bf467867ebef9ddaf3bd64e918294043500bf5a9f45ee089a8d6ace917108d9ce9e4f41e7e860cbce19ac52e791db3b6dde1c4b0367377b581f999f340e1d6814d724edc94cb07f9c4730774", "0xb145f203eee1ac0a1a1731113ffa7a8b0b694ef2312dabc4d431660f5e0645ef5838e3e624cfe1228cfa248d48b5760501f93e6ab13d3159fc241427116c4b90359599a4cb0a86d0bb9190aa7fabff482c812db966fd2ce0a1b48cb8ac8b3bca", "0xadabe5d215c608696e03861cbd5f7401869c756b3a5aadc55f41745ad9478145d44393fec8bb6dfc4ad9236dc62b9ada0f7ca57fe2bae1b71565dbf9536d33a68b8e2090b233422313cc96afc7f1f7e0907dc7787806671541d6de8ce47c4cd0", "0xae7845fa6b06db53201c1080e01e629781817f421f28956589c6df3091ec33754f8a4bd4647a6bb1c141ac22731e3c1014865d13f3ed538dcb0f7b7576435133d9d03be655f8fbb4c9f7d83e06d1210aedd45128c2b0c9bab45a9ddde1c862a5", "0x9159eaa826a24adfa7adf6e8d2832120ebb6eccbeb3d0459ffdc338548813a2d239d22b26451fda98cc0c204d8e1ac69150b5498e0be3045300e789bcb4e210d5cd431da4bdd915a21f407ea296c20c96608ded0b70d07188e96e6c1a7b9b86b", "0xa9fc6281e2d54b46458ef564ffaed6944bff71e389d0acc11fa35d3fcd8e10c1066e0dde5b9b6516f691bb478e81c6b20865281104dcb640e29dc116daae2e884f1fe6730d639dbe0e19a532be4fb337bf52ae8408446deb393d224eee7cfa50", "0x84291a42f991bfb36358eedead3699d9176a38f6f63757742fdbb7f631f2c70178b1aedef4912fed7b6cf27e88ddc7eb0e2a6aa4b999f3eb4b662b93f386c8d78e9ac9929e21f4c5e63b12991fcde93aa64a735b75b535e730ff8dd2abb16e04", "0xa1b7fcacae181495d91765dfddf26581e8e39421579c9cbd0dd27a40ea4c54af3444a36bf85a11dda2114246eaddbdd619397424bb1eb41b5a15004b902a590ede5742cd850cf312555be24d2df8becf48f5afba5a8cd087cb7be0a521728386", "0x92feaaf540dbd84719a4889a87cdd125b7e995a6782911931fef26da9afcfbe6f86aaf5328fe1f77631491ce6239c5470f44c7791506c6ef1626803a5794e76d2be0af92f7052c29ac6264b7b9b51f267ad820afc6f881460521428496c6a5f1", "0xa525c925bfae1b89320a5054acc1fa11820f73d0cf28d273092b305467b2831fab53b6daf75fb926f332782d50e2522a19edcd85be5eb72f1497193c952d8cd0bcc5d43b39363b206eae4cb1e61668bde28a3fb2fc1e0d3d113f6dfadb799717", "0x98752bb6f5a44213f40eda6aa4ff124057c1b13b6529ab42fe575b9afa66e59b9c0ed563fb20dff62130c436c3e905ee17dd8433ba02c445b1d67182ab6504a90bbe12c26a754bbf734665c622f76c62fe2e11dd43ce04fd2b91a8463679058b", "0xa9aa9a84729f7c44219ff9e00e651e50ddea3735ef2a73fdf8ed8cd271961d8ed7af5cd724b713a89a097a3fe65a3c0202f69458a8b4c157c62a85668b12fc0d3957774bc9b35f86c184dd03bfefd5c325da717d74192cc9751c2073fe9d170e", "0xb221c1fd335a4362eff504cd95145f122bf93ea02ae162a3fb39c75583fc13a932d26050e164da97cff3e91f9a7f6ff80302c19dd1916f24acf6b93b62f36e9665a8785413b0c7d930c7f1668549910f849bca319b00e59dd01e5dec8d2edacc", "0xa71e2b1e0b16d754b848f05eda90f67bedab37709550171551050c94efba0bfc282f72aeaaa1f0330041461f5e6aa4d11537237e955e1609a469d38ed17f5c2a35a1752f546db89bfeff9eab78ec944266f1cb94c1db3334ab48df716ce408ef", "0xb990ae72768779ba0b2e66df4dd29b3dbd00f901c23b2b4a53419226ef9232acedeb498b0d0687c463e3f1eead58b20b09efcefa566fbfdfe1c6e48d32367936142d0a734143e5e63cdf86be7457723535b787a9cfcfa32fe1d61ad5a2617220", "0x8d27e7fbff77d5b9b9bbc864d5231fecf817238a6433db668d5a62a2c1ee1e5694fdd90c3293c06cc0cb15f7cbeab44d0d42be632cb9ff41fc3f6628b4b62897797d7b56126d65b694dcf3e298e3561ac8813fbd7296593ced33850426df42db", "0xa92039a08b5502d5b211a7744099c9f93fa8c90cedcb1d05e92f01886219dd464eb5fb0337496ad96ed09c987da4e5f019035c5b01cc09b2a18b8a8dd419bc5895388a07e26958f6bd26751929c25f89b8eb4a299d822e2d26fec9ef350e0d3c", "0x92dcc5a1c8c3e1b28b1524e3dd6dbecd63017c9201da9dbe077f1b82adc08c50169f56fc7b5a3b28ec6b89254de3e2fd12838a761053437883c3e01ba616670cea843754548ef84bcc397de2369adcca2ab54cd73c55dc68d87aec3fc2fe4f10" ] } ================================================ FILE: kurtosis/src/nodes/nodes.star ================================================ CONSENSUS_DEFAULT_SETTINGS = { "specs": { "min_cpu": 0, "max_cpu": 2000, "min_memory": 0, "max_memory": 2048, }, "images": { "beaconkit": "beacond:kurtosis-local", }, "labels": {}, "node_selectors": {}, "config": { "timeout_propose": "3s", "timeout_prevote": "1s", "timeout_precommit": "1s", "max_num_inbound_peers": 40, "max_num_outbound_peers": 10, }, "app": { "payload-timeout": "1.5s", }, } EXECUTION_DEFAULT_SETTINGS = { "specs": { "min_cpu": 0, "max_cpu": 2000, "min_memory": 0, "max_memory": 2048, }, "images": { "reth": "ghcr.io/berachain/bera-reth:nightly", }, "labels": {}, "node_selectors": {}, } CL_TYPE = "beaconkit" def parse_nodes_from_dict(vals, settings): node_type = vals["type"] node_list = [] consensus_settings = parse_consensus_settings(settings) execution_settings = parse_execution_settings(settings) count = 0 for val_configuration in vals["nodes"]: replicas = 1 if "replicas" in val_configuration: replicas = val_configuration["replicas"] if replicas != 0: for i in range(replicas): val_struct = parse_node_from_dict(node_type, val_configuration, consensus_settings, execution_settings, count) node_list.append(val_struct) count += 1 return node_list def parse_node_from_dict(node_type, val, consensus_settings, execution_settings, index): # if kzg implementation is not provided, give default kzg_impl = "crate-crypto/go-kzg-4844" if "kzg_impl" in val: kzg_impl = val["kzg_impl"] return struct( node_type = node_type, el_type = val["el_type"], el_image = execution_settings.images[val["el_type"]], cl_type = CL_TYPE, cl_image = consensus_settings.images[CL_TYPE], index = index, cl_service_name = "cl-{}-{}-{}".format(node_type, CL_TYPE, index), el_service_name = "el-{}-{}-{}".format(node_type, val["el_type"], index), consensus_settings = consensus_settings, execution_settings = execution_settings, kzg_impl = kzg_impl, ) def parse_consensus_settings(settings): consensus_settings = {} if "consensus_settings" in settings: consensus_settings = dict(settings["consensus_settings"]) consensus_settings = parse_default_node_settings(consensus_settings, CONSENSUS_DEFAULT_SETTINGS) consensus_settings = parse_extra_consensus_settings(consensus_settings) return get_consensus_struct(consensus_settings) def parse_extra_consensus_settings(settings): config_settings = parse_consensus_config_settings(settings["config"]) if "config" in settings else parse_consensus_config_settings(CONSENSUS_DEFAULT_SETTINGS["config"]) app_settings = parse_consensus_app_settings(settings["app"]) if "app" in settings else parse_consensus_app_settings(CONSENSUS_DEFAULT_SETTINGS["app"]) consensus_settings = dict(settings) consensus_settings["config"] = config_settings consensus_settings["app"] = app_settings return consensus_settings def parse_consensus_config_settings(config_settings): config_settings = dict(config_settings) if "timeout_propose" not in config_settings: config_settings["timeout_propose"] = CONSENSUS_DEFAULT_SETTINGS["config"]["timeout_propose"] if "timeout_prevote" not in config_settings: config_settings["timeout_prevote"] = CONSENSUS_DEFAULT_SETTINGS["config"]["timeout_prevote"] if "timeout_precommit" not in config_settings: config_settings["timeout_precommit"] = CONSENSUS_DEFAULT_SETTINGS["config"]["timeout_precommit"] if "max_num_inbound_peers" not in config_settings: config_settings["max_num_inbound_peers"] = CONSENSUS_DEFAULT_SETTINGS["config"]["max_num_inbound_peers"] if "max_num_outbound_peers" not in config_settings: config_settings["max_num_outbound_peers"] = CONSENSUS_DEFAULT_SETTINGS["config"]["max_num_outbound_peers"] return struct( timeout_propose = config_settings["timeout_propose"], timeout_prevote = config_settings["timeout_prevote"], timeout_precommit = config_settings["timeout_precommit"], max_num_inbound_peers = config_settings["max_num_inbound_peers"], max_num_outbound_peers = config_settings["max_num_outbound_peers"], ) def parse_consensus_app_settings(app_settings): app_settings = dict(app_settings) if "payload_timeout" not in app_settings: app_settings["payload_timeout"] = CONSENSUS_DEFAULT_SETTINGS["app"]["payload_timeout"] return struct( payload_timeout = app_settings["payload_timeout"], ) def parse_execution_settings(settings): execution_settings = {} if "execution_settings" in settings: execution_settings = dict(settings["execution_settings"]) execution_settings = parse_default_node_settings(execution_settings, EXECUTION_DEFAULT_SETTINGS) return get_execution_struct(execution_settings) def parse_default_node_settings(settings, default_settings): node_settings = dict(settings) if "specs" not in node_settings: node_settings["specs"] = default_settings["specs"] node_specs = dict(node_settings["specs"]) if "min_cpu" not in node_specs: node_specs["min_cpu"] = default_settings["specs"]["min_cpu"] if "max_cpu" not in node_specs: node_specs["max_cpu"] = default_settings["specs"]["max_cpu"] if "min_memory" not in node_specs: node_specs["min_memory"] = default_settings["specs"]["min_memory"] if "max_memory" not in node_specs: node_specs["max_memory"] = default_settings["specs"]["max_memory"] if "images" not in node_settings: node_settings["images"] = default_settings["images"] if "labels" not in node_settings: node_settings["labels"] = default_settings["labels"] if "node_selectors" not in node_settings: node_settings["node_selectors"] = default_settings["node_selectors"] node_specs = struct( min_cpu = node_specs["min_cpu"], max_cpu = node_specs["max_cpu"], min_memory = node_specs["min_memory"], max_memory = node_specs["max_memory"], ) node_settings["specs"] = node_specs return node_settings def get_consensus_struct(consensus_settings): return struct( specs = consensus_settings["specs"], images = consensus_settings["images"], labels = consensus_settings["labels"], node_selectors = consensus_settings["node_selectors"], config = consensus_settings["config"], app = consensus_settings["app"], ) def get_execution_struct(execution_settings): return struct( specs = execution_settings["specs"], images = execution_settings["images"], labels = execution_settings["labels"], node_selectors = execution_settings["node_selectors"], ) def int_to_hex(plan, n): """Convert integer to hex string with '0x' prefix using shell printf""" result = plan.run_sh( run = 'printf "0x%x" ' + str(n), description = "Converting {} to hex".format(n), ) return str(result.output.strip()) def render_genesis_template(plan, template_path, chain_id, chain_id_hex, genesis_deposits_root, genesis_deposit_count_hex): """Helper function to render a specific genesis template""" genesis_template = read_file(src = template_path) artifact = plan.render_templates( config = { "genesis.json": struct( template = genesis_template, data = { "CHAIN_ID": chain_id, "CHAIN_ID_HEX": chain_id_hex, "GENESIS_DEPOSIT_COUNT_HEX": genesis_deposit_count_hex, "GENESIS_DEPOSITS_ROOT": genesis_deposits_root, }, ), }, # As we are rendering the template twice, add GENESIS_DEPOSITS_ROOT to the name name = template_path + "_" + genesis_deposits_root, description = "Rendering genesis.json template", ) return artifact def create_genesis_files_part1(plan, chain_id): """Creates genesis files for all client types and returns them as a dict""" # Convert chain_id to hexadecimal string chain_id_hex = int_to_hex(plan, int(chain_id)) genesis_files = {} # Render default genesis for all clients default_artifact = render_genesis_template( plan, "../networks/kurtosis-devnet/network-configs/genesis.json.template", chain_id, chain_id_hex, "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", ) genesis_files["default"] = default_artifact return genesis_files # This has the deposit contract storage slots and we need to modify the eth genesis files with them. def create_genesis_files_part2(plan, chain_id, genesis_deposits_root, genesis_deposit_count_hex): """Creates genesis files for all client types and returns them as a dict""" # Convert chain_id to hexadecimal string chain_id_hex = int_to_hex(plan, int(chain_id)) genesis_files = {} # Render default genesis for all clients default_artifact = render_genesis_template( plan, "../networks/kurtosis-devnet/network-configs/genesis.json.template", chain_id, chain_id_hex, genesis_deposits_root, genesis_deposit_count_hex, ) genesis_files["default"] = default_artifact return genesis_files ================================================ FILE: kurtosis/src/observability/grafana/dashboard-providers.yml.tmpl ================================================ apiVersion: 1 providers: # an unique provider name. Required - name: '{{ .DashboardProviderName }}' # Org id. Default to 1 orgId: 1 # name of the dashboard folder. folder: '' # folder UID. will be automatically generated if not specified folderUid: '' # provider type. Default to 'file' type: file # disable dashboard deletion disableDeletion: false # how often Grafana will scan for changed dashboards updateIntervalSeconds: 10 # allow updating provisioned dashboards from the UI allowUiUpdates: true editable: true options: # path to dashboard files on disk. Required when using the 'file' type path: {{ .DashboardsDirpath }} # use folder names from filesystem to create folders in Grafana foldersFromFilesStructure: true ================================================ FILE: kurtosis/src/observability/grafana/datasource.yml.tmpl ================================================ apiVersion: 1 # can add support for non prometheus datasource to this package in the future datasources: - name: prometheus type: prometheus access: proxy orgId: 1 url: {{ .PrometheusURL }} basicAuth: false isDefault: true editable: true ================================================ FILE: kurtosis/src/observability/grafana/grafana.star ================================================ CONFIG_DIR_PATH = "/config" DASHBOARDS_DIR_PATH = "/dashboards" def start(plan, prometheus_url): run(plan, prometheus_url, "github.com/berachain/helm-charts/grafana-dashboards") def run( plan, prometheus_url, grafana_dashboards_location, name = "grafana", grafana_dashboards_name = "Grafana Dashboards in Kurtosis"): """Runs provided Grafana dashboards in Kurtosis. Args: prometheus_url(string): Prometheus endpoint that will populate Grafana dashboard data. grafana_dashboards_location(string): Where to find config for Grafana dashboard(s) (usually sitting somewhere repo of that's importing this package)) grafana_dashboards_name(string): Name of Grafana Dashboard provider. """ # create config files artifacts based on datasource and dashboard providers info datasource_config_template = read_file(src = "./datasource.yml.tmpl") dashboard_provider_config_template = read_file(src = "./dashboard-providers.yml.tmpl") grafana_config_files_artifact = plan.render_templates( config = { "datasources/datasource.yml": struct( template = datasource_config_template, data = {"PrometheusURL": prometheus_url}, ), "dashboards/dashboard-providers.yml": struct( template = dashboard_provider_config_template, data = { "DashboardProviderName": grafana_dashboards_name, "DashboardsDirpath": DASHBOARDS_DIR_PATH, }, ), }, ) # grab grafana dashboards from given location and upload them into enclave as a files artifact # grafana_dashboards_files_artifact = plan.upload_files(src = grafana_dashboards_location, name = "grafana-dashboards") plan.add_service(name = name, config = ServiceConfig( image = "grafana/grafana-enterprise:9.5.12", ports = { "dashboards": PortSpec( number = 3000, transport_protocol = "TCP", application_protocol = "http", ), }, env_vars = { "GF_PATHS_PROVISIONING": CONFIG_DIR_PATH, "GF_AUTH_ANONYMOUS_ENABLED": "true", "GF_AUTH_ANONYMOUS_ORG_ROLE": "Admin", "GF_AUTH_ANONYMOUS_ORG_NAME": "Main Org.", }, files = { CONFIG_DIR_PATH: grafana_config_files_artifact, # DASHBOARDS_DIR_PATH: grafana_dashboards_files_artifact, }, )) ================================================ FILE: kurtosis/src/observability/prometheus/prometheus.star ================================================ prometheus = import_module("github.com/kurtosis-tech/prometheus-package/main.star") """ A service should follow the format of below example: { ## required "name": "api_service", "service": Service( ip_address="0.0.0.0", ports={ "metrics": PortSpec( number=8080 ) } ), "metrics_path": "/metrics", ## optional "labels": { "service_type": "api" }, "scrape_interval": "60s" } """ def start(plan, services): metrics_jobs = [] for service in services: constant_labels = {} # use no constant labels if none provided if "labels" in service: constant_labels = service["labels"] scrape_interval = prometheus.DEFAULT_SCRAPE_INTERVAL # use 5s as default scrape interval if "scrape_interval" in service: scrape_interval = service["scrape_interval"] metrics_job = { "Name": "{0}".format(service["name"]), "Endpoint": "{0}:{1}".format(service["service"].ip_address, service["service"].ports["metrics"].number), "Labels": constant_labels, "MetricsPath": service["metrics_path"], "ScrapeInterval": scrape_interval, } metrics_jobs.append(metrics_job) prometheus_url = prometheus.run(plan, metrics_jobs) plan.print(prometheus_url) return prometheus_url ================================================ FILE: kurtosis/src/observability/pyroscope/pyroscope.star ================================================ """ A package to install pyroscope: """ def run(plan, name = "pyroscope"): plan.add_service(name = name, config = ServiceConfig( image = "grafana/pyroscope:latest", ports = { "pyroscope": PortSpec( number = 4040, transport_protocol = "TCP", application_protocol = "http", ), }, )) ================================================ FILE: kurtosis/src/services/blockscout/launcher.star ================================================ shared_utils = import_module("github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star") postgres = import_module("github.com/kurtosis-tech/postgres-package/main.star") IMAGE_NAME_BLOCKSCOUT = "blockscout/blockscout:6.6.0" IMAGE_NAME_BLOCKSCOUT_VERIF = "ghcr.io/blockscout/smart-contract-verifier:v1.10.0" SERVICE_NAME_BLOCKSCOUT = "blockscout" HTTP_PORT_ID = "http" HTTP_PORT_NUMBER = 4000 HTTP_PORT_NUMBER_VERIF = 8050 BLOCKSCOUT_MIN_CPU = 100 BLOCKSCOUT_MAX_CPU = 1000 BLOCKSCOUT_MIN_MEMORY = 1024 BLOCKSCOUT_MAX_MEMORY = 2048 BLOCKSCOUT_VERIF_MIN_CPU = 10 BLOCKSCOUT_VERIF_MAX_CPU = 1000 BLOCKSCOUT_VERIF_MIN_MEMORY = 10 BLOCKSCOUT_VERIF_MAX_MEMORY = 1024 USED_PORTS = { HTTP_PORT_ID: shared_utils.new_port_spec( HTTP_PORT_NUMBER, shared_utils.TCP_PROTOCOL, shared_utils.HTTP_APPLICATION_PROTOCOL, ), } VERIF_USED_PORTS = { HTTP_PORT_ID: shared_utils.new_port_spec( HTTP_PORT_NUMBER_VERIF, shared_utils.TCP_PROTOCOL, shared_utils.HTTP_APPLICATION_PROTOCOL, ), } def launch_blockscout( plan, full_node_el_clients, client_from_user, persistent, verifier_image = None): postgres_output = postgres.run( plan, service_name = "{}-postgres".format(SERVICE_NAME_BLOCKSCOUT), database = "blockscout", extra_configs = ["max_connections=1000"], persistent = persistent, ) el_client_info = {} # Get the full_node_el_clients that match the client_from_user for full_node_el_client_name, full_node_el_client_service in full_node_el_clients.items(): if full_node_el_client_name in client_from_user: rpc_port = full_node_el_client_service.ports["eth-json-rpc"].number name = full_node_el_client_name ip_address = full_node_el_client_service.ip_address el_client_info = get_el_client_info( ip_address, rpc_port, name, ) break config_verif = get_config_verif(verifier_image) verif_service_name = "{}-verif".format(SERVICE_NAME_BLOCKSCOUT) verif_service = plan.add_service(verif_service_name, config_verif) verif_url = "http://{}:{}/api".format( verif_service.hostname, verif_service.ports["http"].number, ) config_backend = get_config_backend( postgres_output, el_client_info.get("RPC_Url"), verif_url, el_client_info.get("Eth_Type"), ) blockscout_service = plan.add_service(SERVICE_NAME_BLOCKSCOUT, config_backend) plan.print(blockscout_service) blockscout_url = "http://{}:{}".format( blockscout_service.hostname, blockscout_service.ports["http"].number, ) return blockscout_url def get_config_verif(verifier_image = None): return ServiceConfig( image = verifier_image or IMAGE_NAME_BLOCKSCOUT_VERIF, ports = VERIF_USED_PORTS, env_vars = { "SMART_CONTRACT_VERIFIER__SERVER__HTTP__ADDR": "0.0.0.0:{}".format( HTTP_PORT_NUMBER_VERIF, ), }, min_cpu = BLOCKSCOUT_VERIF_MIN_CPU, max_cpu = BLOCKSCOUT_VERIF_MAX_CPU, min_memory = BLOCKSCOUT_VERIF_MIN_MEMORY, max_memory = BLOCKSCOUT_VERIF_MAX_MEMORY, ) def get_config_backend( postgres_output, el_client_rpc_url, verif_url, el_client_name): database_url = "{protocol}://{user}:{password}@{hostname}:{port}/{database}".format( protocol = "postgresql", user = postgres_output.user, password = postgres_output.password, hostname = postgres_output.service.hostname, port = postgres_output.port.number, database = postgres_output.database, ) return ServiceConfig( image = IMAGE_NAME_BLOCKSCOUT, ports = USED_PORTS, cmd = [ "/bin/sh", "-c", 'bin/blockscout eval "Elixir.Explorer.ReleaseTasks.create_and_migrate()" && bin/blockscout start', ], env_vars = { "ETHEREUM_JSONRPC_VARIANT": el_client_name, "ETHEREUM_JSONRPC_HTTP_URL": el_client_rpc_url, "ETHEREUM_JSONRPC_TRACE_URL": el_client_rpc_url, "DATABASE_URL": database_url, "COIN": "ETH", "MICROSERVICE_SC_VERIFIER_ENABLED": "true", "MICROSERVICE_SC_VERIFIER_URL": verif_url, "MICROSERVICE_SC_VERIFIER_TYPE": "sc_verifier", "INDEXER_DISABLE_PENDING_TRANSACTIONS_FETCHER": "true", "ECTO_USE_SSL": "false", "NETWORK": "Kurtosis", "SUBNETWORK": "Kurtosis", "API_V2_ENABLED": "true", "PORT": "{}".format(HTTP_PORT_NUMBER), "SECRET_KEY_BASE": "56NtB48ear7+wMSf0IQuWDAAazhpb31qyc7GiyspBP2vh7t5zlCsF5QDv76chXeN", }, min_cpu = BLOCKSCOUT_MIN_CPU, max_cpu = BLOCKSCOUT_MAX_CPU, min_memory = BLOCKSCOUT_MIN_MEMORY, max_memory = BLOCKSCOUT_MAX_MEMORY, ) BLOCKSCOUT_JSONRPC_VARIANT = { "reth": "geth", } def get_el_client_info(ip_addr, rpc_port_num, full_name): el_client_rpc_url = "http://{}:{}/".format( ip_addr, rpc_port_num, ) el_client_type = full_name.split("-")[2] return { "RPC_Url": el_client_rpc_url, "Eth_Type": BLOCKSCOUT_JSONRPC_VARIANT.get(el_client_type, el_client_type), } ================================================ FILE: kurtosis/src/services/service.star ================================================ def parse_service_from_dict(service): if "replicas" not in service: service["replicas"] = 1 if "client" not in service: service["client"] = None if "verifier_image" not in service: service["verifier_image"] = None return struct( name = service["name"], replicas = service["replicas"], client = service["client"], verifier_image = service["verifier_image"], ) ================================================ FILE: kurtosis/src/services/spamoor/launcher.star ================================================ SERVICE_NAME = "spamoor" IMAGE_NAME = "ethpandaops/spamoor:latest" ENTRYPOINT_ARGS = ["/bin/sh", "-c"] # The min/max CPU/memory that spamoor can use MIN_CPU = 100 MAX_CPU = 500 MIN_MEMORY = 20 MAX_MEMORY = 300 def launch_spamoor(plan, funding_account, rpc_endpoint): config = get_config(funding_account, rpc_endpoint) plan.add_service(SERVICE_NAME, config) plan.print(config) def get_config(funding_account, rpc_endpoint): blob_cmd = "./spamoor blob-combined -p {0} -b 6 -t 3 --max-pending 9 -h {1}".format( funding_account.private_key, rpc_endpoint, ) return ServiceConfig( image = IMAGE_NAME, entrypoint = ENTRYPOINT_ARGS, cmd = [blob_cmd], min_cpu = MIN_CPU, max_cpu = MAX_CPU, min_memory = MIN_MEMORY, max_memory = MAX_MEMORY, ) ================================================ FILE: kurtosis/src/services/tx_fuzz/launcher.star ================================================ shared_utils = import_module("github.com/ethpandaops/ethereum-package/src/shared_utils/shared_utils.star") constants = import_module("../../constants.star") execution = import_module("../../nodes/execution/execution.star") SERVICE_NAME = "tx-fuzz" # The min/max CPU/memory that tx-spammer can use MIN_CPU = 100 MAX_CPU = 2000 MIN_MEMORY = 128 MAX_MEMORY = 1024 def launch_tx_fuzzes(plan, amount, next_free_prefunded_account, full_node_el_client_configs, full_node_el_clients, tx_spammer_extra_args): tx_fuzz_service_configs = {} for i in range(amount): full_node_service_name = full_node_el_client_configs[i % len(full_node_el_client_configs)]["name"] fuzzing_node = full_node_el_clients[full_node_service_name] tx_fuzz_config = get_config( constants.PRE_FUNDED_ACCOUNTS[next_free_prefunded_account].private_key, "http://{}:{}".format(fuzzing_node.ip_address, execution.RPC_PORT_NUM), tx_spammer_extra_args, ) tx_fuzz_service_configs[SERVICE_NAME + "-" + str(i)] = tx_fuzz_config next_free_prefunded_account += 1 plan.add_services(tx_fuzz_service_configs) return next_free_prefunded_account def launch_tx_fuzz( plan, id, prefunded_private_key, el_uri, tx_spammer_extra_args): config = get_config( prefunded_private_key, el_uri, tx_spammer_extra_args, ) plan.add_service( SERVICE_NAME + "-" + str(id), config, ) def get_config( prefunded_private_key, el_uri, tx_spammer_extra_args): tx_spammer_image = "ethpandaops/tx-fuzz:master" entrypoint = [ "/bin/sh", "-c", ] # A sleep is added to ensure the full node is up in single-node deployments cmd = " ".join([ "sleep", "5", "&&", "/tx-fuzz.bin", "spam", "--rpc={}".format(el_uri), "--sk={0}".format(prefunded_private_key), "--accounts=100", "--txcount=100", "--slot-time=2", ]) if len(tx_spammer_extra_args) > 0: cmd.extend([param for param in tx_spammer_extra_args]) return ServiceConfig( image = tx_spammer_image, cmd = [cmd], entrypoint = entrypoint, min_cpu = MIN_CPU, max_cpu = MAX_CPU, min_memory = MIN_MEMORY, max_memory = MAX_MEMORY, ) ================================================ FILE: log/mod.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package log // Logger represents a basic logger that is extremely similar to the Cosmos-SDK // Logger interface. type Logger interface { // Info takes a message and a set of key/value pairs and logs with level // INFO. // The key of the tuple must be a string. Info(msg string, keyVals ...any) // Warn takes a message and a set of key/value pairs and logs with level // WARN. // The key of the tuple must be a string. Warn(msg string, keyVals ...any) // Error takes a message and a set of key/value pairs and logs with level // ERR. // The key of the tuple must be a string. Error(msg string, keyVals ...any) // Debug takes a message and a set of key/value pairs and logs with level // DEBUG. // The key of the tuple must be a string. Debug(msg string, keyVals ...any) } // ConfigurableLogger extends the basic logger with the ability to configure // the logger with a config. type ConfigurableLogger[LoggerT, ConfigT any] interface { Configurable[LoggerT, ConfigT] Logger } type Configurable[LoggerT, ConfigT any] interface { WithConfig(config ConfigT) LoggerT } // ColorLogger extends the basic logger with the ability to configure the // logger with key and key value colors. type Colorable interface { // AddKeyColor sets the log color for a key. AddKeyColor(key any, color Color) // AddKeyValColor sets the log color for a key and its value. AddKeyValColor(key any, val any, color Color) } // AdvancedLogger extends the color logger with the ability to wrap the logger // with additional context and to access the underlying logger implementation. type AdvancedLogger[LoggerT any] interface { Logger Colorable // With returns a new wrapped logger with additional context provided by a // set. With(keyVals ...any) LoggerT } // Color is a string that holds the hex color code for the color. type Color string // Raw returns the raw color code. func (c Color) Raw() string { return string(c) } const ( // colours. Reset Color = "\x1b[0m" Black Color = "\x1b[30m" Red Color = "\x1b[31m" Green Color = "\x1b[32m" Yellow Color = "\x1b[33m" Blue Color = "\x1b[34m" Magenta Color = "\x1b[35m" Cyan Color = "\x1b[36m" White Color = "\x1b[37m" Gray Color = "\x1b[90m" BrightRed Color = "\x1b[91m" BrightGreen Color = "\x1b[92m" BrightYellow Color = "\x1b[93m" BrightBlue Color = "\x1b[94m" BrightMagenta Color = "\x1b[95m" BrightCyan Color = "\x1b[96m" BrightWhite Color = "\x1b[97m" BrightBackgroundWhite Color = "\x1b[107m" BrightBackgroundBlue Color = "\x1b[104m" ) ================================================ FILE: log/noop/noop.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package noop import "github.com/berachain/beacon-kit/log" // Logger is a logger that performs no operations. It can be used in // environments where logging should be disabled. It implements the Logger // interface with no-op methods. type Logger[ImplT any] struct{} // NewLogger creates a blank no-op AdvancedLogger. func NewLogger[ImplT any]() *Logger[ImplT] { return &Logger[ImplT]{} } // Info logs an informational message with associated key-value pairs. This // method does nothing. func (n *Logger[ImplT]) Info(string, ...any) { // No operation } // Warn logs a warning message with associated key-value pairs. This method does // nothing. func (n *Logger[ImplT]) Warn(string, ...any) { // No operation } // Error logs an error message with associated key-value pairs. This method does // nothing. func (n *Logger[ImplT]) Error(string, ...any) { // No operation } // Debug logs a debug message with associated key-value pairs. This method does // nothing. func (n *Logger[ImplT]) Debug(string, ...any) { // No operation } // With returns a new AdvancedLogger with the provided key-value pairs. This // method does nothing. func (n *Logger[ImplT]) With(...any) ImplT { //nolint:errcheck // should be safe return any(n).(ImplT) } func (n *Logger[ImplT]) Impl() any { return nil } func (n *Logger[ImplT]) AddKeyColor(any, log.Color) { // No operation } func (n *Logger[ImplT]) AddKeyValColor(any, any, log.Color) { // No operation } ================================================ FILE: log/noop/noop_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package noop_test import ( "testing" "github.com/berachain/beacon-kit/log/noop" ) func TestNewLogger(t *testing.T) { t.Parallel() logger := noop.NewLogger[any]() if logger == nil { t.Error("Expected NewLogger to return a non-nil logger") } } func TestLogger_Info(t *testing.T) { t.Parallel() logger := noop.NewLogger[any]() logger.Info("test message", "key1", "value1", "key2", "value2") // Since it's a no-op logger, there's nothing to assert. This test just // ensures no panic occurs. } func TestLogger_Warn(t *testing.T) { t.Parallel() logger := noop.NewLogger[any]() logger.Warn("test warning", "key1", "value1", "key2", "value2") // Since it's a no-op logger, there's nothing to assert. This test just // ensures no panic occurs. } func TestLogger_Error(t *testing.T) { t.Parallel() logger := noop.NewLogger[any]() logger.Error("test error", "key1", "value1", "key2", "value2") // Since it's a no-op logger, there's nothing to assert. This test just // ensures no panic occurs. } func TestLogger_Debug(t *testing.T) { t.Parallel() logger := noop.NewLogger[any]() logger.Debug("test debug", "key1", "value1", "key2", "value2") // Since it's a no-op logger, there's nothing to assert. This test just // ensures no panic occurs. } ================================================ FILE: log/phuslu/buffer.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package phuslu import "sync" // byteBuffer is a byte buffer. type byteBuffer struct { Bytes []byte } // byteBufferPool is a pool of byte buffers. // //nolint:gochecknoglobals // buffer pool var byteBufferPool = sync.Pool{ New: func() any { return &byteBuffer{ Bytes: make([]byte, 0), } }, } // Reset resets the byte buffer. func (b *byteBuffer) Reset() { b.Bytes = b.Bytes[:0] } ================================================ FILE: log/phuslu/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package phuslu // Config is a structure that defines the configuration for the logger. type Config struct { // TimeFormat is a string that defines the format of the time in // the logger. TimeFormat string `mapstructure:"time-format"` // Logger will log messages with verbosity up to LogLevel. LogLevel string `mapstructure:"log-level"` // pretty or json. Style string `mapstructure:"style"` } // DefaultConfig is a function that returns a new Config with default values. func DefaultConfig() Config { return Config{ TimeFormat: "RFC3339", LogLevel: "info", Style: StylePretty, } } ================================================ FILE: log/phuslu/formatter.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIred BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package phuslu import ( "io" "github.com/phuslu/log" ) // Formatter is a custom formatter for log messages. type Formatter struct { // KeyColors applies specific colors to log entries based on their keys. keyColors map[string]Color // KeyValColors applies specific colors to log entries based on their keys // and values. keyValColors map[string]Color } // NewFormatter creates a new Formatter with default settings. func NewFormatter() *Formatter { return &Formatter{ keyColors: make(map[string]Color), keyValColors: make(map[string]Color), } } // Format formats the log message. func (f *Formatter) Format( out io.Writer, args *log.FormatterArgs, ) (int, error) { buffer, ok := byteBufferPool.Get().(*byteBuffer) if !ok { panic("failed to get byte buffer from pool") } buffer.Reset() defer byteBufferPool.Put(buffer) var color, label string switch args.Level { case "trace": color, label = traceColor.Raw(), traceLabel case "debug": color, label = debugColor.Raw(), debugLabel case "info": color, label = infoColor.Raw(), infoLabel case "warn": color, label = warnColor.Raw(), warnLabel case "error": color, label = errorColor.Raw(), errorLabel case "fatal": color, label = fatalColor.Raw(), fatalLabel case "panic": color, label = panicColor.Raw(), panicLabel default: color, label = defaultColor.Raw(), defaultLabel } f.printWithColor(args, buffer, color, label) f.ensureLineBreak(buffer) if args.Stack != "" { buffer.Bytes = append(buffer.Bytes, args.Stack...) if args.Stack[len(args.Stack)-1] != '\n' { buffer.Bytes = append(buffer.Bytes, '\n') } } return out.Write(buffer.Bytes) } // AddKeyColor adds a key and color to the keyColors map. func (f *Formatter) AddKeyColor(key string, color Color) { f.keyColors[key] = color } // AddKeyValColor adds a key and color to the keyValColors map. func (f *Formatter) AddKeyValColor(key string, val string, color Color) { f.keyValColors[key+val] = color } // printWithColor prints the log message with color. func (f *Formatter) printWithColor( args *log.FormatterArgs, b *byteBuffer, color, label string, ) { var ( ok bool kvColor Color kColor Color ) f.formatHeader(args, b, color, label) b.Bytes = append(b.Bytes, ' ') b.Bytes = append(b.Bytes, args.Message...) for _, kv := range args.KeyValues { b.Bytes = append(b.Bytes, ' ') // apply the key+value color if configured, otherwise apply key color if kvColor, ok = f.keyValColors[kv.Key+kv.Value]; ok { b.Bytes = append(b.Bytes, kvColor.Raw()...) } else if kColor, ok = f.keyColors[kv.Key]; ok { b.Bytes = append(b.Bytes, kColor.Raw()...) } b.Bytes = append(b.Bytes, kv.Key...) b.Bytes = append(b.Bytes, '=') b.Bytes = append(b.Bytes, kv.Value...) b.Bytes = append(b.Bytes, reset...) } } // formatHeader formats the header of the log message. func (f *Formatter) formatHeader( args *log.FormatterArgs, b *byteBuffer, color, label string, ) { b.Bytes = append(b.Bytes, gray...) b.Bytes = append(b.Bytes, args.Time...) b.Bytes = append(b.Bytes, ' ') b.Bytes = append(b.Bytes, color...) b.Bytes = append(b.Bytes, label...) if args.Caller != "" { b.Bytes = append(b.Bytes, args.Goid...) b.Bytes = append(b.Bytes, ' ') b.Bytes = append(b.Bytes, args.Caller...) b.Bytes = append(b.Bytes, ' ') } b.Bytes = append(b.Bytes, reset...) } // ensureLineBreak ensures the log message ends with a line break. func (f *Formatter) ensureLineBreak(b *byteBuffer) { if b.Bytes == nil { b.Bytes = make([]byte, 0) } length := len(b.Bytes) if length == 0 || b.Bytes[length-1] != '\n' { b.Bytes = append(b.Bytes, '\n') } } ================================================ FILE: log/phuslu/logger.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package phuslu import ( "io" "github.com/phuslu/log" ) // Logger is a wrapper around phuslogger. type Logger struct { // logger is the underlying logger implementation. logger *log.Logger // context is a map of key-value pairs that are added to every log entry. context log.Fields // out is the writer to write logs to. out io.Writer // formatter is the formatter to use for the logger. formatter *Formatter } // NewLogger initializes a new wrapped phuslogger with the provided config. func NewLogger( out io.Writer, cfg *Config, ) *Logger { logger := &Logger{ logger: &log.Logger{}, context: make(log.Fields), out: out, formatter: NewFormatter(), } logger.WithConfig(cfg) return logger } // Info logs a message at level Info. func (l *Logger) Info(msg string, keyVals ...any) { if l.logger.Level > log.InfoLevel { return } l.msgWithContext(msg, l.logger.Info(), keyVals...) } // Warn logs a message at level Warn. func (l *Logger) Warn(msg string, keyVals ...any) { if l.logger.Level > log.WarnLevel { return } l.msgWithContext(msg, l.logger.Warn(), keyVals...) } // Error logs a message at level Error. func (l *Logger) Error(msg string, keyVals ...any) { if l.logger.Level > log.ErrorLevel { return } l.msgWithContext(msg, l.logger.Error(), keyVals...) } // Debug logs a message at level Debug. func (l *Logger) Debug(msg string, keyVals ...any) { if l.logger.Level > log.DebugLevel { return } l.msgWithContext(msg, l.logger.Debug(), keyVals...) } // Impl returns the underlying logger implementation. func (l *Logger) Impl() any { return l.logger } // With returns a new wrapped logger with additional context provided by a set. func (l Logger) With(keyVals ...any) *Logger { newLogger := l // Perform a deep copy of the map with preallocated size. newLogger.context = make(log.Fields, len(l.context)+len(keyVals)/2) for k, v := range l.context { newLogger.context[k] = v } // Add the new context to the existing context. for i := 0; i < len(keyVals); i += 2 { key, ok := keyVals[i].(string) if !ok { continue } newLogger.context[key] = keyVals[i+1] } return &newLogger } // Writer returns the io.Writer of the logger. func (l *Logger) Writer() io.Writer { return l.out } // msgWithContext logs a message with keyVals and current context. func (l *Logger) msgWithContext( msg string, e *log.Entry, keyVals ...any, ) { e.Fields(l.context).KeysAndValues(keyVals...).Msg(msg) } /* -------------------------------------------------------------------------- */ /* config */ /* -------------------------------------------------------------------------- */ // Temporary workaround to allow dynamic configuration post-logger creation. // This is necessary due to dependencies on runtime-populated configurations. func (l *Logger) WithConfig(cfg *Config) *Logger { // Use default config if nil. if cfg == nil { c := DefaultConfig() cfg = &c } l.withTimeFormat(cfg.TimeFormat) l.withStyle(cfg.Style) l.withLogLevel(cfg.LogLevel) return l } // AddKeyColor applies a color to log entries based on their keys. func (l *Logger) AddKeyColor(key any, color Color) { //nolint:errcheck // should be safe l.formatter.AddKeyColor(key.(string), color) } // AddKeyValColor applies specific colors to log entries based on their keys and // values. func (l *Logger) AddKeyValColor(key any, val any, color Color) { //nolint:errcheck // should be safe l.formatter.AddKeyValColor(key.(string), val.(string), color) } // sets the style of the logger. func (l *Logger) withStyle(style string) { if style == StylePretty { l.useConsoleWriter() } else if style == StyleJSON { l.useJSONWriter() } } // SetLevel sets the log level of the logger. func (l *Logger) withLogLevel(level string) { l.logger.Level = log.ParseLevel(level) } // useConsoleWriter sets the logger to use a console writer. func (l *Logger) useConsoleWriter() { l.setWriter(&log.ConsoleWriter{ Writer: l.out, Formatter: l.formatter.Format, }) } // useJSONWriter sets the logger to use a IOWriter wrapper. func (l *Logger) useJSONWriter() { l.setWriter(log.IOWriter{Writer: l.out}) } // setWriter sets the writer of the logger. func (l *Logger) setWriter(writer log.Writer) { l.logger.Writer = writer } ================================================ FILE: log/phuslu/style.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package phuslu import "github.com/berachain/beacon-kit/log" type Color = log.Color const ( reset = log.Reset black = log.Black red = log.Red green = log.Green yellow = log.Yellow blue = log.Blue magenta = log.Magenta cyan = log.Cyan white = log.White gray = log.Gray lightWhite = log.BrightWhite brightBackgroundWhite = log.BrightBackgroundWhite // log levels. traceColor = magenta debugColor = yellow infoColor = green warnColor = yellow errorColor = red fatalColor = red panicColor = red defaultColor = gray apiColor = blue traceLabel = "TRCE" debugLabel = "DBUG" infoLabel = "INFO" warnLabel = "WARN" errorLabel = "ERRR" fatalLabel = "FATAL" panicLabel = "PANIC" defaultLabel = "???" apiLabel = "API" // output styles flags. StylePretty = "pretty" StyleJSON = "json" ) ================================================ FILE: log/phuslu/time.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package phuslu import ( "time" ) const ( // time formats. rfc3339 = "RFC3339" rfc3339Nano = "RFC3339Nano" rfc1123 = "RFC1123" rfc1123Z = "RFC1123Z" kitchen = "Kitchen" layout = "Layout" ansic = "ANSIC" unixDate = "UnixDate" rubyDate = "RubyDate" timeOnly = "TimeOnly" dateOnly = "DateOnly" ) // withTimeFormat sets the time format for the logger. func (l *Logger) withTimeFormat(formatStr string) { l.logger.TimeFormat = parseFormat(formatStr) } // parseFormat parses the time format string. func parseFormat(formatStr string) string { switch formatStr { case rfc3339: return time.RFC3339 case rfc3339Nano: return time.RFC3339Nano case rfc1123: return time.RFC1123 case rfc1123Z: return time.RFC1123Z case kitchen: return time.Kitchen case layout: return time.Layout case ansic: return time.ANSIC case unixDate: return time.UnixDate case rubyDate: return time.RubyDate case timeOnly: return time.TimeOnly case dateOnly: return time.DateOnly default: return time.RFC3339 } } ================================================ FILE: node-api/backend/backend.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package backend import ( "context" "encoding/json" "errors" "fmt" "sync" corestore "cosmossdk.io/core/store" "cosmossdk.io/log" "cosmossdk.io/store" sdkmetrics "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" "github.com/berachain/beacon-kit/chain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/node-core/components/storage" "github.com/berachain/beacon-kit/node-core/types" "github.com/berachain/beacon-kit/state-transition/core/state" kvstorage "github.com/berachain/beacon-kit/storage" "github.com/berachain/beacon-kit/storage/beacondb" "github.com/berachain/beacon-kit/storage/db" cmtcfg "github.com/cometbft/cometbft/config" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" ) // Backend is the db access layer for the beacon node-api. // It serves as a wrapper around the storage backend and provides an abstraction // over building the query context for a given state. type Backend struct { sb *storage.Backend cs chain.Spec cmtCfg *cmtcfg.Config // used to fetch genesis data upon LoadData node types.ConsensusService // Genesis related data sp GenesisStateProcessor // only needed to recreate genesis state upon API loading db dbm.DB // in-memory DB to store genesis state muSt sync.RWMutex // mutex to allow initializing and copying genesisState in a safe way cms storetypes.CommitMultiStore genesisState *state.StateDB // caches genesis data to serve API requests } // New creates and returns a new Backend instance. func New( storageBackend *storage.Backend, sp GenesisStateProcessor, cs chain.Spec, cmtCfg *cmtcfg.Config, consensusService types.ConsensusService, ) *Backend { b := &Backend{ sb: storageBackend, sp: sp, cs: cs, cmtCfg: cmtCfg, node: consensusService, } // genesis data will be cached in LoadData return b } func (b *Backend) LoadData(_ context.Context) error { switch err := b.node.IsAppReady(); { case err == nil: // chain finally ready, time to loading genesis //nolint:contextcheck // loadGenesisState creates its own context for in-memory store return b.loadGenesisState() case errors.Is(err, cometbft.ErrAppNotReady): // start anyhow, we'll init genesis state later on return nil default: return fmt.Errorf("unable to check whether app is ready: %w", err) } } func (b *Backend) Close() error { if b.db == nil { return nil } return b.db.Close() } type backendKVStoreService struct { ctx sdk.Context } func (kvs *backendKVStoreService) OpenKVStore(context.Context) corestore.KVStore { //nolint:contextcheck // fine with this node-api backend store := sdk.UnwrapSDKContext(kvs.ctx).KVStore(backendStoreKey) return kvstorage.NewKVStore(store) } //nolint:gochecknoglobals // fine with this node-api backend var backendStoreKey = storetypes.NewKVStoreKey("backend-genesis") func (b *Backend) loadGenesisState() error { b.muSt.Lock() defer b.muSt.Unlock() if b.genesisState != nil { // genesis state already initialized, we're fine return nil } // 1- Load Genesis bytes genesisData, err := b.parseGenesisBytes() if err != nil { return err } // 2- Create Genesis Store if err = b.initGenesisState(); err != nil { return fmt.Errorf("backend data loading:%w", err) } // 3- Reprocess Genesis via state Processor. This is safe // since it's done on its own state AND state processor does not // make any call to the EVM during genesis processing. // Note: we process genesis here as soon as node start, but // chain would wait for genesisTime to come if genesisTime // is set in the future. We replicate this behaviour with checkChainIsReady. if _, err = b.sp.InitializeBeaconStateFromEth1( b.genesisState, genesisData.GetDeposits(), genesisData.GetExecutionPayloadHeader(), genesisData.GetForkVersion(), ); err != nil { return fmt.Errorf("failed processing genesis: %w", err) } _ = b.cms.Commit() // not really necessary for in-memoryDB. Still. return nil } func (b *Backend) parseGenesisBytes() (ctypes.Genesis, error) { appGenesis, err := genutiltypes.AppGenesisFromFile(b.cmtCfg.GenesisFile()) if err != nil { return ctypes.Genesis{}, fmt.Errorf("failed loading app genesis from file: %w", err) } gen, err := appGenesis.ToGenesisDoc() if err != nil { return ctypes.Genesis{}, fmt.Errorf("failed parsing app genesis: %w", err) } var genesisState map[string]json.RawMessage if err = json.Unmarshal(gen.AppState, &genesisState); err != nil { return ctypes.Genesis{}, fmt.Errorf("failed to unmarshal genesis state: %w", err) } data := []byte(genesisState["beacon"]) genesisData := ctypes.Genesis{} if err = json.Unmarshal(data, &genesisData); err != nil { return ctypes.Genesis{}, fmt.Errorf("failed to unmarshal genesis data: %w", err) } return genesisData, nil } func (b *Backend) initGenesisState() error { var err error b.db, err = db.OpenDB("", dbm.MemDBBackend) if err != nil { return fmt.Errorf("failed opening mem db: %w", err) } var ( nopLog = log.NewNopLogger() nopMetrics = sdkmetrics.NewNoOpMetrics() ) b.cms = store.NewCommitMultiStore(b.db, nopLog, nopMetrics) b.cms.MountStoreWithDB(backendStoreKey, storetypes.StoreTypeIAVL, nil) if err = b.cms.LoadLatestVersion(); err != nil { return fmt.Errorf("backend data loading: failed to load latest version: %w", err) } ctx := sdk.NewContext(b.cms, true, nopLog) backendStoreService := &backendKVStoreService{ ctx: ctx, } kvStore := beacondb.New(backendStoreService) sdkCtx := sdk.NewContext(b.cms.CacheMultiStore(), true, log.NewNopLogger()) b.genesisState = state.NewBeaconStateFromDB( kvStore.WithContext(sdkCtx), b.cs, sdkCtx.Logger(), metrics.NewNoOpTelemetrySink(), ) return nil } ================================================ FILE: node-api/backend/backend_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package backend_test import ( "errors" "os" "path/filepath" "testing" "cosmossdk.io/log" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/node-api/backend" "github.com/berachain/beacon-kit/node-api/backend/mocks" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/node-core/components/storage" coremocks "github.com/berachain/beacon-kit/node-core/types/mocks" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/state-transition/core/state" statetransition "github.com/berachain/beacon-kit/testing/state-transition" cmtcfg "github.com/cometbft/cometbft/config" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestBackendLoadData(t *testing.T) { t.Parallel() // some genesis data, to check they match with what it's in the state that backend returns var ( expectedGenesisPayload *types.ExecutionPayloadHeader expectedGenesisFork *types.Fork ) testCases := []struct { name string setMockExpectations func( *coremocks.ConsensusService, *mocks.GenesisStateProcessor, ) check func(t *testing.T, b *backend.Backend, errLoad error) }{ { name: "success", setMockExpectations: func( cs *coremocks.ConsensusService, sp *mocks.GenesisStateProcessor, ) { t.Helper() cs.EXPECT().IsAppReady().Return(nil) // mark the app as ready sp.EXPECT().InitializeBeaconStateFromEth1( mock.Anything, mock.Anything, mock.Anything, mock.Anything, ).Run(func( st *state.StateDB, _ types.Deposits, execPayloadHeader *types.ExecutionPayloadHeader, genesisVersion common.Version, ) { expectedGenesisPayload = execPayloadHeader expectedGenesisFork = &types.Fork{ PreviousVersion: genesisVersion, CurrentVersion: genesisVersion, } require.NoError(t, st.SetLatestExecutionPayloadHeader(execPayloadHeader)) require.NoError(t, st.SetFork(expectedGenesisFork)) }).Return(nil, nil) // duly process genesis once parsed }, check: func(t *testing.T, b *backend.Backend, errLoad error) { t.Helper() require.NoError(t, errLoad) // Load genesis state and show (at least some) data matches genState, genSlot, err := b.StateAndSlotFromHeight(0) // check genesis state is provided require.NoError(t, err) require.Equal(t, math.Slot(0), genSlot) gotGenesisPayload, err := genState.GetLatestExecutionPayloadHeader() require.NoError(t, err) require.Equal(t, expectedGenesisPayload, gotGenesisPayload) gotGenesisFork, err := genState.GetFork() require.NoError(t, err) require.Equal(t, expectedGenesisFork, gotGenesisFork) }, }, { name: "app not ready", setMockExpectations: func( cs *coremocks.ConsensusService, _ *mocks.GenesisStateProcessor, ) { t.Helper() cs.EXPECT().IsAppReady().Return(cometbft.ErrAppNotReady) // mark the app as not ready }, check: func(t *testing.T, b *backend.Backend, errLoad error) { t.Helper() // just keep going, it will load later on, as soon as possible require.NoError(t, errLoad) _, _, err := b.StateAndSlotFromHeight(0) // check genesis state is provided require.ErrorIs(t, err, cometbft.ErrAppNotReady) }, }, { name: "could not check app is ready", setMockExpectations: func( cs *coremocks.ConsensusService, _ *mocks.GenesisStateProcessor, ) { t.Helper() cs.EXPECT().IsAppReady().Return(errors.New("unknown error")) }, check: func(t *testing.T, _ *backend.Backend, errLoad error) { t.Helper() require.Error(t, errLoad) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // 1 - Build backend cs, err := spec.MainnetChainSpec() require.NoError(t, err) cmtCfg := buildTestCometConfig(t) _, kvStore, depositStore, err := statetransition.BuildTestStores() require.NoError(t, err) sb := storage.NewBackend( cs, nil, kvStore, depositStore, nil, log.NewNopLogger(), metrics.NewNoOpTelemetrySink(), ) tcs := coremocks.NewConsensusService(t) sp := mocks.NewGenesisStateProcessor(t) b := backend.New(sb, sp, cs, cmtCfg, tcs) defer func() { require.NoError(t, b.Close()) }() // 2- Setup expectations tc.setMockExpectations(tcs, sp) // 3 - Test errLoad := b.LoadData(t.Context()) // 4- Checks tc.check(t, b, errLoad) }) } } //nolint:lll // adapted genesis from mainnet func buildTestCometConfig(t *testing.T) *cmtcfg.Config { t.Helper() // Create a temporary directory for CometBFT config tmpDir := t.TempDir() cmtCfg := cmtcfg.DefaultConfig() cmtCfg.SetRoot(tmpDir) // Create config directory configDir := filepath.Join(tmpDir, "config") err := os.MkdirAll(configDir, 0o755) require.NoError(t, err) // Create app genesis with version of Deneb 0x04000000. appGenesis := genutiltypes.NewAppGenesisWithVersion("test-chain", []byte(` { "beacon": { "fork_version": "0x04000000", "deposits": [], "execution_payload_header": { "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000", "stateRoot": "0x2aace2f233f1ef6ca13e5fd8feae4cb1b0b580fa56c8ee081ab89d861eaf1515", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x0", "gasLimit": "0x1c9c380", "gasUsed": "0x0", "timestamp": "0x678e56e0", "extraData": "0x", "baseFeePerGas": "1000000000", "blockHash": "0xd57819422128da1c44339fc7956662378c17e2213e669b427ac91cd11dfcfb38", "transactionsRoot": "0x7ffe241ea60187fdb0187bfa22de35d1f9bed7ab061d9401fd47e34a54fbede1", "withdrawalsRoot": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", "blobGasUsed": "0x0", "excessBlobGas": "0x0" } } } `)) // Save genesis file to the config directory genesisFile := filepath.Join(configDir, "genesis.json") err = appGenesis.SaveAs(genesisFile) require.NoError(t, err) return cmtCfg } ================================================ FILE: node-api/backend/getters.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package backend import ( "errors" "fmt" "runtime" "cosmossdk.io/log" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" cmttypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" ) // StateAndSlotFromHeight returns the beacon state at a particular slot using query context, // resolving an input height of -1 to the latest slot. // // This returns the beacon state of the version that was committed to disk at the requested slot, // which has the empty state root in the latest block header. Hence, the most recent state and // block roots are not updated. func (b *Backend) StateAndSlotFromHeight(height int64) (ReadOnlyBeaconState, math.Slot, error) { if height < -1 { return nil, 0, fmt.Errorf("expected height, must be non-negative or -1 to request tip, got %d", height) } if height == 0 { switch err := b.node.IsAppReady(); { case err == nil: // chain finally ready, time to loading genesis if err = b.loadGenesisState(); err != nil { return nil, 0, fmt.Errorf("failed loading genesis state: %w", err) } case errors.Is(err, cometbft.ErrAppNotReady): return nil, 0, cometbft.ErrAppNotReady default: return nil, 0, fmt.Errorf("unable to check whether app is ready: %w", err) } b.muSt.Lock() defer b.muSt.Unlock() // Copy the state to ensure clients potential changes won't pollute the state // Also we make sure to create the copy in a thread-safe way via the muCms mutex. ms := b.cms.CacheMultiStore() ctx := sdk.NewContext(ms, true, log.NewNopLogger()) ephemeralGenesisState := b.genesisState.Protect(ctx) return ephemeralGenesisState, 0, nil } height = max(0, height) // CreateQueryContext uses 0 to pick latest height. queryCtx, err := b.node.CreateQueryContext(height, false) if err != nil { return nil, 0, fmt.Errorf("CreateQueryContext failed: %w", err) } st := b.sb.StateFromContext(queryCtx) var slot math.Slot if height > 0 { slot = math.Slot(height) } else { // height must be -1, so pick state slot slot, err = st.GetSlot() if err != nil { return st, slot, fmt.Errorf("GetSlot failed: %w", err) } } return st, slot, nil } // GetSlotByBlockRoot retrieves the slot by a block root from the block store. func (b *Backend) GetSlotByBlockRoot(root common.Root) (math.Slot, error) { return b.sb.BlockStore().GetSlotByBlockRoot(root) } // GetSlotByStateRoot retrieves the slot by a state root from the block store. func (b *Backend) GetSlotByStateRoot(root common.Root) (math.Slot, error) { return b.sb.BlockStore().GetSlotByStateRoot(root) } // GetParentSlotByTimestamp retrieves the parent slot by a given timestamp from // the block store. func (b *Backend) GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) { return b.sb.BlockStore().GetParentSlotByTimestamp(timestamp) } // GetSignatureBySlot retrieves the block signature for a given slot by decoding // the SignedBeaconBlock from CometBFT's blockstore. func (b *Backend) GetSignatureBySlot(slot math.Slot) (crypto.BLSSignature, error) { block := b.node.GetBlock(int64(slot.Unwrap())) //#nosec:G115 if block == nil { return crypto.BLSSignature{}, fmt.Errorf("block not found at slot %d", slot) } // Extract transactions from CometBFT block txs := make([][]byte, len(block.Data.Txs)) for i, tx := range block.Data.Txs { txs[i] = tx } forkVersion := b.cs.ActiveForkVersionForTimestamp(math.U64(block.Header.Time.Unix())) //#nosec:G115 signedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest(txs, 0, forkVersion) if err != nil { return crypto.BLSSignature{}, fmt.Errorf("failed to unmarshal block at slot %d: %w", slot, err) } return signedBlock.Signature, nil } func (b *Backend) GetBlobSidecarsAtSlot(slot math.Slot) (datypes.BlobSidecars, error) { return b.sb.AvailabilityStore().GetBlobSidecars(slot) } func (b *Backend) GetSyncData() (int64 /*latestHeight*/, int64 /*syncToHeight*/) { return b.node.GetSyncData() } func (b *Backend) GetVersionData() ( string, // appName string, // cometVersion string, // os string, // arch ) { cometVersionInfo := version.NewInfo() // same used in beacond version command var ( appName = cometVersionInfo.AppName cometVersion = cometVersionInfo.Version os = runtime.GOOS arch = runtime.GOARCH ) return appName, cometVersion, os, arch } // GetCometBFTBlock returns the CometBFT block at the given height. func (b *Backend) GetCometBFTBlock(height int64) *cmttypes.Block { return b.node.GetBlock(height) } // GetCometBFTSignedHeader returns the CometBFT signed header (header + commit) at the given height. func (b *Backend) GetCometBFTSignedHeader(height int64) *cmttypes.SignedHeader { return b.node.GetSignedHeader(height) } ================================================ FILE: node-api/backend/interface.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package backend import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" statedb "github.com/berachain/beacon-kit/state-transition/core/state" ) type GenesisStateProcessor interface { InitializeBeaconStateFromEth1( st *statedb.StateDB, deposits ctypes.Deposits, execPayloadHeader *ctypes.ExecutionPayloadHeader, genesisVersion common.Version, ) (transition.ValidatorUpdates, error) } // Keep just getters currently used. To be expanded as we increase API endpoints available type ReadOnlyBeaconState interface { GetGenesisValidatorsRoot() (common.Root, error) GetFork() (*ctypes.Fork, error) GetLatestExecutionPayloadHeader() (*ctypes.ExecutionPayloadHeader, error) GetLatestBlockHeader() (*ctypes.BeaconBlockHeader, error) HashTreeRoot() common.Root GetRandaoMixAtIndex(uint64) (common.Bytes32, error) GetBalances() ([]uint64, error) GetBalance(math.ValidatorIndex) (math.Gwei, error) ValidatorIndexByPubkey(crypto.BLSPubkey) (math.ValidatorIndex, error) GetValidators() (ctypes.Validators, error) ValidatorByIndex(math.ValidatorIndex) (*ctypes.Validator, error) GetPendingPartialWithdrawals() ([]*ctypes.PendingPartialWithdrawal, error) GetMarshallable() (*ctypes.BeaconState, error) } ================================================ FILE: node-api/backend/mocks/genesis_state_processor.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( types "github.com/berachain/beacon-kit/consensus-types/types" common "github.com/berachain/beacon-kit/primitives/common" transition "github.com/berachain/beacon-kit/primitives/transition" state "github.com/berachain/beacon-kit/state-transition/core/state" mock "github.com/stretchr/testify/mock" ) // GenesisStateProcessor is an autogenerated mock type for the GenesisStateProcessor type type GenesisStateProcessor struct { mock.Mock } type GenesisStateProcessor_Expecter struct { mock *mock.Mock } func (_m *GenesisStateProcessor) EXPECT() *GenesisStateProcessor_Expecter { return &GenesisStateProcessor_Expecter{mock: &_m.Mock} } // InitializeBeaconStateFromEth1 provides a mock function with given fields: st, deposits, execPayloadHeader, genesisVersion func (_m *GenesisStateProcessor) InitializeBeaconStateFromEth1(st *state.StateDB, deposits types.Deposits, execPayloadHeader *types.ExecutionPayloadHeader, genesisVersion common.Version) (transition.ValidatorUpdates, error) { ret := _m.Called(st, deposits, execPayloadHeader, genesisVersion) if len(ret) == 0 { panic("no return value specified for InitializeBeaconStateFromEth1") } var r0 transition.ValidatorUpdates var r1 error if rf, ok := ret.Get(0).(func(*state.StateDB, types.Deposits, *types.ExecutionPayloadHeader, common.Version) (transition.ValidatorUpdates, error)); ok { return rf(st, deposits, execPayloadHeader, genesisVersion) } if rf, ok := ret.Get(0).(func(*state.StateDB, types.Deposits, *types.ExecutionPayloadHeader, common.Version) transition.ValidatorUpdates); ok { r0 = rf(st, deposits, execPayloadHeader, genesisVersion) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(transition.ValidatorUpdates) } } if rf, ok := ret.Get(1).(func(*state.StateDB, types.Deposits, *types.ExecutionPayloadHeader, common.Version) error); ok { r1 = rf(st, deposits, execPayloadHeader, genesisVersion) } else { r1 = ret.Error(1) } return r0, r1 } // GenesisStateProcessor_InitializeBeaconStateFromEth1_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InitializeBeaconStateFromEth1' type GenesisStateProcessor_InitializeBeaconStateFromEth1_Call struct { *mock.Call } // InitializeBeaconStateFromEth1 is a helper method to define mock.On call // - st *state.StateDB // - deposits types.Deposits // - execPayloadHeader *types.ExecutionPayloadHeader // - genesisVersion common.Version func (_e *GenesisStateProcessor_Expecter) InitializeBeaconStateFromEth1(st interface{}, deposits interface{}, execPayloadHeader interface{}, genesisVersion interface{}) *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call { return &GenesisStateProcessor_InitializeBeaconStateFromEth1_Call{Call: _e.mock.On("InitializeBeaconStateFromEth1", st, deposits, execPayloadHeader, genesisVersion)} } func (_c *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call) Run(run func(st *state.StateDB, deposits types.Deposits, execPayloadHeader *types.ExecutionPayloadHeader, genesisVersion common.Version)) *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(*state.StateDB), args[1].(types.Deposits), args[2].(*types.ExecutionPayloadHeader), args[3].(common.Version)) }) return _c } func (_c *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call) Return(_a0 transition.ValidatorUpdates, _a1 error) *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call) RunAndReturn(run func(*state.StateDB, types.Deposits, *types.ExecutionPayloadHeader, common.Version) (transition.ValidatorUpdates, error)) *GenesisStateProcessor_InitializeBeaconStateFromEth1_Call { _c.Call.Return(run) return _c } // NewGenesisStateProcessor creates a new instance of GenesisStateProcessor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewGenesisStateProcessor(t interface { mock.TestingT Cleanup(func()) }) *GenesisStateProcessor { mock := &GenesisStateProcessor{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-api/handlers/beacon/backend.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/node-api/backend" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" ) // Backend is the interface for backend of the beacon API. type Backend interface { // Blob related methods GetSyncData() (int64 /*latestHeight*/, int64 /*syncToHeight*/) GetBlobSidecarsAtSlot(slot math.Slot) (datypes.BlobSidecars, error) // State loading method, used by most of the handlers // Height == -1 must be used to require tip state. // Height == 0 must be used to require Genesis state // Height > 0 must be used to require state at slot StateAndSlotFromHeight(height int64) (backend.ReadOnlyBeaconState, math.Slot, error) // Methods helping mapping block/state/... IDs in requests to heights GetSlotByBlockRoot(root common.Root) (math.Slot, error) GetSlotByStateRoot(root common.Root) (math.Slot, error) // GetSignatureBySlot retrieves the block signature for a given slot. GetSignatureBySlot(slot math.Slot) (crypto.BLSSignature, error) } ================================================ FILE: node-api/handlers/beacon/blob_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon_test import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "github.com/berachain/beacon-kit/config/spec" ctypes "github.com/berachain/beacon-kit/consensus-types/types" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/beacon" "github.com/berachain/beacon-kit/node-api/handlers/beacon/mocks" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/labstack/echo/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestGetBlobSidecars(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) testSidecars := datypes.BlobSidecars{ { Index: 25, SignedBeaconBlockHeader: &ctypes.SignedBeaconBlockHeader{ Header: &ctypes.BeaconBlockHeader{ Slot: math.Slot(987), ProposerIndex: math.ValidatorIndex(2), ParentBlockRoot: common.Root{0x1, 0x2}, StateRoot: common.Root{0x3, 0x4}, BodyRoot: common.Root{0x5, 0x6}, }, }, }, } testCases := []struct { name string inputs func() beacontypes.GetBlobSidecarsRequest setMockExpectations func(*testing.T, *mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "success", inputs: func() beacontypes.GetBlobSidecarsRequest { return beacontypes.GetBlobSidecarsRequest{ BlockIDRequest: handlertypes.BlockIDRequest{ BlockID: utils.StateIDHead, }, Indices: nil, } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) { t.Helper() b.EXPECT().GetSyncData().Return(int64(1234), int64(1234)) b.EXPECT().GetBlobSidecarsAtSlot(mock.Anything).Return(testSidecars, nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.SidecarsResponse{}, res) sr, _ := res.(beacontypes.SidecarsResponse) require.Len(t, sr.Data, 1) require.Equal(t, beacontypes.SidecarFromConsensus(testSidecars[0]), sr.Data[0]) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // create API inputs input := tc.inputs() inputBytes, err := json.Marshal(input) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodGet, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // set expectations tc.setMockExpectations(t, backend) // test res, err := h.GetBlobSidecars(c) // finally do checks tc.check(t, res, err) }) } } ================================================ FILE: node-api/handlers/beacon/blobs.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "errors" "fmt" "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/math" ) // GetBlobSidecars provides an implementation for the // "/eth/v1/beacon/blob_sidecars/:block_id" API endpoint. // //nolint:gocognit // TODO: fix func (h *Handler) GetBlobSidecars(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[types.GetBlobSidecarsRequest]( c, h.Logger(), ) if err != nil { return nil, err } // Map requested blockID to slot slotID, err := utils.BlockIDToHeight(req.BlockID, h.backend) if err != nil { return nil, err } var slot math.Slot if slotID == utils.Head { latestHeight, _ := h.backend.GetSyncData() if latestHeight < 0 { return nil, errors.New("invalid negative block height") } slot = math.Slot(latestHeight) } else { slot = math.Slot(slotID) //#nosec: G115 // practically safe } // Convert indices to uint64. indices := make([]uint64, len(req.Indices)) for i, idxS := range req.Indices { var idx math.U64 idx, err = math.U64FromString(idxS) if err != nil { return nil, err } indices[i] = idx.Unwrap() } // Validate the requested slot is within the Data Availability Period. if !h.cs.WithinDAPeriod(slot, slot) { return nil, fmt.Errorf( "requested slot (%d) is not within Data Availability Period (previous %d epochs)", slotID, h.cs.MinEpochsForBlobsSidecarsRequest(), ) } // Validate request indices. if uint64(len(indices)) >= h.cs.MaxBlobsPerBlock() { return nil, errors.New("too many indices requested") } for _, index := range indices { if index >= h.cs.MaxBlobsPerBlock() { return nil, errors.New("blob index out of range") } } blobSidecars, err := h.backend.GetBlobSidecarsAtSlot(slot) if err != nil { return nil, err } // Create a map of requested indices for O(1) index lookups. isRequestIndex := make(map[uint64]bool) for _, idx := range indices { isRequestIndex[idx] = true } // Preallocate response slice - if indices specified, size will be len(indices), // otherwise size will be all sidecars. responseCap := len(blobSidecars) if len(indices) > 0 { responseCap = len(indices) } blobSidecarsResponse := make([]*types.Sidecar, 0, responseCap) for _, blobSidecar := range blobSidecars { // Skip if indices specified and this index not requested. if len(indices) > 0 && !isRequestIndex[blobSidecar.GetIndex()] { continue } // Craft and append the blob sidecar serialized data to the response. blobSidecarsResponse = append(blobSidecarsResponse, types.SidecarFromConsensus(blobSidecar), ) } return types.SidecarsResponse{ Data: blobSidecarsResponse, }, nil } ================================================ FILE: node-api/handlers/beacon/block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" ) func (h *Handler) GetBlockRewards(c handlers.Context) (any, error) { _, err := utils.BindAndValidate[beacontypes.GetBlockRewardsRequest]( c, h.Logger(), ) if err != nil { return nil, err } // TODO: Implement this. rewards := &beacontypes.BlockRewardsData{ ProposerIndex: 1, Total: 1, Attestations: 1, SyncAggregate: 1, ProposerSlashings: 1, AttesterSlashings: 1, } return beacontypes.NewResponse(rewards), nil } ================================================ FILE: node-api/handlers/beacon/genesis.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "errors" "fmt" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" ) func (h *Handler) GetGenesis(handlers.Context) (any, error) { st, _, err := h.backend.StateAndSlotFromHeight(utils.Genesis) if err != nil { if errors.Is(err, cometbft.ErrAppNotReady) { // chain not ready, like when genesis time is set in the future return nil, handlertypes.ErrNotFound } return nil, fmt.Errorf("failed to get state from genesis: %w", err) } genesisRoot, err := st.GetGenesisValidatorsRoot() if err != nil { return nil, err } genesisFork, err := st.GetFork() if err != nil { return nil, err } payload, err := st.GetLatestExecutionPayloadHeader() if err != nil { return nil, err } return beacontypes.GenesisResponse{ Data: beacontypes.GenesisData{ GenesisTime: payload.GetTimestamp().Base10(), GenesisValidatorsRoot: genesisRoot, GenesisForkVersion: genesisFork.CurrentVersion.String(), }, }, nil } ================================================ FILE: node-api/handlers/beacon/genesis_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon_test import ( "context" "testing" corestore "cosmossdk.io/core/store" "cosmossdk.io/log" "cosmossdk.io/store" sdkmetrics "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" ctypes "github.com/berachain/beacon-kit/consensus-types/types" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" beaconlog "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/beacon" "github.com/berachain/beacon-kit/node-api/handlers/beacon/mocks" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/state-transition/core/state" kvstorage "github.com/berachain/beacon-kit/storage" "github.com/berachain/beacon-kit/storage/beacondb" "github.com/berachain/beacon-kit/storage/db" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/labstack/echo/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestGetGenesis(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) var ( testGenesisRoot = common.Root{0x10, 0x20, 0x30} testGenesisForkVersion = common.Version{0xff, 0x11, 0x22, 0x33} testGenesisTime = math.U64(123456789) ) testCases := []struct { name string setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "success", setMockExpectations: func(b *mocks.Backend) { st := initTestGenesisState(t, cs) require.NoError(t, st.SetGenesisValidatorsRoot(testGenesisRoot)) require.NoError(t, st.SetFork(&ctypes.Fork{ PreviousVersion: testGenesisForkVersion, CurrentVersion: testGenesisForkVersion, })) require.NoError(t, st.SetLatestExecutionPayloadHeader(&ctypes.ExecutionPayloadHeader{ Versionable: ctypes.NewVersionable(testGenesisForkVersion), Timestamp: testGenesisTime, })) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, 0, nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenesisResponse{}, res) gr, _ := res.(beacontypes.GenesisResponse) require.Equal(t, testGenesisRoot, gr.Data.GenesisValidatorsRoot) require.Equal(t, testGenesisForkVersion.String(), gr.Data.GenesisForkVersion) require.Equal(t, testGenesisTime.Base10(), gr.Data.GenesisTime) }, }, { name: "genesis not ready", setMockExpectations: func(b *mocks.Backend) { b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(nil, 0, cometbft.ErrAppNotReady) }, check: func(t *testing.T, res any, err error) { t.Helper() require.ErrorIs(t, err, types.ErrNotFound) require.Nil(t, res) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[beaconlog.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // set expectations tc.setMockExpectations(backend) // test res, err := h.GetGenesis(nil) // input not relevant for this API // finally do checks tc.check(t, res, err) }) } } type backendKVStoreService struct { ctx sdk.Context } func (kvs *backendKVStoreService) OpenKVStore(context.Context) corestore.KVStore { //nolint:contextcheck // fine with tests store := sdk.UnwrapSDKContext(kvs.ctx).KVStore(testStoreKey) return kvstorage.NewKVStore(store) } var testStoreKey = storetypes.NewKVStoreKey("test-genesis") func initTestGenesisState(t *testing.T, cs chain.Spec) *state.StateDB { t.Helper() db, err := db.OpenDB("", dbm.MemDBBackend) require.NoError(t, err) var ( nopLog = log.NewNopLogger() nopMetrics = sdkmetrics.NewNoOpMetrics() ) cms := store.NewCommitMultiStore(db, nopLog, nopMetrics) cms.MountStoreWithDB(testStoreKey, storetypes.StoreTypeIAVL, nil) require.NoError(t, cms.LoadLatestVersion()) ctx := sdk.NewContext(cms, true, nopLog) backendStoreService := &backendKVStoreService{ ctx: ctx, } kvStore := beacondb.New(backendStoreService) sdkCtx := sdk.NewContext(cms.CacheMultiStore(), true, nopLog) return state.NewBeaconStateFromDB( kvStore.WithContext(sdkCtx), cs, sdkCtx.Logger(), metrics.NewNoOpTelemetrySink(), ) } ================================================ FILE: node-api/handlers/beacon/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" ) // Handler is the handler for the beacon API. type Handler struct { *handlers.BaseHandler cs chain.Spec backend Backend } // NewHandler creates a new handler for the beacon API. func NewHandler(backend Backend, cs chain.Spec, logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), cs: cs, backend: backend, } registerRoutes(h) return h } ================================================ FILE: node-api/handlers/beacon/header.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "errors" "fmt" stdmath "math" "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/math" ) var ErrMismatchedSlotAndParentBlock = errors.New("slot does not match with parent block") func (h *Handler) GetBlockHeaders(c handlers.Context) (any, error) { req, errReq := utils.BindAndValidate[beacontypes.GetBlockHeadersRequest](c, h.Logger()) if errReq != nil { return nil, errReq } switch { case len(req.Slot) == 0 && len(req.ParentRoot) == 0: // no parameter specified, pick chain HEAD // by requesting special height -1. height := utils.Head return h.makeBlockHeaderResponse(height, true /*resultsInList*/) case len(req.Slot) != 0 && len(req.ParentRoot) == 0: slot, errSlot := math.U64FromString(req.Slot) // errSlot should always be nil since we validated slots in BindAndValidate. if errSlot != nil { return nil, fmt.Errorf("failed retrieving slot from input parameters: %w", errSlot) } if slot > stdmath.MaxInt64 { // appease linters return 0, fmt.Errorf("%w: slot %d", utils.ErrFailedMappingHeightTooHigh, slot) } return h.makeBlockHeaderResponse(int64(slot), true /*resultsInList*/) //#nosec: G115 // safe case len(req.Slot) == 0 && len(req.ParentRoot) != 0: parentHeight, errParent := utils.BlockIDToHeight(req.ParentRoot, h.backend) if errParent != nil { return nil, fmt.Errorf("%w, failed retrieving parent root with error: %w", handlertypes.ErrNotFound, errParent) } if parentHeight == utils.Head { return nil, fmt.Errorf("%w, requested header of tip's child", handlertypes.ErrNotFound) } height := parentHeight + 1 return h.makeBlockHeaderResponse(height, true /*resultsInList*/) default: var ( slot, errSlot = math.U64FromString(req.Slot) parentSlot, errParent = utils.BlockIDToHeight(req.ParentRoot, h.backend) ) if err := errors.Join(errSlot, errParent); err != nil { return nil, err } if slot > stdmath.MaxInt64 { // appease linters return 0, fmt.Errorf("%w: slot %d", utils.ErrFailedMappingHeightTooHigh, slot) } height := int64(slot) //#nosec: G115 // safe if height != parentSlot+1 { return nil, fmt.Errorf("%w: request slot %d, parent block slot %d", ErrMismatchedSlotAndParentBlock, slot, parentSlot) } return h.makeBlockHeaderResponse(height, true /*resultsInList*/) } } func (h *Handler) GetBlockHeaderByID(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetBlockHeaderRequest](c, h.Logger()) if err != nil { return nil, err } slot, err := utils.BlockIDToHeight(req.BlockID, h.backend) if err != nil { return nil, fmt.Errorf("failed retrieving slot from block ID %s: %w", req.BlockID, err) } return h.makeBlockHeaderResponse(slot, false /*resultsInList*/) } func (h *Handler) makeBlockHeaderResponse(height int64, resultsInList bool) (any, error) { st, slot, err := h.backend.StateAndSlotFromHeight(height) if err != nil { return nil, fmt.Errorf("%w: failed to get state from height %d, %s", handlertypes.ErrNotFound, height, err.Error()) } // Return after updating the state root in the block header. header, err := st.GetLatestBlockHeader() if err != nil { return nil, fmt.Errorf("failed to get latest block header: %w", err) } header.SetStateRoot(st.HashTreeRoot()) // Retrieve the block signature from the block store. The signature may not be available // if the block is outside the availability window or if querying genesis. var signatureStr string if slot > 0 { signature, sigErr := h.backend.GetSignatureBySlot(slot) if sigErr == nil { signatureStr = signature.String() } } // While an Ethereum node may have multiple blocks per slot, BeaconKit // will access only one, given single slot finality and the fact that we only // access finalized blocks in this APIs. Still we may return a list of responses // to be compliant with API specs https://ethereum.github.io/beacon-APIs/?urls.primaryName=v3.1.0#/Beacon/getBlockHeader headerResp := beacontypes.BlockHeaderResponse{ Root: header.GetBodyRoot(), Canonical: true, Header: &beacontypes.SignedBeaconBlockHeader{ Message: beacontypes.BeaconBlockHeaderFromConsensus(header), Signature: signatureStr, }, } if !resultsInList { return beacontypes.NewResponse(&headerResp), nil } res := []beacontypes.BlockHeaderResponse{ headerResp, } return beacontypes.NewResponse(res), nil } ================================================ FILE: node-api/handlers/beacon/header_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon_test import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/beacon" "github.com/berachain/beacon-kit/node-api/handlers/beacon/mocks" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/labstack/echo/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) //nolint:maintidx // multiple test cases func TestGetBlockHeaders(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) // testHeaders to build test cases on top of testParentHeader := &ctypes.BeaconBlockHeader{ Slot: math.Slot(10), ProposerIndex: math.ValidatorIndex(1234), ParentBlockRoot: common.Root{'p', 'a', 'r', 'e', 'n', 't', 'b', 'l', 'o', 'c', 'k', 'r', 'o', 'o', 't'}, StateRoot: common.Root{'p', 'a', 'r', 'e', 'n', 't', 's', 't', 'a', 't', 'e', 'r', 'o', 'o', 't'}, BodyRoot: common.Root{'p', 'a', 'r', 'e', 'n', 't', 'r', 'o', 'o', 't'}, } testHeader := &ctypes.BeaconBlockHeader{ Slot: testParentHeader.Slot + 1, ProposerIndex: math.ValidatorIndex(5678), ParentBlockRoot: testParentHeader.BodyRoot, StateRoot: common.Root{}, // set in test cases BodyRoot: common.Root{'d', 'u', 'm', 'm', 'y', 'r', 'o', 'o', 't'}, } wrongSlot := testHeader.Slot + 1234 errTestHeaderNotFound := errors.New("test header not found error") testCases := []struct { name string inputs func() beacontypes.GetBlockHeadersRequest setMockExpectations func(*testing.T, *mocks.Backend) common.Root check func(t *testing.T, expectedStateRoot common.Root, res any, err error) }{ { name: "GetBlockHeaders - success - no query params", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{}, ParentRoot: "", } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) common.Root { t.Helper() st := makeTestState(t, cs) stateRoot := testDummyState(t, cs, st, testHeader) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) return stateRoot }, check: func(t *testing.T, expectedStateRoot common.Root, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []beacontypes.BlockHeaderResponse{}, gr.Data) data, _ := gr.Data.([]beacontypes.BlockHeaderResponse) require.Len(t, data, 1) require.Equal(t, testHeader.BodyRoot, data[0].Root) expectedHeader := &beacontypes.BeaconBlockHeader{ Slot: testHeader.Slot.Base10(), ProposerIndex: testHeader.ProposerIndex.Base10(), ParentRoot: testHeader.ParentBlockRoot.Hex(), StateRoot: expectedStateRoot.Hex(), BodyRoot: testHeader.BodyRoot.Hex(), } require.Equal(t, expectedHeader, data[0].Header.Message) }, }, { name: "GetBlockHeaders - success - slot only", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{ Slot: testHeader.Slot.Base10(), }, ParentRoot: "", } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) common.Root { t.Helper() st := makeTestState(t, cs) stateRoot := testDummyState(t, cs, st, testHeader) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) return stateRoot }, check: func(t *testing.T, expectedStateRoot common.Root, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []beacontypes.BlockHeaderResponse{}, gr.Data) data, _ := gr.Data.([]beacontypes.BlockHeaderResponse) require.Len(t, data, 1) require.Equal(t, testHeader.BodyRoot, data[0].Root) expectedHeader := &beacontypes.BeaconBlockHeader{ Slot: testHeader.Slot.Base10(), ProposerIndex: testHeader.ProposerIndex.Base10(), ParentRoot: testHeader.ParentBlockRoot.Hex(), StateRoot: expectedStateRoot.Hex(), BodyRoot: testHeader.BodyRoot.Hex(), } require.Equal(t, expectedHeader, data[0].Header.Message) }, }, { name: "GetBlockHeaders - failure - invalid slot", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{ Slot: "AAAA", }, ParentRoot: "", } }, setMockExpectations: func(*testing.T, *mocks.Backend) common.Root { // nothing to set here, slot is invalid return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() require.ErrorIs(t, err, handlertypes.ErrInvalidRequest) }, }, { name: "GetBlockHeaders - failure - unindexed slot", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{ Slot: testHeader.Slot.Base10(), }, ParentRoot: "", } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) common.Root { t.Helper() b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(nil, math.Slot(0), errTestHeaderNotFound) return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() // Implicitly ensuring that 404 error code is returned // (see responseFromError implementation) require.ErrorIs(t, err, handlertypes.ErrNotFound) }, }, { name: "GetBlockHeaders - success - parent root only", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{}, ParentRoot: testHeader.ParentBlockRoot.Hex(), } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) common.Root { t.Helper() st := makeTestState(t, cs) stateRoot := testDummyState(t, cs, st, testHeader) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) b.EXPECT().GetSlotByBlockRoot(testParentHeader.BodyRoot).Return(testParentHeader.Slot, nil) return stateRoot }, check: func(t *testing.T, expectedStateRoot common.Root, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []beacontypes.BlockHeaderResponse{}, gr.Data) data, _ := gr.Data.([]beacontypes.BlockHeaderResponse) require.Len(t, data, 1) require.Equal(t, testHeader.BodyRoot, data[0].Root) expectedHeader := &beacontypes.BeaconBlockHeader{ Slot: testHeader.Slot.Base10(), ProposerIndex: testHeader.ProposerIndex.Base10(), ParentRoot: testHeader.ParentBlockRoot.Hex(), StateRoot: expectedStateRoot.Hex(), BodyRoot: testHeader.BodyRoot.Hex(), } require.Equal(t, expectedHeader, data[0].Header.Message) }, }, { name: "GetBlockHeaders - failure - invalid parent root", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{}, ParentRoot: "AN-INVALID-HEX", } }, setMockExpectations: func(*testing.T, *mocks.Backend) common.Root { // nothing to set here, slot is invalid return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() require.ErrorIs(t, err, handlertypes.ErrInvalidRequest) }, }, { name: "GetBlockHeaders - failure - unindexed parent block", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{}, ParentRoot: testHeader.ParentBlockRoot.Hex(), } }, setMockExpectations: func(_ *testing.T, b *mocks.Backend) common.Root { // Assume parent header is not known b.EXPECT().GetSlotByBlockRoot(testParentHeader.BodyRoot).Return(0, errTestHeaderNotFound) return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() // Implicitly ensuring that 404 error code is returned // (see responseFromError implementation) require.ErrorIs(t, err, handlertypes.ErrNotFound) }, }, { name: "GetBlockHeaders - success - slot and parent root", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{ Slot: testHeader.Slot.Base10(), }, ParentRoot: testHeader.ParentBlockRoot.Hex(), } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) common.Root { t.Helper() st := makeTestState(t, cs) stateRoot := testDummyState(t, cs, st, testHeader) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) b.EXPECT().GetSlotByBlockRoot(testParentHeader.BodyRoot).Return(testParentHeader.Slot, nil) return stateRoot }, check: func(t *testing.T, expectedStateRoot common.Root, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []beacontypes.BlockHeaderResponse{}, gr.Data) data, _ := gr.Data.([]beacontypes.BlockHeaderResponse) require.Len(t, data, 1) require.Equal(t, testHeader.BodyRoot, data[0].Root) expectedHeader := &beacontypes.BeaconBlockHeader{ Slot: testHeader.Slot.Base10(), ProposerIndex: testHeader.ProposerIndex.Base10(), ParentRoot: testHeader.ParentBlockRoot.Hex(), StateRoot: expectedStateRoot.Hex(), BodyRoot: testHeader.BodyRoot.Hex(), } require.Equal(t, expectedHeader, data[0].Header.Message) }, }, { name: "GetBlockHeaders - failure - mismatched slot and parent root", inputs: func() beacontypes.GetBlockHeadersRequest { return beacontypes.GetBlockHeadersRequest{ SlotRequest: beacontypes.SlotRequest{ Slot: wrongSlot.Base10(), }, ParentRoot: testHeader.ParentBlockRoot.Hex(), } }, setMockExpectations: func(_ *testing.T, b *mocks.Backend) common.Root { b.EXPECT().GetSlotByBlockRoot(testParentHeader.BodyRoot).Return(testParentHeader.Slot, nil) return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() require.ErrorIs(t, err, beacon.ErrMismatchedSlotAndParentBlock) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // create API inputs input := tc.inputs() inputBytes, err := json.Marshal(input) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodGet, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // set expectations expectedStateRoot := tc.setMockExpectations(t, backend) // test res, err := h.GetBlockHeaders(c) // finally do checks tc.check(t, expectedStateRoot, res, err) }) } } func TestGetBlockHeaderByID(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) // a test testHeader to build test cases on top of testHeader := &ctypes.BeaconBlockHeader{ Slot: math.Slot(1234), ProposerIndex: math.ValidatorIndex(5678), ParentBlockRoot: common.Root{'p', 'a', 'r', 'e', 'n', 't', 'b', 'l', 'o', 'c', 'k', 'r', 'o', 'o', 't'}, StateRoot: common.Root{}, // set in test cases BodyRoot: common.Root{'d', 'u', 'm', 'm', 'y', 'r', 'o', 'o', 't'}, } errTestHeaderNotFound := errors.New("test header not found error") testCases := []struct { name string inputs func() beacontypes.GetBlockHeaderRequest setMockExpectations func(*testing.T, *mocks.Backend) common.Root check func(t *testing.T, expectedStateRoot common.Root, res any, err error) }{ { name: "GetBlockHeaderByID - success - id is slot", inputs: func() beacontypes.GetBlockHeaderRequest { return beacontypes.GetBlockHeaderRequest{ BlockIDRequest: handlertypes.BlockIDRequest{ BlockID: testHeader.Slot.Base10(), }, } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) common.Root { t.Helper() st := makeTestState(t, cs) stateRoot := testDummyState(t, cs, st, testHeader) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) return stateRoot }, check: func(t *testing.T, expectedStateRoot common.Root, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, &beacontypes.BlockHeaderResponse{}, gr.Data) data, _ := gr.Data.(*beacontypes.BlockHeaderResponse) require.Equal(t, testHeader.BodyRoot, data.Root) expectedHeader := &beacontypes.BeaconBlockHeader{ Slot: testHeader.Slot.Base10(), ProposerIndex: testHeader.ProposerIndex.Base10(), ParentRoot: testHeader.ParentBlockRoot.Hex(), StateRoot: expectedStateRoot.Hex(), BodyRoot: testHeader.BodyRoot.Hex(), } require.Equal(t, expectedHeader, data.Header.Message) }, }, { name: "GetBlockHeaderByID - failure - invalid slot", inputs: func() beacontypes.GetBlockHeaderRequest { return beacontypes.GetBlockHeaderRequest{ BlockIDRequest: handlertypes.BlockIDRequest{ BlockID: "zzzz", }, } }, setMockExpectations: func(*testing.T, *mocks.Backend) common.Root { // nothing to set here, slot is invalid return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() require.ErrorIs(t, err, handlertypes.ErrInvalidRequest) }, }, { name: "GetBlockHeaderByID - failure - unindexed slot", inputs: func() beacontypes.GetBlockHeaderRequest { return beacontypes.GetBlockHeaderRequest{ BlockIDRequest: handlertypes.BlockIDRequest{ BlockID: testHeader.Slot.Base10(), }, } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) common.Root { t.Helper() b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(nil, math.Slot(0), errTestHeaderNotFound) return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() // Implicitly ensuring that 404 error code is returned // (see responseFromError implementation) require.ErrorIs(t, err, handlertypes.ErrNotFound) }, }, { name: "GetBlockHeaderByID - success - id is block root", inputs: func() beacontypes.GetBlockHeaderRequest { return beacontypes.GetBlockHeaderRequest{ BlockIDRequest: handlertypes.BlockIDRequest{ BlockID: testHeader.BodyRoot.Hex(), }, } }, setMockExpectations: func(t *testing.T, b *mocks.Backend) common.Root { t.Helper() st := makeTestState(t, cs) stateRoot := testDummyState(t, cs, st, testHeader) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) b.EXPECT().GetSlotByBlockRoot(testHeader.BodyRoot).Return(testHeader.Slot, nil) return stateRoot }, check: func(t *testing.T, expectedStateRoot common.Root, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, &beacontypes.BlockHeaderResponse{}, gr.Data) data, _ := gr.Data.(*beacontypes.BlockHeaderResponse) require.Equal(t, testHeader.BodyRoot, data.Root) expectedHeader := &beacontypes.BeaconBlockHeader{ Slot: testHeader.Slot.Base10(), ProposerIndex: testHeader.ProposerIndex.Base10(), ParentRoot: testHeader.ParentBlockRoot.Hex(), StateRoot: expectedStateRoot.Hex(), BodyRoot: testHeader.BodyRoot.Hex(), } require.Equal(t, expectedHeader, data.Header.Message) }, }, { name: "GetBlockHeaderByID - failure - invalid block root", inputs: func() beacontypes.GetBlockHeaderRequest { return beacontypes.GetBlockHeaderRequest{ BlockIDRequest: handlertypes.BlockIDRequest{ BlockID: "AN-INVALID-HEX", }, } }, setMockExpectations: func(*testing.T, *mocks.Backend) common.Root { // nothing to set here, slot is invalid return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() require.ErrorIs(t, err, handlertypes.ErrInvalidRequest) }, }, { name: "GetBlockHeaderByID - failure - unindexed block", inputs: func() beacontypes.GetBlockHeaderRequest { return beacontypes.GetBlockHeaderRequest{ BlockIDRequest: handlertypes.BlockIDRequest{ BlockID: testHeader.BodyRoot.Hex(), }, } }, setMockExpectations: func(_ *testing.T, b *mocks.Backend) common.Root { // Assume parent header is not known b.EXPECT().GetSlotByBlockRoot(testHeader.BodyRoot).Return(0, errTestHeaderNotFound) return common.Root{} }, check: func(t *testing.T, _ common.Root, _ any, err error) { t.Helper() require.ErrorIs(t, err, errTestHeaderNotFound) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // create API inputs input := tc.inputs() inputBytes, err := json.Marshal(input) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodGet, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // set expectations expectedStateRoot := tc.setMockExpectations(t, backend) // test res, err := h.GetBlockHeaderByID(c) // finally do checks tc.check(t, expectedStateRoot, res, err) }) } } // TestDummyState sets a few dummy state elements, enough to // be able to call HashTreeRoot over the state. func testDummyState( t *testing.T, cs chain.Spec, st *statedb.StateDB, testHeader *ctypes.BeaconBlockHeader, ) common.Root { t.Helper() dummyFork := &ctypes.Fork{ PreviousVersion: version.Deneb(), CurrentVersion: version.Electra(), Epoch: math.Epoch(200), } require.NoError(t, st.SetSlot(1234)) require.NoError(t, st.SetFork(dummyFork)) require.NoError(t, st.SetGenesisValidatorsRoot(common.Root{0x01})) require.NoError(t, st.SetLatestBlockHeader(testHeader)) for i := range cs.HistoricalRootsLimit() { require.NoError(t, st.UpdateBlockRootAtIndex(i, common.Root{})) require.NoError(t, st.UpdateStateRootAtIndex(i, common.Root{})) } require.NoError(t, st.SetLatestExecutionPayloadHeader(&ctypes.ExecutionPayloadHeader{ Versionable: ctypes.NewVersionable(dummyFork.CurrentVersion), })) require.NoError(t, st.SetEth1Data(&ctypes.Eth1Data{})) require.NoError(t, st.SetEth1DepositIndex(0)) require.NoError(t, st.AddValidator(&ctypes.Validator{})) require.NoError(t, st.SetBalance(math.ValidatorIndex(0), math.Gwei(0))) for i := range cs.EpochsPerHistoricalVector() { require.NoError(t, st.UpdateRandaoMixAtIndex(i, common.Bytes32{})) } require.NoError(t, st.SetNextWithdrawalIndex(0)) require.NoError(t, st.SetNextWithdrawalValidatorIndex(math.ValidatorIndex(0))) require.NoError(t, st.SetPendingPartialWithdrawals([]*ctypes.PendingPartialWithdrawal{})) return st.HashTreeRoot() } ================================================ FILE: node-api/handlers/beacon/historical.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" ) func (h *Handler) GetStateRoot(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetStateRootRequest]( c, h.Logger(), ) if err != nil { return nil, err } slot, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } st, _, err := h.backend.StateAndSlotFromHeight(slot) if err != nil { return nil, err } return beacontypes.NewResponse(beacontypes.RootData{Root: st.HashTreeRoot()}), nil } func (h *Handler) GetStateFork(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetStateForkRequest]( c, h.Logger(), ) if err != nil { return nil, err } slot, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } st, _, err := h.backend.StateAndSlotFromHeight(slot) if err != nil { return nil, err } fork, err := st.GetFork() if err != nil { return nil, err } return beacontypes.NewResponse(fork), nil } ================================================ FILE: node-api/handlers/beacon/mocks/backend.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( backend "github.com/berachain/beacon-kit/node-api/backend" types "github.com/berachain/beacon-kit/da/types" common "github.com/berachain/beacon-kit/primitives/common" crypto "github.com/berachain/beacon-kit/primitives/crypto" math "github.com/berachain/beacon-kit/primitives/math" mock "github.com/stretchr/testify/mock" ) // Backend is an autogenerated mock type for the Backend type type Backend struct { mock.Mock } type Backend_Expecter struct { mock *mock.Mock } func (_m *Backend) EXPECT() *Backend_Expecter { return &Backend_Expecter{mock: &_m.Mock} } // GetBlobSidecarsAtSlot provides a mock function with given fields: slot func (_m *Backend) GetBlobSidecarsAtSlot(slot math.Slot) (types.BlobSidecars, error) { ret := _m.Called(slot) if len(ret) == 0 { panic("no return value specified for GetBlobSidecarsAtSlot") } var r0 types.BlobSidecars var r1 error if rf, ok := ret.Get(0).(func(math.Slot) (types.BlobSidecars, error)); ok { return rf(slot) } if rf, ok := ret.Get(0).(func(math.Slot) types.BlobSidecars); ok { r0 = rf(slot) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(types.BlobSidecars) } } if rf, ok := ret.Get(1).(func(math.Slot) error); ok { r1 = rf(slot) } else { r1 = ret.Error(1) } return r0, r1 } // Backend_GetBlobSidecarsAtSlot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlobSidecarsAtSlot' type Backend_GetBlobSidecarsAtSlot_Call struct { *mock.Call } // GetBlobSidecarsAtSlot is a helper method to define mock.On call // - slot math.Slot func (_e *Backend_Expecter) GetBlobSidecarsAtSlot(slot interface{}) *Backend_GetBlobSidecarsAtSlot_Call { return &Backend_GetBlobSidecarsAtSlot_Call{Call: _e.mock.On("GetBlobSidecarsAtSlot", slot)} } func (_c *Backend_GetBlobSidecarsAtSlot_Call) Run(run func(slot math.Slot)) *Backend_GetBlobSidecarsAtSlot_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(math.Slot)) }) return _c } func (_c *Backend_GetBlobSidecarsAtSlot_Call) Return(_a0 types.BlobSidecars, _a1 error) *Backend_GetBlobSidecarsAtSlot_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *Backend_GetBlobSidecarsAtSlot_Call) RunAndReturn(run func(math.Slot) (types.BlobSidecars, error)) *Backend_GetBlobSidecarsAtSlot_Call { _c.Call.Return(run) return _c } // GetSignatureBySlot provides a mock function with given fields: slot func (_m *Backend) GetSignatureBySlot(slot math.Slot) (crypto.BLSSignature, error) { ret := _m.Called(slot) if len(ret) == 0 { panic("no return value specified for GetSignatureBySlot") } var r0 crypto.BLSSignature var r1 error if rf, ok := ret.Get(0).(func(math.Slot) (crypto.BLSSignature, error)); ok { return rf(slot) } if rf, ok := ret.Get(0).(func(math.Slot) crypto.BLSSignature); ok { r0 = rf(slot) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(crypto.BLSSignature) } } if rf, ok := ret.Get(1).(func(math.Slot) error); ok { r1 = rf(slot) } else { r1 = ret.Error(1) } return r0, r1 } // Backend_GetSignatureBySlot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSignatureBySlot' type Backend_GetSignatureBySlot_Call struct { *mock.Call } // GetSignatureBySlot is a helper method to define mock.On call // - slot math.Slot func (_e *Backend_Expecter) GetSignatureBySlot(slot interface{}) *Backend_GetSignatureBySlot_Call { return &Backend_GetSignatureBySlot_Call{Call: _e.mock.On("GetSignatureBySlot", slot)} } func (_c *Backend_GetSignatureBySlot_Call) Run(run func(slot math.Slot)) *Backend_GetSignatureBySlot_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(math.Slot)) }) return _c } func (_c *Backend_GetSignatureBySlot_Call) Return(_a0 crypto.BLSSignature, _a1 error) *Backend_GetSignatureBySlot_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *Backend_GetSignatureBySlot_Call) RunAndReturn(run func(math.Slot) (crypto.BLSSignature, error)) *Backend_GetSignatureBySlot_Call { _c.Call.Return(run) return _c } // GetSlotByBlockRoot provides a mock function with given fields: root func (_m *Backend) GetSlotByBlockRoot(root common.Root) (math.Slot, error) { ret := _m.Called(root) if len(ret) == 0 { panic("no return value specified for GetSlotByBlockRoot") } var r0 math.Slot var r1 error if rf, ok := ret.Get(0).(func(common.Root) (math.Slot, error)); ok { return rf(root) } if rf, ok := ret.Get(0).(func(common.Root) math.Slot); ok { r0 = rf(root) } else { r0 = ret.Get(0).(math.Slot) } if rf, ok := ret.Get(1).(func(common.Root) error); ok { r1 = rf(root) } else { r1 = ret.Error(1) } return r0, r1 } // Backend_GetSlotByBlockRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByBlockRoot' type Backend_GetSlotByBlockRoot_Call struct { *mock.Call } // GetSlotByBlockRoot is a helper method to define mock.On call // - root common.Root func (_e *Backend_Expecter) GetSlotByBlockRoot(root interface{}) *Backend_GetSlotByBlockRoot_Call { return &Backend_GetSlotByBlockRoot_Call{Call: _e.mock.On("GetSlotByBlockRoot", root)} } func (_c *Backend_GetSlotByBlockRoot_Call) Run(run func(root common.Root)) *Backend_GetSlotByBlockRoot_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(common.Root)) }) return _c } func (_c *Backend_GetSlotByBlockRoot_Call) Return(_a0 math.Slot, _a1 error) *Backend_GetSlotByBlockRoot_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *Backend_GetSlotByBlockRoot_Call) RunAndReturn(run func(common.Root) (math.Slot, error)) *Backend_GetSlotByBlockRoot_Call { _c.Call.Return(run) return _c } // GetSlotByStateRoot provides a mock function with given fields: root func (_m *Backend) GetSlotByStateRoot(root common.Root) (math.Slot, error) { ret := _m.Called(root) if len(ret) == 0 { panic("no return value specified for GetSlotByStateRoot") } var r0 math.Slot var r1 error if rf, ok := ret.Get(0).(func(common.Root) (math.Slot, error)); ok { return rf(root) } if rf, ok := ret.Get(0).(func(common.Root) math.Slot); ok { r0 = rf(root) } else { r0 = ret.Get(0).(math.Slot) } if rf, ok := ret.Get(1).(func(common.Root) error); ok { r1 = rf(root) } else { r1 = ret.Error(1) } return r0, r1 } // Backend_GetSlotByStateRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSlotByStateRoot' type Backend_GetSlotByStateRoot_Call struct { *mock.Call } // GetSlotByStateRoot is a helper method to define mock.On call // - root common.Root func (_e *Backend_Expecter) GetSlotByStateRoot(root interface{}) *Backend_GetSlotByStateRoot_Call { return &Backend_GetSlotByStateRoot_Call{Call: _e.mock.On("GetSlotByStateRoot", root)} } func (_c *Backend_GetSlotByStateRoot_Call) Run(run func(root common.Root)) *Backend_GetSlotByStateRoot_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(common.Root)) }) return _c } func (_c *Backend_GetSlotByStateRoot_Call) Return(_a0 math.Slot, _a1 error) *Backend_GetSlotByStateRoot_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *Backend_GetSlotByStateRoot_Call) RunAndReturn(run func(common.Root) (math.Slot, error)) *Backend_GetSlotByStateRoot_Call { _c.Call.Return(run) return _c } // GetSyncData provides a mock function with no fields func (_m *Backend) GetSyncData() (int64, int64) { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetSyncData") } var r0 int64 var r1 int64 if rf, ok := ret.Get(0).(func() (int64, int64)); ok { return rf() } if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() } else { r0 = ret.Get(0).(int64) } if rf, ok := ret.Get(1).(func() int64); ok { r1 = rf() } else { r1 = ret.Get(1).(int64) } return r0, r1 } // Backend_GetSyncData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSyncData' type Backend_GetSyncData_Call struct { *mock.Call } // GetSyncData is a helper method to define mock.On call func (_e *Backend_Expecter) GetSyncData() *Backend_GetSyncData_Call { return &Backend_GetSyncData_Call{Call: _e.mock.On("GetSyncData")} } func (_c *Backend_GetSyncData_Call) Run(run func()) *Backend_GetSyncData_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *Backend_GetSyncData_Call) Return(_a0 int64, _a1 int64) *Backend_GetSyncData_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *Backend_GetSyncData_Call) RunAndReturn(run func() (int64, int64)) *Backend_GetSyncData_Call { _c.Call.Return(run) return _c } // StateAndSlotFromHeight provides a mock function with given fields: height func (_m *Backend) StateAndSlotFromHeight(height int64) (backend.ReadOnlyBeaconState, math.Slot, error) { ret := _m.Called(height) if len(ret) == 0 { panic("no return value specified for StateAndSlotFromHeight") } var r0 backend.ReadOnlyBeaconState var r1 math.Slot var r2 error if rf, ok := ret.Get(0).(func(int64) (backend.ReadOnlyBeaconState, math.Slot, error)); ok { return rf(height) } if rf, ok := ret.Get(0).(func(int64) backend.ReadOnlyBeaconState); ok { r0 = rf(height) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(backend.ReadOnlyBeaconState) } } if rf, ok := ret.Get(1).(func(int64) math.Slot); ok { r1 = rf(height) } else { r1 = ret.Get(1).(math.Slot) } if rf, ok := ret.Get(2).(func(int64) error); ok { r2 = rf(height) } else { r2 = ret.Error(2) } return r0, r1, r2 } // Backend_StateAndSlotFromHeight_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StateAndSlotFromHeight' type Backend_StateAndSlotFromHeight_Call struct { *mock.Call } // StateAndSlotFromHeight is a helper method to define mock.On call // - height int64 func (_e *Backend_Expecter) StateAndSlotFromHeight(height interface{}) *Backend_StateAndSlotFromHeight_Call { return &Backend_StateAndSlotFromHeight_Call{Call: _e.mock.On("StateAndSlotFromHeight", height)} } func (_c *Backend_StateAndSlotFromHeight_Call) Run(run func(height int64)) *Backend_StateAndSlotFromHeight_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(int64)) }) return _c } func (_c *Backend_StateAndSlotFromHeight_Call) Return(_a0 backend.ReadOnlyBeaconState, _a1 math.Slot, _a2 error) *Backend_StateAndSlotFromHeight_Call { _c.Call.Return(_a0, _a1, _a2) return _c } func (_c *Backend_StateAndSlotFromHeight_Call) RunAndReturn(run func(int64) (backend.ReadOnlyBeaconState, math.Slot, error)) *Backend_StateAndSlotFromHeight_Call { _c.Call.Return(run) return _c } // NewBackend creates a new instance of Backend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBackend(t interface { mock.TestingT Cleanup(func()) }) *Backend { mock := &Backend{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-api/handlers/beacon/randao.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/math" ) func (h *Handler) GetRandao(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetRandaoRequest]( c, h.Logger(), ) if err != nil { return nil, err } // Get slot and associated state height, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } st, slot, err := h.backend.StateAndSlotFromHeight(height) if err != nil { return nil, errors.Wrapf(err, "failed to get state from height %d", height) } // Get the epoch var epoch math.Epoch if req.Epoch != "" { epoch, err = math.U64FromString(req.Epoch) if err != nil { return nil, err } } else { // Infer the epoch if not provided. epoch = h.cs.SlotToEpoch(slot) } // Retrieve the randao index := epoch.Unwrap() % h.cs.EpochsPerHistoricalVector() randao, err := st.GetRandaoMixAtIndex(index) if err != nil { return nil, err } return beacontypes.NewResponse(randao), nil } ================================================ FILE: node-api/handlers/beacon/randao_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon_test import ( "encoding/json" "net/http" "net/http/httptest" "strconv" "strings" "testing" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/beacon" "github.com/berachain/beacon-kit/node-api/handlers/beacon/mocks" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/labstack/echo/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestGetRandao(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) var ( testSlot = math.Slot(1234) testEpoch = cs.SlotToEpoch(testSlot) index = testEpoch.Unwrap() % cs.EpochsPerHistoricalVector() testMix = common.Bytes32{0x01, 0x02, 0x03} ) testCases := []struct { name string inputs func() beacontypes.GetRandaoRequest setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "randao request - specified epoch", inputs: func() beacontypes.GetRandaoRequest { stateID := utils.StateIDHead epoch := strconv.Itoa(int(testEpoch.Unwrap())) return beacontypes.GetRandaoRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, EpochOptionalRequest: beacontypes.EpochOptionalRequest{ Epoch: epoch, }, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) require.NoError(t, st.UpdateRandaoMixAtIndex(index, testMix)) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, testSlot, nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, common.Bytes32{}, gr.Data) data, _ := gr.Data.(common.Bytes32) require.Equal(t, testMix, data) }, }, { name: "randao request - unspecified epoch", inputs: func() beacontypes.GetRandaoRequest { stateID := utils.StateIDHead return beacontypes.GetRandaoRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) require.NoError(t, st.UpdateRandaoMixAtIndex(index, testMix)) b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, testSlot, nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, common.Bytes32{}, gr.Data) data, _ := gr.Data.(common.Bytes32) require.Equal(t, testMix, data) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // set expectations tc.setMockExpectations(backend) // create input input := tc.inputs() inputBytes, err := json.Marshal(input) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodGet, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // test res, err := h.GetRandao(c) // check tc.check(t, res, err) }) } } ================================================ FILE: node-api/handlers/beacon/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) //nolint:funlen // routes are long func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodGet, Path: "/eth/v1/beacon/genesis", Handler: h.GetGenesis, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/root", Handler: h.GetStateRoot, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/fork", Handler: h.GetStateFork, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/finality_checkpoints", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/validators", Handler: h.GetStateValidators, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/states/:state_id/validators", Handler: h.PostStateValidators, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/validators/:validator_id", Handler: h.GetStateValidator, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/validator_balances", Handler: h.GetStateValidatorBalances, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/states/:state_id/validator_balances", Handler: h.PostStateValidatorBalances, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/states/:state_id/validator_identities", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/committees", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/sync_committees", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/randao", Handler: h.GetRandao, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/pending_deposits", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/states/:state_id/pending_partial_withdrawals", Handler: h.GetPendingPartialWithdrawals, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/headers", Handler: h.GetBlockHeaders, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/headers/:block_id", Handler: h.GetBlockHeaderByID, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/blocks/blinded_blocks", Handler: h.Deprecated, }, { Method: http.MethodPost, Path: "eth/v2/beacon/blocks/blinded_blocks", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/blocks", Handler: h.Deprecated, }, { Method: http.MethodPost, Path: "eth/v2/beacon/blocks", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "eth/v2/beacon/blocks/:block_id", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/blocks/:block_id/root", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/blocks/:block_id/attestations", Handler: h.Deprecated, }, { Method: http.MethodGet, Path: "/eth/v2/beacon/blocks/:block_id/attestations", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/blob_sidecars/:block_id", Handler: h.GetBlobSidecars, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/rewards/sync_committee/:block_id", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/deposit_snapshot", Handler: h.Deprecated, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/rewards/blocks/:block_id", Handler: h.GetBlockRewards, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/rewards/attestations/:epoch", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/blinded_blocks/:block_id", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/light_client/bootstrap/:block_root", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/light_client/updates", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/light_client/finality_update", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/light_client/optimistic_update", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/pool/attestations", Handler: h.Deprecated, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/pool/attestations", Handler: h.Deprecated, }, { Method: http.MethodGet, Path: "/eth/v2/beacon/pool/attestations", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v2/beacon/pool/attestations", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/pool/attester_slashings", Handler: h.Deprecated, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/pool/attester_slashings", Handler: h.Deprecated, }, { Method: http.MethodGet, Path: "/eth/v2/beacon/pool/attester_slashings", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v2/beacon/pool/attester_slashings", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/pool/proposer_slashings", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/pool/proposer_slashings", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/pool/sync_committees", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/pool/voluntary_exits", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/pool/voluntary_exits", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/beacon/pool/bls_to_execution_changes", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/beacon/pool/bls_to_execution_changes", Handler: h.NotImplemented, }, }) } ================================================ FILE: node-api/handlers/beacon/types/conversions.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "fmt" "strconv" "github.com/berachain/beacon-kit/cli/utils/parser" ctypes "github.com/berachain/beacon-kit/consensus-types/types" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/math" ) func BeaconBlockHeaderFromConsensus(h *ctypes.BeaconBlockHeader) *BeaconBlockHeader { return &BeaconBlockHeader{ Slot: fmt.Sprintf("%d", h.Slot), ProposerIndex: fmt.Sprintf("%d", h.ProposerIndex), ParentRoot: h.ParentBlockRoot.Hex(), StateRoot: h.StateRoot.Hex(), BodyRoot: h.BodyRoot.Hex(), } } func SignedBeaconBlockHeaderFromConsensus(h *ctypes.SignedBeaconBlockHeader) *SignedBeaconBlockHeader { return &SignedBeaconBlockHeader{ Message: BeaconBlockHeaderFromConsensus(h.Header), Signature: h.Signature.String(), } } func SidecarFromConsensus(sc *datypes.BlobSidecar) *Sidecar { proofs := make([]string, len(sc.InclusionProof)) for i := range sc.InclusionProof { proofs[i] = hex.EncodeBytes(sc.InclusionProof[i][:]) } return &Sidecar{ Index: strconv.FormatUint(sc.Index, 10), Blob: hex.EncodeBytes(sc.Blob[:]), KZGCommitment: hex.EncodeBytes(sc.KzgCommitment[:]), SignedBlockHeader: SignedBeaconBlockHeaderFromConsensus(sc.SignedBeaconBlockHeader), KZGProof: hex.EncodeBytes(sc.KzgProof[:]), KZGCommitmentInclusionProof: proofs, } } func ValidatorFromConsensus(v *ctypes.Validator) *Validator { return &Validator{ PublicKey: v.GetPubkey().String(), WithdrawalCredentials: v.GetWithdrawalCredentials().String(), EffectiveBalance: v.GetEffectiveBalance().Base10(), Slashed: v.IsSlashed(), ActivationEligibilityEpoch: v.GetActivationEligibilityEpoch().Base10(), ActivationEpoch: v.GetActivationEpoch().Base10(), ExitEpoch: v.GetExitEpoch().Base10(), WithdrawableEpoch: v.GetWithdrawableEpoch().Base10(), } } // useful in UTs func ValidatorToConsensus(v *Validator) (*ctypes.Validator, error) { pk, err := parser.ConvertPubkey(v.PublicKey) if err != nil { return nil, fmt.Errorf("failed parsing public key: %w", err) } wc, err := parser.ConvertWithdrawalCredentials(v.WithdrawalCredentials) if err != nil { return nil, fmt.Errorf("failed parsing withdrawals: %w", err) } eb, err := math.U64FromString(v.EffectiveBalance) if err != nil { return nil, fmt.Errorf("failed parsing effective balance: %w", err) } aee, err := math.U64FromString(v.ActivationEligibilityEpoch) if err != nil { return nil, fmt.Errorf("failed parsing activation eligibility epoch: %w", err) } ae, err := math.U64FromString(v.ActivationEpoch) if err != nil { return nil, fmt.Errorf("failed parsing activation epoch: %w", err) } ee, err := math.U64FromString(v.ExitEpoch) if err != nil { return nil, fmt.Errorf("failed parsing exit epoch: %w", err) } we, err := math.U64FromString(v.WithdrawableEpoch) if err != nil { return nil, fmt.Errorf("failed parsing withdrawable epoch: %w", err) } return &ctypes.Validator{ Pubkey: pk, WithdrawalCredentials: wc, EffectiveBalance: eb, Slashed: v.Slashed, ActivationEligibilityEpoch: aee, ActivationEpoch: ae, ExitEpoch: ee, WithdrawableEpoch: we, }, nil } ================================================ FILE: node-api/handlers/beacon/types/request.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-api/handlers/types" ) type GetGenesisRequest struct{} type GetStateRootRequest struct { types.StateIDRequest } type GetStateRequest struct { types.StateIDRequest } type GetStateForkRequest struct { types.StateIDRequest } type GetFinalityCheckpointsRequest struct { types.StateIDRequest } type GetPendingPartialWithdrawalsRequest struct { types.StateIDRequest } type GetStateValidatorsRequest struct { types.StateIDRequest IDs []string `query:"id" validate:"dive,validator_id"` Statuses []string `query:"status" validate:"dive,validator_status"` } type PostStateValidatorsRequest struct { types.StateIDRequest IDs []string `json:"ids" validate:"dive,validator_id"` Statuses []string `json:"statuses" validate:"dive,validator_status"` } type GetStateValidatorRequest struct { types.StateIDRequest ValidatorID string `param:"validator_id" validate:"required,validator_id"` } type GetValidatorBalancesRequest struct { types.StateIDRequest IDs []string `query:"id" validate:"dive,validator_id"` } type PostValidatorBalancesRequest struct { types.StateIDRequest IDs []string `json:"-" validate:"dive,validator_id"` } type GetStateCommitteesRequest struct { types.StateIDRequest EpochOptionalRequest CommitteeIndexRequest SlotRequest } type GetSyncCommitteesRequest struct { types.StateIDRequest EpochOptionalRequest } type GetRandaoRequest struct { types.StateIDRequest EpochOptionalRequest } type GetBlockHeadersRequest struct { SlotRequest ParentRoot string `query:"parent_root" validate:"omitempty,hex"` } type GetBlockHeaderRequest struct { types.BlockIDRequest } type PostBlindedBlocksV1Request struct { EthConsensusVersion string `json:"eth_consensus_version" validate:"required,eth_consensus_version"` } type PostBlindedBlocksV2Request struct { PostBlindedBlocksV1Request BroadcastValidation string `json:"broadcast_validation" validate:"required,broadcast_validation"` } type PostBlocksV1Request struct { EthConsensusVersion string `json:"eth_consensus_version" validate:"required,eth_consensus_version"` BeaconBlock ctypes.BeaconBlock `json:"beacon_block"` } type PostBlocksV2Request struct { PostBlocksV1Request BroadcastValidation string `json:"broadcast_validation" validate:"required,broadcast_validation"` } type GetBlocksRequest struct { types.BlockIDRequest } type GetBlockRootRequest struct { types.BlockIDRequest } type GetBlockAttestationsRequest struct { types.BlockIDRequest } type GetBlobSidecarsRequest struct { types.BlockIDRequest Indices []string `query:"indices" validate:"dive,numeric"` } type PostRewardsSyncCommitteeRequest struct { types.BlockIDRequest IDs []string `validate:"dive,validator_id"` } type GetDepositTreeSnapshotRequest struct{} type GetBlockRewardsRequest struct { types.BlockIDRequest } type PostAttestationsRewardsRequest struct { EpochRequest IDs []string `validate:"dive,validator_id"` } type GetBlindedBlockRequest struct { types.BlockIDRequest } type EpochOptionalRequest struct { Epoch string `query:"epoch" validate:"epoch"` } type EpochRequest struct { Epoch string `param:"epoch" validate:"required,epoch"` } type CommitteeIndexRequest struct { CommitteeIndex string `query:"committee_index" validate:"committee_index"` } type SlotRequest struct { Slot string `query:"slot" validate:"slot"` } type HeadersRequest struct { SlotRequest ParentRoot string `query:"parent_root" validate:"hex"` } ================================================ FILE: node-api/handlers/beacon/types/response.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/version" ) type GenericResponse struct { ExecutionOptimistic bool `json:"execution_optimistic"` Finalized bool `json:"finalized"` Data any `json:"data"` } // NewResponse creates a new response with CometBFT's finality guarantees. func NewResponse(data any) GenericResponse { return GenericResponse{ // All data is finalized in CometBFT since we only return data for slots up to head Finalized: true, // Never optimistic since we only return finalized data ExecutionOptimistic: false, Data: data, } } type BlockResponse struct { Version string `json:"version"` GenericResponse } type StateResponse struct { Version string `json:"version"` ExecutionOptimistic bool `json:"execution_optimistic"` Finalized bool `json:"finalized"` Data any `json:"data"` } type BlockHeaderResponse struct { Root common.Root `json:"root"` Canonical bool `json:"canonical"` Header *SignedBeaconBlockHeader `json:"header"` } type BeaconBlockHeader struct { Slot string `json:"slot"` ProposerIndex string `json:"proposer_index"` ParentRoot string `json:"parent_root"` StateRoot string `json:"state_root"` BodyRoot string `json:"body_root"` } type SignedBeaconBlockHeader struct { Message *BeaconBlockHeader `json:"message"` Signature string `json:"signature"` } type GenesisData struct { GenesisTime string `json:"genesis_time"` GenesisValidatorsRoot common.Root `json:"genesis_validators_root"` GenesisForkVersion string `json:"genesis_fork_version"` } // GenesisResponse is handled with this explicit response type since // "finalized" and "execution_optimistic" are not part of the return value. // // https://ethereum.github.io/beacon-APIs/#/Beacon/getGenesis type GenesisResponse struct { Data GenesisData `json:"data"` } type RootData struct { Root common.Root `json:"root"` } type ValidatorData struct { ValidatorBalanceData Status string `json:"status"` Validator *Validator `json:"validator"` } type ValidatorBalanceData struct { Index uint64 `json:"index,string"` Balance uint64 `json:"balance,string"` } // Validator is the spec representation of the struct. type Validator struct { PublicKey string `json:"pubkey"` WithdrawalCredentials string `json:"withdrawal_credentials"` EffectiveBalance string `json:"effective_balance"` Slashed bool `json:"slashed"` ActivationEligibilityEpoch string `json:"activation_eligibility_epoch"` ActivationEpoch string `json:"activation_epoch"` ExitEpoch string `json:"exit_epoch"` WithdrawableEpoch string `json:"withdrawable_epoch"` } //nolint:staticcheck // todo: figure this out. type CommitteeData struct { Index uint64 `json:"index,string"` Slot uint64 `json:"slot,string"` Validators []uint64 `json:"validators,string"` } type BlockRewardsData struct { ProposerIndex uint64 `json:"proposer_index,string"` Total uint64 `json:"total,string"` Attestations uint64 `json:"attestations,string"` SyncAggregate uint64 `json:"sync_aggregate,string"` ProposerSlashings uint64 `json:"proposer_slashings,string"` AttesterSlashings uint64 `json:"attester_slashings,string"` } type Sidecar struct { Index string `json:"index"` Blob string `json:"blob"` KZGCommitment string `json:"kzg_commitment"` KZGProof string `json:"kzg_proof"` SignedBlockHeader *SignedBeaconBlockHeader `json:"signed_block_header"` KZGCommitmentInclusionProof []string `json:"kzg_commitment_inclusion_proof"` } type SidecarsResponse struct { Data []*Sidecar `json:"data"` } // PendingPartialWithdrawalsResponse has a version field to indicate the fork version. // https://ethereum.github.io/beacon-APIs/#/Beacon/getPendingPartialWithdrawals type PendingPartialWithdrawalsResponse struct { Version string `json:"version"` GenericResponse } type PendingPartialWithdrawalData struct { ValidatorIndex uint64 `json:"validator_index,string"` Amount uint64 `json:"amount,string"` WithdrawalEpoch uint64 `json:"withdrawal_epoch,string"` } // NewPendingPartialWithdrawalsResponse creates a typed response with PendingPartialWithdrawal data func NewPendingPartialWithdrawalsResponse( forkVersion common.Version, withdrawals []*PendingPartialWithdrawalData, ) PendingPartialWithdrawalsResponse { return PendingPartialWithdrawalsResponse{ // Version is the name of the fork version. Version: version.Name(forkVersion), GenericResponse: NewResponse(withdrawals), } } ================================================ FILE: node-api/handlers/beacon/validators.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "errors" "fmt" "cosmossdk.io/collections" "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" types "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" ) func (h *Handler) GetStateValidators(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetStateValidatorsRequest]( c, h.Logger(), ) if err != nil { return nil, err } height, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } filteredVals, err := h.FilterValidators(height, req.IDs, req.Statuses) if err != nil { return nil, fmt.Errorf("failed to filter validators: %w", err) } return beacontypes.NewResponse(filteredVals), nil } func (h *Handler) PostStateValidators(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.PostStateValidatorsRequest]( c, h.Logger(), ) if err != nil { return nil, err } height, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } filteredVals, err := h.FilterValidators(height, req.IDs, req.Statuses) if err != nil { return nil, fmt.Errorf("failed to filter validators: %w", err) } return beacontypes.NewResponse(filteredVals), nil } func (h *Handler) GetStateValidator(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetStateValidatorRequest]( c, h.Logger(), ) if err != nil { return nil, err } height, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } valData, err := h.getValidator(height, req.ValidatorID) if err != nil { return nil, err } return beacontypes.NewResponse(valData), err } // getValidator contains all the logic of the GetStateValidator api // that is not related to http stuff. Consider exporting it if needed func (h *Handler) getValidator(height int64, validatorID string) (*beacontypes.ValidatorData, error) { st, resolvedSlot, err := h.backend.StateAndSlotFromHeight(height) if err != nil { return nil, fmt.Errorf("failed to get state from height %d: %w", height, err) } // retrieve validator data index, err := validatorIndexByID(st, validatorID) if err != nil { if errors.Is(err, collections.ErrNotFound) { // this should happen when validatorID is an unknown pub key return nil, fmt.Errorf("%s: %w", err.Error(), types.ErrNotFound) } return nil, fmt.Errorf("failed to get validator index by id %s: %w", validatorID, err) } validator, err := st.ValidatorByIndex(index) if err != nil { // this should happen when validatorID is an unknown index if errors.Is(err, collections.ErrNotFound) { return nil, fmt.Errorf("%s: %w", err.Error(), types.ErrNotFound) } return nil, fmt.Errorf("failed to get validator by index %s: %w", validatorID, err) } balance, err := st.GetBalance(index) if err != nil { return nil, fmt.Errorf( "failed to get validator balance for validator pubkey %s and index %d: %w", validator.GetPubkey(), index, err, ) } status, err := validator.Status(h.cs.SlotToEpoch(resolvedSlot)) if err != nil { return nil, fmt.Errorf("failed to get validator status for validator pubkey %s and index %d: %w", validator.GetPubkey(), index, err) } return &beacontypes.ValidatorData{ ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: index.Unwrap(), Balance: balance.Unwrap(), }, Status: status, Validator: beacontypes.ValidatorFromConsensus(validator), }, nil } ================================================ FILE: node-api/handlers/beacon/validators_balances.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "fmt" "cosmossdk.io/collections" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-api/backend" "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" ) func (h *Handler) GetStateValidatorBalances(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetValidatorBalancesRequest]( c, h.Logger(), ) if err != nil { return nil, err } height, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } balances, err := h.getValidatorBalance(height, req.IDs) if err != nil { return nil, err } return beacontypes.NewResponse(balances), nil } func (h *Handler) PostStateValidatorBalances(c handlers.Context) (any, error) { var ids []string if err := c.Bind(&ids); err != nil { return nil, fmt.Errorf("%s: %w", err.Error(), types.ErrInvalidRequest) } // Get state_id from URL path parameter req := beacontypes.PostValidatorBalancesRequest{ StateIDRequest: types.StateIDRequest{StateID: c.Param("state_id")}, IDs: ids, } if err := c.Validate(&req); err != nil { return nil, types.ErrInvalidRequest } height, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } balances, err := h.getValidatorBalance(height, req.IDs) if err != nil { return nil, err } return beacontypes.NewResponse(balances), nil } func (h *Handler) getValidatorBalance(height int64, validatorIDs []string) ([]*beacontypes.ValidatorBalanceData, error) { st, _, err := h.backend.StateAndSlotFromHeight(height) if err != nil { return nil, fmt.Errorf("failed to get state from height %d: %w", height, err) } // If no IDs provided, return all validator balances if len(validatorIDs) == 0 { rawBalances, errInBalances := st.GetBalances() if errInBalances != nil { return nil, errInBalances } // Convert []uint64 to []*ValidatorBalanceData as per the API spec balances := make([]*beacontypes.ValidatorBalanceData, len(rawBalances)) for i, balance := range rawBalances { balances[i] = &beacontypes.ValidatorBalanceData{ Index: uint64(i), // #nosec:G115 // Safe as i comes from range loop Balance: balance, } } return balances, nil } var ( balances = make([]*beacontypes.ValidatorBalanceData, 0, len(validatorIDs)) index math.U64 ) for _, id := range validatorIDs { index, err = validatorIndexByID(st, id) switch { case err == nil: // nothing to do, keep processing case errors.Is(err, collections.ErrNotFound): // If public key as id is not found in the state // we simply skip the index. continue default: return nil, fmt.Errorf("failed to get validator index by id %s: %w", id, err) } var balance math.U64 switch balance, err = st.GetBalance(index); { case err == nil: balances = append(balances, &beacontypes.ValidatorBalanceData{ Index: index.Unwrap(), Balance: balance.Unwrap(), }) case errors.Is(err, collections.ErrNotFound): // if index does not exist and GetBalance returns // "collections: not found" we simply skip the index. continue default: return nil, fmt.Errorf("failed to get validator balance for validator index %d: %w", index, err) } } return balances, nil } // ValidatorIndexByID parses a validator index from a string. // The string can be either a validator index or a validator pubkey. func validatorIndexByID(st backend.ReadOnlyBeaconState, keyOrIndex string) (math.U64, error) { index, err := math.U64FromString(keyOrIndex) if err == nil { return index, nil } var key crypto.BLSPubkey if err = key.UnmarshalText([]byte(keyOrIndex)); err != nil { return math.U64(0), err } return st.ValidatorIndexByPubkey(key) } ================================================ FILE: node-api/handlers/beacon/validators_balances_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon_test import ( "encoding/json" "net/http" "net/http/httptest" "strconv" "strings" "testing" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/beacon" "github.com/berachain/beacon-kit/node-api/handlers/beacon/mocks" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/math" "github.com/labstack/echo/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestGetStateValidatorBalances(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) // Create some input validators and store them to a readonly state stateValidators := createStateValidators(cs) testCases := []struct { name string inputs func() (beacontypes.GetValidatorBalancesRequest, beacontypes.PostValidatorBalancesRequest) setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "all validators", inputs: func() (beacontypes.GetValidatorBalancesRequest, beacontypes.PostValidatorBalancesRequest) { stateID := utils.StateIDHead IDs := []string(nil) return beacontypes.GetValidatorBalancesRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, IDs: IDs, }, beacontypes.PostValidatorBalancesRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, IDs: IDs, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []*beacontypes.ValidatorBalanceData{}, gr.Data) data, _ := gr.Data.([]*beacontypes.ValidatorBalanceData) expectedBalances := make([]*beacontypes.ValidatorBalanceData, 0, len(stateValidators)) for _, val := range stateValidators { expectedBalances = append(expectedBalances, &beacontypes.ValidatorBalanceData{ Index: val.Index, Balance: val.Balance, }, ) } require.Equal(t, expectedBalances, data) }, }, { name: "single validators", inputs: func() (beacontypes.GetValidatorBalancesRequest, beacontypes.PostValidatorBalancesRequest) { stateID := utils.StateIDHead IDs := []string{ stateValidators[0].Validator.PublicKey, stateValidators[1].Validator.PublicKey, } return beacontypes.GetValidatorBalancesRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, IDs: IDs, }, beacontypes.PostValidatorBalancesRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, IDs: IDs, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []*beacontypes.ValidatorBalanceData{}, gr.Data) data, _ := gr.Data.([]*beacontypes.ValidatorBalanceData) expectedBalances := []*beacontypes.ValidatorBalanceData{ { Index: stateValidators[0].Index, Balance: stateValidators[0].Balance, }, { Index: stateValidators[1].Index, Balance: stateValidators[1].Balance, }, } require.Equal(t, expectedBalances, data) }, }, { name: "mixed know and unknow validators", inputs: func() (beacontypes.GetValidatorBalancesRequest, beacontypes.PostValidatorBalancesRequest) { stateID := utils.StateIDHead unknownValPk := bytes.B48{0xff, 0xff} unknownValIdx := strconv.Itoa(2025) IDs := []string{ unknownValIdx, stateValidators[0].Validator.PublicKey, unknownValPk.String(), } return beacontypes.GetValidatorBalancesRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, IDs: IDs, }, beacontypes.PostValidatorBalancesRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, IDs: IDs, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []*beacontypes.ValidatorBalanceData{}, gr.Data) data, _ := gr.Data.([]*beacontypes.ValidatorBalanceData) expectedBalances := []*beacontypes.ValidatorBalanceData{ { Index: stateValidators[0].Index, Balance: stateValidators[0].Balance, }, } require.Equal(t, expectedBalances, data) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // set expectations tc.setMockExpectations(backend) inputGet, inputPost := tc.inputs() { // Test Get method inputBytes, err := json.Marshal(inputGet) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodGet, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // test Get res, err := h.GetStateValidatorBalances(c) // check Get tc.check(t, res, err) } { // Test Post method // Marshal only the IDs array for the POST body inputBytes, err := json.Marshal(inputPost.IDs) require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodPost, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // Set the state_id as a URL path parameter c.SetParamNames("state_id") c.SetParamValues(inputPost.StateID) // test Post res, err := h.PostStateValidatorBalances(c) // check Post tc.check(t, res, err) } }) } } ================================================ FILE: node-api/handlers/beacon/validators_filters.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "fmt" "slices" consensustypes "github.com/berachain/beacon-kit/consensus-types/types" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-api/backend" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // errStatusFilterMismatch is an error for when a validator status does not // match the status filter. var errStatusFilterMismatch = errors.New("validator status does not match status filter") // FilterValidators is a helper function to provide implementation // consistency between GetStateValidators and PostStateValidators, since they // are intended to behave the same way. func (h *Handler) FilterValidators(height int64, ids []string, statuses []string) ([]*beacontypes.ValidatorData, error) { st, resolvedSlot, err := h.backend.StateAndSlotFromHeight(height) if err != nil { if errors.Is(err, cometbft.ErrAppNotReady) { // chain not ready, like when genesis time is set in the future return nil, handlertypes.ErrNotFound } if errors.Is(err, sdkerrors.ErrInvalidHeight) { // height requested too high return nil, handlertypes.ErrNotFound } return nil, fmt.Errorf("failed to get state from height %d: %w", height, err) } allVals, err := st.GetValidators() if err != nil { return nil, fmt.Errorf("failed to get validators: %w", err) } // Parse all IDs and pubkeys once at the start filters := parseValidatorIDs(ids) epoch := h.cs.SlotToEpoch(resolvedSlot) return filterAndBuildValidatorData(st, allVals, filters, epoch, statuses) } type validatorFilters struct { indexes []uint64 pubkeys []crypto.BLSPubkey } // parseID attempts to parse a single ID as either a numeric ID or pubkey func (f *validatorFilters) parseID(id string) { // Try parsing as numeric ID first if index, err := math.U64FromString(id); err == nil { f.indexes = append(f.indexes, index.Unwrap()) return } // Try parsing as pubkey var pubkey crypto.BLSPubkey if err := pubkey.UnmarshalText([]byte(id)); err == nil { f.pubkeys = append(f.pubkeys, pubkey) } // We can skip errors here, since they should not happen. // We do validate these ids in ValidateValidatorID. } // parseValidatorIDs parses a slice of string IDs into numeric IDs and pubkeys func parseValidatorIDs(ids []string) *validatorFilters { filters := &validatorFilters{ indexes: make([]uint64, 0, len(ids)), pubkeys: make([]crypto.BLSPubkey, 0, len(ids)), } for _, id := range ids { filters.parseID(id) } return filters } // filterAndBuildValidatorData processes all validators and builds their data based on filters func filterAndBuildValidatorData( st backend.ReadOnlyBeaconState, validators []*consensustypes.Validator, filters *validatorFilters, epoch math.Epoch, statuses []string, ) ([]*beacontypes.ValidatorData, error) { validatorData := make([]*beacontypes.ValidatorData, 0, len(validators)) for _, validator := range validators { index, err := st.ValidatorIndexByPubkey(validator.GetPubkey()) if err != nil { return nil, errors.Wrapf(err, "failed to get validator index by pubkey %s", validator.GetPubkey()) } if !matchesFilters(validator, index, filters) { continue } data, err := buildValidatorData(st, validator, index, epoch, statuses) switch { case err == nil: validatorData = append(validatorData, data) case errors.Is(err, errStatusFilterMismatch): continue default: return nil, err } } return validatorData, nil } // matchesFilters checks if a validator matches the filters. func matchesFilters(validator *consensustypes.Validator, index math.U64, filters *validatorFilters) bool { // If no filters, accept all validators if len(filters.indexes) == 0 && len(filters.pubkeys) == 0 { return true } // Check numeric IDs if len(filters.indexes) > 0 && matchesIndex(index, filters.indexes) { return true } // Check pubkeys if len(filters.pubkeys) > 0 && matchesPubkey(validator, filters.pubkeys) { return true } return false } func matchesPubkey(validator *consensustypes.Validator, parsedPubkeys []crypto.BLSPubkey) bool { validatorPubkey := validator.GetPubkey() return slices.Contains(parsedPubkeys, validatorPubkey) } func matchesIndex(index math.U64, ids []uint64) bool { return slices.Contains(ids, index.Unwrap()) } func matchesStatusFilter(status string, statuses []string) bool { return len(statuses) == 0 || slices.Contains(statuses, status) } func buildValidatorData( st backend.ReadOnlyBeaconState, validator *consensustypes.Validator, index math.U64, epoch math.Epoch, statuses []string, ) (*beacontypes.ValidatorData, error) { status, err := validator.Status(epoch) if err != nil { return nil, errors.Wrapf(err, "failed to get validator status for validator pubkey %s and index %d", validator.GetPubkey(), index) } if !matchesStatusFilter(status, statuses) { return nil, errStatusFilterMismatch } balance, err := st.GetBalance(index) if err != nil { return nil, errors.Wrapf(err, "failed to get validator balance for validator pubkey %s and index %d", validator.GetPubkey(), index) } return &beacontypes.ValidatorData{ ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: index.Unwrap(), Balance: balance.Unwrap(), }, Status: status, Validator: beacontypes.ValidatorFromConsensus(validator), }, nil } ================================================ FILE: node-api/handlers/beacon/validators_filters_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon_test import ( "encoding/json" "net/http" "net/http/httptest" "strconv" "strings" "testing" cosmoslog "cosmossdk.io/log" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" ctypes "github.com/berachain/beacon-kit/consensus-types/types" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/beacon" "github.com/berachain/beacon-kit/node-api/handlers/beacon/mocks" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" statedb "github.com/berachain/beacon-kit/state-transition/core/state" statetransition "github.com/berachain/beacon-kit/testing/state-transition" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/labstack/echo/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) //nolint:maintidx // Testing multiple scenarios for Get and Post api in parallel func TestFilterValidators(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) // Create some input validators and store them to a readonly state stateValidators := createStateValidators(cs) testCases := []struct { name string inputs func() (beacontypes.GetStateValidatorsRequest, beacontypes.PostStateValidatorsRequest) setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "all validators", inputs: func() (beacontypes.GetStateValidatorsRequest, beacontypes.PostStateValidatorsRequest) { stateID := utils.StateIDHead return beacontypes.GetStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, }, beacontypes.PostStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []*beacontypes.ValidatorData{}, gr.Data) data, _ := gr.Data.([]*beacontypes.ValidatorData) require.Len(t, data, len(stateValidators)) for i := range data { require.Equal(t, stateValidators[i], data[i], "index %d", i) } }, }, { name: "some validators by indexes", inputs: func() (beacontypes.GetStateValidatorsRequest, beacontypes.PostStateValidatorsRequest) { stateID := utils.StateIDHead IDs := []string{"1", "3"} return beacontypes.GetStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, IDs: IDs, Statuses: nil, }, beacontypes.PostStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: utils.StateIDHead, }, IDs: IDs, Statuses: nil, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []*beacontypes.ValidatorData{}, gr.Data) data, _ := gr.Data.([]*beacontypes.ValidatorData) expectedRes := []*beacontypes.ValidatorData{ stateValidators[1], stateValidators[3], } require.Len(t, data, len(expectedRes)) for i := range data { require.Equal(t, expectedRes[i], data[i], "index %d", i) } }, }, { name: "some validators by pub keys", inputs: func() (beacontypes.GetStateValidatorsRequest, beacontypes.PostStateValidatorsRequest) { stateID := utils.StateIDHead IDs := []string{ stateValidators[2].Validator.PublicKey, stateValidators[4].Validator.PublicKey, } return beacontypes.GetStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, IDs: IDs, }, beacontypes.PostStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: utils.StateIDHead, }, IDs: IDs, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []*beacontypes.ValidatorData{}, gr.Data) data, _ := gr.Data.([]*beacontypes.ValidatorData) expectedRes := []*beacontypes.ValidatorData{ stateValidators[2], stateValidators[4], } require.Len(t, data, len(expectedRes)) for i := range data { require.Equal(t, expectedRes[i], data[i], "index %d", i) } }, }, { name: "some validators by status", inputs: func() (beacontypes.GetStateValidatorsRequest, beacontypes.PostStateValidatorsRequest) { stateID := utils.StateIDHead statuses := []string{ constants.ValidatorStatusActiveOngoing, constants.ValidatorStatusActiveSlashed, constants.ValidatorStatusActiveExiting, } return beacontypes.GetStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, Statuses: statuses, }, beacontypes.PostStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, Statuses: statuses, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, []*beacontypes.ValidatorData{}, gr.Data) data, _ := gr.Data.([]*beacontypes.ValidatorData) expectedRes := []*beacontypes.ValidatorData{ stateValidators[2], stateValidators[3], stateValidators[4], } require.Len(t, data, len(expectedRes)) for i := range data { require.Equal(t, expectedRes[i], data[i], "index %d", i) } }, }, { name: "chain not ready", inputs: func() (beacontypes.GetStateValidatorsRequest, beacontypes.PostStateValidatorsRequest) { stateID := utils.StateIDHead return beacontypes.GetStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, }, beacontypes.PostStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: stateID, }, } }, setMockExpectations: func(b *mocks.Backend) { // cometbft.ErrAppNotReady is the error flag returned when // genesis has not yet been processed and chain is not ready. b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(nil, math.Slot(0), cometbft.ErrAppNotReady) }, check: func(t *testing.T, res any, err error) { t.Helper() // handlertypes.ErrNotFound is the error flag used to return 404 error code require.ErrorIs(t, err, handlertypes.ErrNotFound) require.Nil(t, res) }, }, { name: "height requested too high", inputs: func() (beacontypes.GetStateValidatorsRequest, beacontypes.PostStateValidatorsRequest) { unknownStateID := strconv.Itoa(2025) return beacontypes.GetStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: unknownStateID, }, }, beacontypes.PostStateValidatorsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: unknownStateID, }, } }, setMockExpectations: func(b *mocks.Backend) { // sdkerrors.ErrInvalidHeight is the error flag returned when // requested height is not in the state. b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(nil, math.Slot(0), sdkerrors.ErrInvalidHeight) }, check: func(t *testing.T, res any, err error) { t.Helper() // handlertypes.ErrNotFound is the error flag used to return 404 error code require.ErrorIs(t, err, handlertypes.ErrNotFound) require.Nil(t, res) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // set expectations tc.setMockExpectations(backend) inputGet, inputPost := tc.inputs() { // Test Get method inputBytes, err := json.Marshal(inputGet) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodGet, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // test Get res, err := h.GetStateValidators(c) // check Get tc.check(t, res, err) } { // Test Post method // create Post inputs inputBytes, err := json.Marshal(inputPost) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodPost, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // test Post res, err := h.PostStateValidators(c) // check Post tc.check(t, res, err) } }) } } func createStateValidators(cs chain.Spec) []*beacontypes.ValidatorData { return []*beacontypes.ValidatorData{ { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 0, Balance: cs.MaxEffectiveBalance().Unwrap(), }, Status: constants.ValidatorStatusPendingInitialized, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x01}, WithdrawalCredentials: [32]byte{0x02}, EffectiveBalance: cs.MaxEffectiveBalance(), Slashed: false, ActivationEligibilityEpoch: constants.FarFutureEpoch, ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, ), }, { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 1, Balance: cs.MaxEffectiveBalance().Unwrap() * 3 / 4, }, Status: constants.ValidatorStatusPendingQueued, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x03}, WithdrawalCredentials: [32]byte{0x04}, EffectiveBalance: cs.MaxEffectiveBalance() / 2, Slashed: false, ActivationEligibilityEpoch: math.Epoch(0), ActivationEpoch: constants.FarFutureEpoch, ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, ), }, { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 2, Balance: cs.MaxEffectiveBalance().Unwrap() / 4, }, Status: constants.ValidatorStatusActiveOngoing, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x05}, WithdrawalCredentials: [32]byte{0x06}, EffectiveBalance: cs.MaxEffectiveBalance() / 3, Slashed: false, ActivationEligibilityEpoch: math.Epoch(0), ActivationEpoch: math.Epoch(0), ExitEpoch: constants.FarFutureEpoch, WithdrawableEpoch: constants.FarFutureEpoch, }, ), }, { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 3, Balance: cs.MaxEffectiveBalance().Unwrap() / 4, }, Status: constants.ValidatorStatusActiveSlashed, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x15}, WithdrawalCredentials: [32]byte{0x16}, EffectiveBalance: cs.MaxEffectiveBalance() / 3, Slashed: true, ActivationEligibilityEpoch: math.Epoch(0), ActivationEpoch: math.Epoch(0), ExitEpoch: math.Epoch(5), WithdrawableEpoch: constants.FarFutureEpoch, }, ), }, { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 4, Balance: cs.MaxEffectiveBalance().Unwrap() / 4, }, Status: constants.ValidatorStatusActiveExiting, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x17}, WithdrawalCredentials: [32]byte{0x18}, EffectiveBalance: cs.MaxEffectiveBalance() / 3, Slashed: false, ActivationEligibilityEpoch: math.Epoch(0), ActivationEpoch: math.Epoch(0), ExitEpoch: math.Epoch(5), WithdrawableEpoch: constants.FarFutureEpoch, }, ), }, { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 5, Balance: cs.MaxEffectiveBalance().Unwrap() / 2, }, Status: constants.ValidatorStatusExitedUnslashed, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x07}, WithdrawalCredentials: [32]byte{0x08}, EffectiveBalance: cs.MaxEffectiveBalance() / 4, Slashed: false, ActivationEligibilityEpoch: math.Epoch(0), ActivationEpoch: math.Epoch(0), ExitEpoch: math.Epoch(0), WithdrawableEpoch: constants.FarFutureEpoch, }, ), }, { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 6, Balance: cs.MaxEffectiveBalance().Unwrap() / 2, }, Status: constants.ValidatorStatusExitedSlashed, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x27}, WithdrawalCredentials: [32]byte{0x28}, EffectiveBalance: cs.MaxEffectiveBalance() / 4, Slashed: true, ActivationEligibilityEpoch: math.Epoch(0), ActivationEpoch: math.Epoch(0), ExitEpoch: math.Epoch(0), WithdrawableEpoch: constants.FarFutureEpoch, }, ), }, { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 7, Balance: cs.MinActivationBalance().Unwrap() - cs.EffectiveBalanceIncrement().Unwrap(), }, Status: constants.ValidatorStatusWithdrawalPossible, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x09}, WithdrawalCredentials: [32]byte{0x10}, EffectiveBalance: cs.MaxEffectiveBalance() / 5, Slashed: false, ActivationEligibilityEpoch: math.Epoch(0), ActivationEpoch: math.Epoch(0), ExitEpoch: math.Epoch(0), WithdrawableEpoch: math.Epoch(0), }, ), }, { ValidatorBalanceData: beacontypes.ValidatorBalanceData{ Index: 8, Balance: 0, }, Status: constants.ValidatorStatusWithdrawalPossible, Validator: beacontypes.ValidatorFromConsensus( &ctypes.Validator{ Pubkey: [48]byte{0x39}, WithdrawalCredentials: [32]byte{0x40}, EffectiveBalance: cs.MaxEffectiveBalance() / 5, Slashed: false, ActivationEligibilityEpoch: math.Epoch(0), ActivationEpoch: math.Epoch(0), ExitEpoch: math.Epoch(0), WithdrawableEpoch: math.Epoch(0), }, ), }, } } func addTestValidators(t *testing.T, stateValidators []*beacontypes.ValidatorData, st *statedb.StateDB) { t.Helper() for _, in := range stateValidators { val, errVal := beacontypes.ValidatorToConsensus(in.Validator) require.NoError(t, errVal) require.NoError(t, st.AddValidator(val)) require.NoError(t, st.SetBalance(math.ValidatorIndex(in.Index), math.Gwei(in.Balance))) } } func makeTestState(t *testing.T, cs chain.Spec) *statedb.StateDB { t.Helper() cms, kvStore, _, errSt := statetransition.BuildTestStores() require.NoError(t, errSt) sdkCtx := sdk.NewContext(cms.CacheMultiStore(), true, cosmoslog.NewNopLogger()) st := statedb.NewBeaconStateFromDB( kvStore.WithContext(sdkCtx), cs, sdkCtx.Logger(), metrics.NewNoOpTelemetrySink(), ) return st } ================================================ FILE: node-api/handlers/beacon/validators_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon_test import ( "encoding/json" "net/http" "net/http/httptest" "strconv" "strings" "testing" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/beacon" "github.com/berachain/beacon-kit/node-api/handlers/beacon/mocks" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/math" "github.com/labstack/echo/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestGetValidator(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) // Create some input validators and store them to a readonly state stateValidators := createStateValidators(cs) testCases := []struct { name string inputs func() beacontypes.GetStateValidatorRequest setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "get existing validator", inputs: func() beacontypes.GetStateValidatorRequest { return beacontypes.GetStateValidatorRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: utils.StateIDHead, }, ValidatorID: stateValidators[0].Validator.PublicKey, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.GenericResponse{}, res) gr, _ := res.(beacontypes.GenericResponse) require.IsType(t, &beacontypes.ValidatorData{}, gr.Data) data, _ := gr.Data.(*beacontypes.ValidatorData) require.Equal(t, stateValidators[0], data) }, }, { name: "get unknown validator - 1", inputs: func() beacontypes.GetStateValidatorRequest { unknownValIdx := strconv.Itoa(2025) return beacontypes.GetStateValidatorRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: utils.StateIDHead, }, ValidatorID: unknownValIdx, } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.ErrorIs(t, err, handlertypes.ErrNotFound) require.Nil(t, res) }, }, { name: "get unknown validator - 2", inputs: func() beacontypes.GetStateValidatorRequest { unknownValPk := bytes.B48{0xff, 0xff} return beacontypes.GetStateValidatorRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: utils.StateIDHead, }, ValidatorID: unknownValPk.String(), } }, setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) addTestValidators(t, stateValidators, st) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.ErrorIs(t, err, handlertypes.ErrNotFound) require.Nil(t, res) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // create API inputs input := tc.inputs() inputBytes, err := json.Marshal(input) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodGet, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // set expectations tc.setMockExpectations(backend) // test res, err := h.GetStateValidator(c) // finally do checks tc.check(t, res, err) }) } } ================================================ FILE: node-api/handlers/beacon/withdrawal.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon import ( "fmt" "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/version" ) func (h *Handler) GetPendingPartialWithdrawals(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetPendingPartialWithdrawalsRequest]( c, h.Logger(), ) if err != nil { return nil, err } // Load state for the requested state ID height, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } st, _, err := h.backend.StateAndSlotFromHeight(height) if err != nil { return nil, err } // Check withdrawal are active forkVersion, err := st.GetFork() if err != nil { return nil, err } if version.IsBefore(forkVersion.CurrentVersion, version.Electra()) { return nil, fmt.Errorf("%w: Electra fork not active yet", handlertypes.ErrInvalidRequest) } // Retrieve and return withdrawals cTypePartialWithdrawals, err := st.GetPendingPartialWithdrawals() if err != nil { return nil, fmt.Errorf("failed to get pending partial withdrawals from state: %w", err) } partialWithdrawals := make([]*beacontypes.PendingPartialWithdrawalData, len(cTypePartialWithdrawals)) for i, cTypeWithdrawal := range cTypePartialWithdrawals { partialWithdrawals[i] = &beacontypes.PendingPartialWithdrawalData{ ValidatorIndex: cTypeWithdrawal.ValidatorIndex.Unwrap(), Amount: cTypeWithdrawal.Amount.Unwrap(), WithdrawalEpoch: cTypeWithdrawal.WithdrawableEpoch.Unwrap(), } } return beacontypes.NewPendingPartialWithdrawalsResponse( forkVersion.CurrentVersion, partialWithdrawals, ), nil } ================================================ FILE: node-api/handlers/beacon/withdrawal_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacon_test import ( "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "github.com/berachain/beacon-kit/config/spec" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/beacon" "github.com/berachain/beacon-kit/node-api/handlers/beacon/mocks" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" handlertypes "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/labstack/echo/v4" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestGetPendingPartialWithdrawals(t *testing.T) { t.Parallel() cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) preElectraFork := &ctypes.Fork{ PreviousVersion: version.Capella(), CurrentVersion: version.Deneb(), Epoch: math.Epoch(200), } electraFork := &ctypes.Fork{ PreviousVersion: version.Deneb(), CurrentVersion: version.Electra(), Epoch: math.Epoch(200), } testPendingPartialWithdrawals := []*ctypes.PendingPartialWithdrawal{ { ValidatorIndex: 0, Amount: math.Gwei(1_000_000), WithdrawableEpoch: math.Epoch(1), }, { ValidatorIndex: 1, Amount: math.Gwei(999_999_999), WithdrawableEpoch: math.Epoch(2), }, } testCases := []struct { name string setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "post-Electra withdrawal requests present", setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) require.NoError(t, st.SetFork(electraFork)) require.NoError(t, st.SetPendingPartialWithdrawals(testPendingPartialWithdrawals)) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.PendingPartialWithdrawalsResponse{}, res) resp, _ := res.(beacontypes.PendingPartialWithdrawalsResponse) require.Equal(t, version.Name(electraFork.CurrentVersion), resp.Version) require.IsType(t, []*beacontypes.PendingPartialWithdrawalData{}, resp.GenericResponse.Data) data, _ := resp.GenericResponse.Data.([]*beacontypes.PendingPartialWithdrawalData) require.Len(t, data, len(testPendingPartialWithdrawals)) for i, w := range testPendingPartialWithdrawals { require.Equal(t, math.ValidatorIndex(data[i].ValidatorIndex), w.ValidatorIndex) require.Equal(t, math.Gwei(data[i].Amount), w.Amount) require.Equal(t, math.Epoch(data[i].WithdrawalEpoch), w.WithdrawableEpoch) } }, }, { name: "post-Electra withdrawal no requests", setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) require.NoError(t, st.SetFork(electraFork)) require.NoError(t, st.SetPendingPartialWithdrawals(nil)) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, beacontypes.PendingPartialWithdrawalsResponse{}, res) resp, _ := res.(beacontypes.PendingPartialWithdrawalsResponse) require.Equal(t, version.Name(electraFork.CurrentVersion), resp.Version) require.IsType(t, []*beacontypes.PendingPartialWithdrawalData{}, resp.GenericResponse.Data) data, _ := resp.GenericResponse.Data.([]*beacontypes.PendingPartialWithdrawalData) require.Empty(t, data) }, }, { name: "pre-Electra - error", setMockExpectations: func(b *mocks.Backend) { st := makeTestState(t, cs) require.NoError(t, st.SetFork(preElectraFork)) // slot is not really tested here, we just return zero b.EXPECT().StateAndSlotFromHeight(mock.Anything).Return(st, math.Slot(0), nil) }, check: func(t *testing.T, res any, err error) { t.Helper() require.ErrorIs(t, err, handlertypes.ErrInvalidRequest) require.Nil(t, res) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // setup test backend := mocks.NewBackend(t) h := beacon.NewHandler(backend, cs, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } // set expectations tc.setMockExpectations(backend) // create input input := beacontypes.GetPendingPartialWithdrawalsRequest{ StateIDRequest: handlertypes.StateIDRequest{ StateID: utils.StateIDGenesis, }, } inputBytes, err := json.Marshal(input) //nolint:musttag // TODO:fix require.NoError(t, err) body := strings.NewReader(string(inputBytes)) req := httptest.NewRequest(http.MethodGet, "/", body) req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) // otherwise code=415, message=Unsupported Media Type c := e.NewContext(req, httptest.NewRecorder()) // test res, err := h.GetPendingPartialWithdrawals(c) // check tc.check(t, res, err) }) } } ================================================ FILE: node-api/handlers/builder/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" ) type Handler struct { *handlers.BaseHandler logger log.Logger } func NewHandler(logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), logger: logger, } registerRoutes(h) return h } ================================================ FILE: node-api/handlers/builder/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodGet, Path: "/eth/v1/builder/states/:state_id/expected_withdrawals", Handler: h.Deprecated, }, }) } ================================================ FILE: node-api/handlers/cometbft/backend.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( cmttypes "github.com/cometbft/cometbft/types" ) // Backend is the interface for the CometBFT API backend. type Backend interface { // GetCometBFTBlock returns the CometBFT block at the given height. GetCometBFTBlock(height int64) *cmttypes.Block // GetCometBFTSignedHeader returns the CometBFT signed header (header + commit) at the given height. GetCometBFTSignedHeader(height int64) *cmttypes.SignedHeader } ================================================ FILE: node-api/handlers/cometbft/block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" ) // GetBlock returns the CometBFT block at the specified height. // GET /cometbft/v1/block/:height func (h *Handler) GetBlock(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[HeightRequest](c, h.Logger()) if err != nil { return nil, err } block := h.backend.GetCometBFTBlock(req.Height) if block == nil { return nil, errors.Wrapf(types.ErrNotFound, "block not found at height %d", req.Height) } return Response{Data: block}, nil } ================================================ FILE: node-api/handlers/cometbft/cometbft_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft_test import ( "encoding/json" "net/http" "net/http/httptest" "testing" "time" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" cometbftapi "github.com/berachain/beacon-kit/node-api/handlers/cometbft" "github.com/berachain/beacon-kit/node-api/handlers/cometbft/mocks" "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/middleware" cmtversion "github.com/cometbft/cometbft/api/cometbft/version/v1" cmttypes "github.com/cometbft/cometbft/types" "github.com/labstack/echo/v4" "github.com/stretchr/testify/require" ) func TestGetBlock(t *testing.T) { t.Parallel() testTime := time.Date(2024, 1, 26, 12, 0, 0, 0, time.UTC) testBlock := &cmttypes.Block{ Header: cmttypes.Header{ Version: cmtversion.Consensus{Block: 11, App: 0}, ChainID: "test-chain", Height: 100, Time: testTime, LastBlockID: cmttypes.BlockID{ Hash: []byte("prev-block-hash"), PartSetHeader: cmttypes.PartSetHeader{ Total: 1, Hash: []byte("part-set-hash"), }, }, LastCommitHash: []byte("last-commit-hash"), DataHash: []byte("data-hash"), ValidatorsHash: []byte("validators-hash"), NextValidatorsHash: []byte("next-validators-hash"), ConsensusHash: []byte("consensus-hash"), AppHash: []byte("app-hash"), LastResultsHash: []byte("last-results-hash"), EvidenceHash: []byte("evidence-hash"), ProposerAddress: []byte("proposer-address"), }, Data: cmttypes.Data{ Txs: []cmttypes.Tx{ []byte("transaction-1"), []byte("transaction-2"), }, }, Evidence: cmttypes.EvidenceData{ Evidence: []cmttypes.Evidence{}, }, LastCommit: &cmttypes.Commit{ Height: 99, Round: 0, BlockID: cmttypes.BlockID{ Hash: []byte("prev-block-hash"), PartSetHeader: cmttypes.PartSetHeader{ Total: 1, Hash: []byte("part-set-hash"), }, }, Signatures: []cmttypes.CommitSig{ { BlockIDFlag: cmttypes.BlockIDFlagCommit, ValidatorAddress: []byte("validator-1"), Timestamp: testTime, Signature: []byte("signature-1"), }, }, }, } testCases := []struct { name string height string setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "success", height: "100", setMockExpectations: func(b *mocks.Backend) { b.EXPECT().GetCometBFTBlock(int64(100)).Return(testBlock).Once() }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) respJSON, err := json.Marshal(res) require.NoError(t, err) var response cometbftapi.Response err = json.Unmarshal(respJSON, &response) require.NoError(t, err) require.NotNil(t, response.Data) dataJSON, err := json.Marshal(response.Data) require.NoError(t, err) var blockData cmttypes.Block err = json.Unmarshal(dataJSON, &blockData) require.NoError(t, err) require.Equal(t, "test-chain", blockData.Header.ChainID) require.Equal(t, int64(100), blockData.Header.Height) require.Len(t, blockData.Data.Txs, 2) }, }, { name: "not found", height: "999999", setMockExpectations: func(b *mocks.Backend) { b.EXPECT().GetCometBFTBlock(int64(999999)).Return(nil).Once() }, check: func(t *testing.T, res any, err error) { t.Helper() require.Error(t, err) require.ErrorIs(t, err, types.ErrNotFound) require.Contains(t, err.Error(), "block not found") require.Nil(t, res) }, }, { name: "invalid height - non-numeric", height: "abc", setMockExpectations: func(_ *mocks.Backend) {}, check: func(t *testing.T, res any, err error) { t.Helper() require.Error(t, err) require.Contains(t, err.Error(), "failed to bind request") require.Nil(t, res) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { backend := mocks.NewBackend(t) h := cometbftapi.NewHandler(backend, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } tc.setMockExpectations(backend) req := httptest.NewRequest(http.MethodGet, "/cometbft/v1/block/"+tc.height, nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) c.SetParamNames("height") c.SetParamValues(tc.height) result, err := h.GetBlock(c) tc.check(t, result, err) }) } } func TestGetSignedHeader(t *testing.T) { t.Parallel() testTime := time.Date(2024, 1, 26, 12, 0, 0, 0, time.UTC) testSignedHeader := &cmttypes.SignedHeader{ Header: &cmttypes.Header{ Version: cmtversion.Consensus{Block: 11, App: 0}, ChainID: "test-chain", Height: 100, Time: testTime, ProposerAddress: []byte("proposer-address"), LastBlockID: cmttypes.BlockID{ Hash: []byte("prev-block-hash"), PartSetHeader: cmttypes.PartSetHeader{ Total: 1, Hash: []byte("part-set-hash"), }, }, LastCommitHash: []byte("last-commit-hash"), DataHash: []byte("data-hash"), ValidatorsHash: []byte("validators-hash"), NextValidatorsHash: []byte("next-validators-hash"), ConsensusHash: []byte("consensus-hash"), AppHash: []byte("app-hash"), LastResultsHash: []byte("last-results-hash"), EvidenceHash: []byte("evidence-hash"), }, Commit: &cmttypes.Commit{ Height: 100, Round: 0, BlockID: cmttypes.BlockID{ Hash: []byte("block-hash"), PartSetHeader: cmttypes.PartSetHeader{ Total: 1, Hash: []byte("part-set-hash"), }, }, Signatures: []cmttypes.CommitSig{ { BlockIDFlag: cmttypes.BlockIDFlagCommit, ValidatorAddress: []byte("validator-1"), Timestamp: testTime, Signature: []byte("signature-1"), }, { BlockIDFlag: cmttypes.BlockIDFlagCommit, ValidatorAddress: []byte("validator-2"), Timestamp: testTime.Add(time.Millisecond * 100), Signature: []byte("signature-2"), }, }, }, } testCases := []struct { name string height string setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "success", height: "100", setMockExpectations: func(b *mocks.Backend) { b.EXPECT().GetCometBFTSignedHeader(int64(100)).Return(testSignedHeader).Once() }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) respJSON, err := json.Marshal(res) require.NoError(t, err) var response cometbftapi.Response err = json.Unmarshal(respJSON, &response) require.NoError(t, err) dataJSON, err := json.Marshal(response.Data) require.NoError(t, err) var signedHeaderData cmttypes.SignedHeader err = json.Unmarshal(dataJSON, &signedHeaderData) require.NoError(t, err) require.Equal(t, "test-chain", signedHeaderData.Header.ChainID) require.Equal(t, int64(100), signedHeaderData.Header.Height) require.Equal(t, int64(100), signedHeaderData.Commit.Height) require.Equal(t, int32(0), signedHeaderData.Commit.Round) require.Len(t, signedHeaderData.Commit.Signatures, 2) }, }, { name: "not found", height: "999999", setMockExpectations: func(b *mocks.Backend) { b.EXPECT().GetCometBFTSignedHeader(int64(999999)).Return(nil).Once() }, check: func(t *testing.T, res any, err error) { t.Helper() require.Error(t, err) require.ErrorIs(t, err, types.ErrNotFound) require.Contains(t, err.Error(), "signed header not found") require.Nil(t, res) }, }, { name: "invalid height - non-numeric", height: "abc", setMockExpectations: func(_ *mocks.Backend) {}, check: func(t *testing.T, res any, err error) { t.Helper() require.Error(t, err) require.Contains(t, err.Error(), "failed to bind request") require.Nil(t, res) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { backend := mocks.NewBackend(t) h := cometbftapi.NewHandler(backend, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } tc.setMockExpectations(backend) req := httptest.NewRequest(http.MethodGet, "/cometbft/v1/signed_header/"+tc.height, nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) c.SetParamNames("height") c.SetParamValues(tc.height) result, err := h.GetSignedHeader(c) tc.check(t, result, err) }) } } func TestGetBlock_FieldConversion(t *testing.T) { t.Parallel() testTime := time.Date(2024, 1, 26, 12, 0, 0, 123456789, time.UTC) block := &cmttypes.Block{ Header: cmttypes.Header{ Version: cmtversion.Consensus{Block: 11, App: 1}, ChainID: "test-chain-123", Height: 12345, Time: testTime, ProposerAddress: []byte("proposer"), }, Data: cmttypes.Data{ Txs: []cmttypes.Tx{[]byte("tx1"), []byte("tx2"), []byte("tx3")}, }, Evidence: cmttypes.EvidenceData{ Evidence: []cmttypes.Evidence{}, }, } backend := mocks.NewBackend(t) h := cometbftapi.NewHandler(backend, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } backend.EXPECT().GetCometBFTBlock(int64(12345)).Return(block).Once() req := httptest.NewRequest(http.MethodGet, "/cometbft/v1/block/12345", nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) c.SetParamNames("height") c.SetParamValues("12345") result, err := h.GetBlock(c) require.NoError(t, err) respJSON, err := json.Marshal(result) require.NoError(t, err) var response cometbftapi.Response err = json.Unmarshal(respJSON, &response) require.NoError(t, err) dataJSON, err := json.Marshal(response.Data) require.NoError(t, err) var blockData cmttypes.Block err = json.Unmarshal(dataJSON, &blockData) require.NoError(t, err) require.Equal(t, "test-chain-123", blockData.Header.ChainID) require.Equal(t, int64(12345), blockData.Header.Height) require.Equal(t, uint64(11), blockData.Header.Version.Block) require.Equal(t, uint64(1), blockData.Header.Version.App) require.Len(t, blockData.Data.Txs, 3) } func TestGetSignedHeader_MultipleSignatures(t *testing.T) { t.Parallel() testTime := time.Date(2024, 1, 26, 12, 0, 0, 0, time.UTC) signedHeader := &cmttypes.SignedHeader{ Header: &cmttypes.Header{ Version: cmtversion.Consensus{Block: 11, App: 0}, ChainID: "test-chain", Height: 100, Time: testTime, ProposerAddress: []byte("proposer"), }, Commit: &cmttypes.Commit{ Height: 100, Round: 2, BlockID: cmttypes.BlockID{ Hash: []byte("block-hash"), }, Signatures: []cmttypes.CommitSig{ { BlockIDFlag: cmttypes.BlockIDFlagCommit, ValidatorAddress: []byte("val1"), Timestamp: testTime, Signature: []byte("sig1"), }, { BlockIDFlag: cmttypes.BlockIDFlagAbsent, ValidatorAddress: []byte("val2"), Timestamp: testTime, Signature: nil, }, { BlockIDFlag: cmttypes.BlockIDFlagNil, ValidatorAddress: []byte("val3"), Timestamp: testTime, Signature: []byte("sig3"), }, }, }, } backend := mocks.NewBackend(t) h := cometbftapi.NewHandler(backend, noop.NewLogger[log.Logger]()) e := echo.New() e.Validator = &middleware.CustomValidator{ Validator: middleware.ConstructValidator(), } backend.EXPECT().GetCometBFTSignedHeader(int64(100)).Return(signedHeader).Once() req := httptest.NewRequest(http.MethodGet, "/cometbft/v1/signed_header/100", nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) c.SetParamNames("height") c.SetParamValues("100") result, err := h.GetSignedHeader(c) require.NoError(t, err) respJSON, err := json.Marshal(result) require.NoError(t, err) var response cometbftapi.Response err = json.Unmarshal(respJSON, &response) require.NoError(t, err) dataJSON, err := json.Marshal(response.Data) require.NoError(t, err) var signedHeaderData cmttypes.SignedHeader err = json.Unmarshal(dataJSON, &signedHeaderData) require.NoError(t, err) require.Equal(t, "test-chain", signedHeaderData.Header.ChainID) require.Equal(t, int64(100), signedHeaderData.Header.Height) require.Equal(t, int32(2), signedHeaderData.Commit.Round) require.Len(t, signedHeaderData.Commit.Signatures, 3) require.Equal(t, cmttypes.BlockIDFlagCommit, signedHeaderData.Commit.Signatures[0].BlockIDFlag) require.Equal(t, cmttypes.BlockIDFlagAbsent, signedHeaderData.Commit.Signatures[1].BlockIDFlag) require.Equal(t, cmttypes.BlockIDFlagNil, signedHeaderData.Commit.Signatures[2].BlockIDFlag) } ================================================ FILE: node-api/handlers/cometbft/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" ) // Handler is the handler for the CometBFT API. type Handler struct { *handlers.BaseHandler backend Backend } // NewHandler creates a new handler for the CometBFT API. func NewHandler(backend Backend, logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), backend: backend, } registerRoutes(h) return h } ================================================ FILE: node-api/handlers/cometbft/mocks/backend.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( cometbfttypes "github.com/cometbft/cometbft/types" mock "github.com/stretchr/testify/mock" ) // Backend is an autogenerated mock type for the Backend type type Backend struct { mock.Mock } type Backend_Expecter struct { mock *mock.Mock } func (_m *Backend) EXPECT() *Backend_Expecter { return &Backend_Expecter{mock: &_m.Mock} } // GetCometBFTBlock provides a mock function with given fields: height func (_m *Backend) GetCometBFTBlock(height int64) *cometbfttypes.Block { ret := _m.Called(height) if len(ret) == 0 { panic("no return value specified for GetCometBFTBlock") } var r0 *cometbfttypes.Block if rf, ok := ret.Get(0).(func(int64) *cometbfttypes.Block); ok { r0 = rf(height) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*cometbfttypes.Block) } } return r0 } // Backend_GetCometBFTBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCometBFTBlock' type Backend_GetCometBFTBlock_Call struct { *mock.Call } // GetCometBFTBlock is a helper method to define mock.On call // - height int64 func (_e *Backend_Expecter) GetCometBFTBlock(height interface{}) *Backend_GetCometBFTBlock_Call { return &Backend_GetCometBFTBlock_Call{Call: _e.mock.On("GetCometBFTBlock", height)} } func (_c *Backend_GetCometBFTBlock_Call) Run(run func(height int64)) *Backend_GetCometBFTBlock_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(int64)) }) return _c } func (_c *Backend_GetCometBFTBlock_Call) Return(_a0 *cometbfttypes.Block) *Backend_GetCometBFTBlock_Call { _c.Call.Return(_a0) return _c } func (_c *Backend_GetCometBFTBlock_Call) RunAndReturn(run func(int64) *cometbfttypes.Block) *Backend_GetCometBFTBlock_Call { _c.Call.Return(run) return _c } // GetCometBFTSignedHeader provides a mock function with given fields: height func (_m *Backend) GetCometBFTSignedHeader(height int64) *cometbfttypes.SignedHeader { ret := _m.Called(height) if len(ret) == 0 { panic("no return value specified for GetCometBFTSignedHeader") } var r0 *cometbfttypes.SignedHeader if rf, ok := ret.Get(0).(func(int64) *cometbfttypes.SignedHeader); ok { r0 = rf(height) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*cometbfttypes.SignedHeader) } } return r0 } // Backend_GetCometBFTSignedHeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCometBFTSignedHeader' type Backend_GetCometBFTSignedHeader_Call struct { *mock.Call } // GetCometBFTSignedHeader is a helper method to define mock.On call // - height int64 func (_e *Backend_Expecter) GetCometBFTSignedHeader(height interface{}) *Backend_GetCometBFTSignedHeader_Call { return &Backend_GetCometBFTSignedHeader_Call{Call: _e.mock.On("GetCometBFTSignedHeader", height)} } func (_c *Backend_GetCometBFTSignedHeader_Call) Run(run func(height int64)) *Backend_GetCometBFTSignedHeader_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(int64)) }) return _c } func (_c *Backend_GetCometBFTSignedHeader_Call) Return(_a0 *cometbfttypes.SignedHeader) *Backend_GetCometBFTSignedHeader_Call { _c.Call.Return(_a0) return _c } func (_c *Backend_GetCometBFTSignedHeader_Call) RunAndReturn(run func(int64) *cometbfttypes.SignedHeader) *Backend_GetCometBFTSignedHeader_Call { _c.Call.Return(run) return _c } // NewBackend creates a new instance of Backend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBackend(t interface { mock.TestingT Cleanup(func()) }) *Backend { mock := &Backend{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-api/handlers/cometbft/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodGet, Path: "/cometbft/v1/block/:height", Handler: h.GetBlock, }, { Method: http.MethodGet, Path: "/cometbft/v1/signed_header/:height", Handler: h.GetSignedHeader, }, }) } ================================================ FILE: node-api/handlers/cometbft/signed_header.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" ) // GetSignedHeader returns the CometBFT signed header (header + commit) at the specified height. // GET /cometbft/v1/signed_header/:height func (h *Handler) GetSignedHeader(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[HeightRequest](c, h.Logger()) if err != nil { return nil, err } signedHeader := h.backend.GetCometBFTSignedHeader(req.Height) if signedHeader == nil { return nil, errors.Wrapf(types.ErrNotFound, "signed header not found at height %d", req.Height) } return Response{Data: signedHeader}, nil } ================================================ FILE: node-api/handlers/cometbft/types.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cometbft // HeightRequest is a request type for CometBFT endpoints that accept a height parameter. type HeightRequest struct { Height int64 `param:"height" validate:"required,numeric"` } // Response wraps CometBFT data in a standard response envelope. type Response struct { Data any `json:"data"` } ================================================ FILE: node-api/handlers/config/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" ) type Handler struct { *handlers.BaseHandler cs chain.Spec } func NewHandler(cs chain.Spec, logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), cs: cs, } registerRoutes(h) return h } ================================================ FILE: node-api/handlers/config/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodGet, Path: "/eth/v1/config/fork_schedule", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/config/spec", Handler: h.GetSpec, }, { Method: http.MethodGet, Path: "/eth/v1/config/deposit_contract", Handler: h.NotImplemented, }, }) } ================================================ FILE: node-api/handlers/config/spec.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/config/types" "github.com/berachain/beacon-kit/primitives/math" ) // InactivityPenaltyQuotientPlaceholder is a placeholder value for the inactivity penalty quotient. const InactivityPenaltyQuotientPlaceholder = "0" // GetSpec returns the spec of the beacon chain. func (h *Handler) GetSpec(handlers.Context) (any, error) { return types.SpecResponse{Data: types.SpecData{ DepositContractAddress: h.cs.DepositContractAddress().String(), // Network ID is same as eth1 chain ID. DepositNetworkID: math.U64(h.cs.DepositEth1ChainID()).Base10(), DomainAggregateAndProof: h.cs.DomainTypeAggregateAndProof().String(), // Currently these are placeholders, will be replaced with the correct values for our // versions like Deneb, Deneb1 etc once we implement slashing for inactivity. InactivityPenaltyQuotient: InactivityPenaltyQuotientPlaceholder, InactivityPenaltyQuotientAltair: InactivityPenaltyQuotientPlaceholder, }}, nil } ================================================ FILE: node-api/handlers/config/types/response.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types type SpecResponse struct { Data SpecData `json:"data"` } type SpecData struct { DepositContractAddress string `json:"DEPOSIT_CONTRACT_ADDRESS"` DepositNetworkID string `json:"DEPOSIT_NETWORK_ID"` DomainAggregateAndProof string `json:"DOMAIN_AGGREGATE_AND_PROOF"` InactivityPenaltyQuotient string `json:"INACTIVITY_PENALTY_QUOTIENT"` InactivityPenaltyQuotientAltair string `json:"INACTIVITY_PENALTY_QUOTIENT_ALTAIR"` } ================================================ FILE: node-api/handlers/debug/backend.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package debug import ( "github.com/berachain/beacon-kit/node-api/backend" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) // Backend is the interface for backend of the debug API. type Backend interface { GetSlotByStateRoot(root common.Root) (math.Slot, error) StateAndSlotFromHeight(height int64) (backend.ReadOnlyBeaconState, math.Slot, error) } ================================================ FILE: node-api/handlers/debug/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package debug import ( "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" ) // Handler is the handler for the beacon API. type Handler struct { *handlers.BaseHandler backend Backend } // NewHandler creates a new handler for the beacon API. func NewHandler(backend Backend, logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), backend: backend, } registerRoutes(h) return h } ================================================ FILE: node-api/handlers/debug/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package debug import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodGet, Path: "/eth/v2/debug/beacon/states/:state_id", Handler: h.GetState, }, { Method: http.MethodGet, Path: "/eth/v2/debug/beacon/heads", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/debug/fork_choice", Handler: h.NotImplemented, }, }) } ================================================ FILE: node-api/handlers/debug/state.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package debug import ( "github.com/berachain/beacon-kit/node-api/handlers" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/version" ) func (h *Handler) GetState(c handlers.Context) (any, error) { req, err := utils.BindAndValidate[beacontypes.GetStateRequest]( c, h.Logger(), ) if err != nil { return nil, err } height, err := utils.StateIDToHeight(req.StateID, h.backend) if err != nil { return nil, err } // Get the raw state at the given slot. state, _, err := h.backend.StateAndSlotFromHeight(height) if err != nil { return nil, err } beaconState, err := state.GetMarshallable() if err != nil { return nil, err } // Get the fork version from the state. fork, err := state.GetFork() if err != nil { return nil, err } return beacontypes.StateResponse{ // All data is finalized in CometBFT since we only return data for slots up to head Finalized: true, // Never optimistic since we only return finalized data ExecutionOptimistic: false, Version: version.Name(fork.CurrentVersion), Data: beaconState, }, nil } ================================================ FILE: node-api/handlers/error.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package handlers import "fmt" // HTTPError represents an HTTP error response. type HTTPError struct { Code int `json:"code"` Message string `json:"message"` } // NewHTTPError creates a new HTTPError with a formatted message. func NewHTTPError(code int, message string, args ...any) *HTTPError { return &HTTPError{ Code: code, Message: fmt.Sprintf(message, args...), } } // Error implements the error interface. func (e *HTTPError) Error() string { return e.Message } // StatusCode returns the HTTP status code. func (e *HTTPError) StatusCode() int { return e.Code } ================================================ FILE: node-api/handlers/events/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package events import ( "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" ) type Handler struct { *handlers.BaseHandler } func NewHandler(logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), } registerRoutes(h) return h } ================================================ FILE: node-api/handlers/events/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package events import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodGet, Path: "/eth/v1/events", Handler: h.NotImplemented, }, }) } ================================================ FILE: node-api/handlers/handlers.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package handlers import ( "fmt" "github.com/berachain/beacon-kit/log" ) // BaseHandler is a base handler for all handlers. It abstracts the route set // and logger from the handler. type BaseHandler struct { routes *RouteSet logger log.Logger } // NewBaseHandler initializes a new base handler with the given routes and // logger. func NewBaseHandler(logger log.Logger) *BaseHandler { return &BaseHandler{ routes: &RouteSet{ Routes: make([]*Route, 0), // Must be set via AddRoutes, }, logger: logger, } } // NotImplemented is the handler for API endpoints that are defined in the Ethereum Beacon Node API // spec, but not yet implemented. func (b *BaseHandler) NotImplemented(c Context) (any, error) { endpoint := c.Request().URL.Path return nil, fmt.Errorf("endpoint %s is not yet implemented", endpoint) } // Deprecated handles deprecated API endpoints that are no longer supported according to the // Ethereum Beacon Node API spec. func (b *BaseHandler) Deprecated(c Context) (any, error) { endpoint := c.Request().URL.Path return nil, fmt.Errorf("endpoint %s is deprecated", endpoint) } // RouteSet returns the route set for the base handler. func (b *BaseHandler) RouteSet() *RouteSet { return b.routes } // Logger is used to access the logger for the base handler. func (b *BaseHandler) Logger() log.Logger { return b.logger } // AddRoutes adds the given slice of routes to the base handler. func (b *BaseHandler) AddRoutes(routes []*Route) { b.routes.Routes = append(b.routes.Routes, routes...) } ================================================ FILE: node-api/handlers/node/backend.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2024, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package node type Backend interface { GetSyncData() (latestHeight int64, syncToHeight int64) GetVersionData() ( appName, version, os, arch string, ) } ================================================ FILE: node-api/handlers/node/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package node import ( "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" ) type Handler struct { *handlers.BaseHandler backend Backend } func NewHandler(b Backend, logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), backend: b, } registerRoutes(h) return h } ================================================ FILE: node-api/handlers/node/mocks/backend.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import mock "github.com/stretchr/testify/mock" // Backend is an autogenerated mock type for the Backend type type Backend struct { mock.Mock } type Backend_Expecter struct { mock *mock.Mock } func (_m *Backend) EXPECT() *Backend_Expecter { return &Backend_Expecter{mock: &_m.Mock} } // GetSyncData provides a mock function with no fields func (_m *Backend) GetSyncData() (int64, int64) { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetSyncData") } var r0 int64 var r1 int64 if rf, ok := ret.Get(0).(func() (int64, int64)); ok { return rf() } if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() } else { r0 = ret.Get(0).(int64) } if rf, ok := ret.Get(1).(func() int64); ok { r1 = rf() } else { r1 = ret.Get(1).(int64) } return r0, r1 } // Backend_GetSyncData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSyncData' type Backend_GetSyncData_Call struct { *mock.Call } // GetSyncData is a helper method to define mock.On call func (_e *Backend_Expecter) GetSyncData() *Backend_GetSyncData_Call { return &Backend_GetSyncData_Call{Call: _e.mock.On("GetSyncData")} } func (_c *Backend_GetSyncData_Call) Run(run func()) *Backend_GetSyncData_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *Backend_GetSyncData_Call) Return(latestHeight int64, syncToHeight int64) *Backend_GetSyncData_Call { _c.Call.Return(latestHeight, syncToHeight) return _c } func (_c *Backend_GetSyncData_Call) RunAndReturn(run func() (int64, int64)) *Backend_GetSyncData_Call { _c.Call.Return(run) return _c } // GetVersionData provides a mock function with no fields func (_m *Backend) GetVersionData() (string, string, string, string) { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetVersionData") } var r0 string var r1 string var r2 string var r3 string if rf, ok := ret.Get(0).(func() (string, string, string, string)); ok { return rf() } if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() } else { r0 = ret.Get(0).(string) } if rf, ok := ret.Get(1).(func() string); ok { r1 = rf() } else { r1 = ret.Get(1).(string) } if rf, ok := ret.Get(2).(func() string); ok { r2 = rf() } else { r2 = ret.Get(2).(string) } if rf, ok := ret.Get(3).(func() string); ok { r3 = rf() } else { r3 = ret.Get(3).(string) } return r0, r1, r2, r3 } // Backend_GetVersionData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetVersionData' type Backend_GetVersionData_Call struct { *mock.Call } // GetVersionData is a helper method to define mock.On call func (_e *Backend_Expecter) GetVersionData() *Backend_GetVersionData_Call { return &Backend_GetVersionData_Call{Call: _e.mock.On("GetVersionData")} } func (_c *Backend_GetVersionData_Call) Run(run func()) *Backend_GetVersionData_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *Backend_GetVersionData_Call) Return(appName string, version string, os string, arch string) *Backend_GetVersionData_Call { _c.Call.Return(appName, version, os, arch) return _c } func (_c *Backend_GetVersionData_Call) RunAndReturn(run func() (string, string, string, string)) *Backend_GetVersionData_Call { _c.Call.Return(run) return _c } // NewBackend creates a new instance of Backend. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBackend(t interface { mock.TestingT Cleanup(func()) }) *Backend { mock := &Backend{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-api/handlers/node/node.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package node import ( "fmt" "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/node/types" ) // Syncing returns the syncing status of the beacon node. func (h *Handler) Syncing(handlers.Context) (any, error) { latestHeight, syncingToHeight := h.backend.GetSyncData() syncDistance := syncingToHeight - latestHeight response := &types.SyncingData{ HeadSlot: latestHeight, SyncDistance: syncDistance, // BeaconKit has two operation modes: syncing from genesis // and normal operations. Every block finalized is verified // by the EL so for every purpose IsSyncing is equivalent to syncDistance > 0 IsSyncing: syncDistance > 0, // BeaconKit always verifies blocks payload, whether // it is syncing or it's in normal operation mode. // So IsOptimistic is always false IsOptimistic: false, // BeaconKit fails to verify and finalize blocks if // the EL is not reachable, resulting in a panic state. // TODO: consider exposing the EL state here ELOffline: false, } return types.Wrap(response), nil } // Note: version comes from git describe (via the build process) // Git describe usually returns string like , which can be understood as follow: // - v1.2.3 → the most recent tag reachable from this commit // - 14 → number of commits since that tag // - g2414721 → the abbreviated commit hash, **with a leading g**. // That g stands for “git”. It’s a prefix Git uses to distinguish the commit hash from other possible identifiers. func (h *Handler) Version(handlers.Context) (any, error) { appName, version, os, arch := h.backend.GetVersionData() r := &types.VersionData{ Version: fmt.Sprintf("%s/%s (%s %s)", appName, version, os, arch, ), } return types.Wrap(r), nil } ================================================ FILE: node-api/handlers/node/node_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package node_test import ( "testing" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/handlers/node" "github.com/berachain/beacon-kit/node-api/handlers/node/mocks" "github.com/berachain/beacon-kit/node-api/handlers/node/types" "github.com/stretchr/testify/require" ) func TestNodeSyncing(t *testing.T) { t.Parallel() testCases := []struct { name string setMockExpectations func(*mocks.Backend) check func(t *testing.T, res any, err error) }{ { name: "syncing", setMockExpectations: func(b *mocks.Backend) { latestHeight := int64(2025) syncToHeight := int64(2026) b.EXPECT().GetSyncData().Return(latestHeight, syncToHeight).Once() }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, types.DataResponse{}, res) dr, _ := res.(types.DataResponse) require.IsType(t, &types.SyncingData{}, dr.Data) data, _ := dr.Data.(*types.SyncingData) latestHeight := int64(2025) // duplicated from setMockExpectations syncToHeight := int64(2026) // duplicated from setMockExpectations require.Equal(t, latestHeight, data.HeadSlot) require.Equal(t, syncToHeight-latestHeight, data.SyncDistance) require.True(t, data.IsSyncing) require.False(t, data.IsOptimistic) require.False(t, data.ELOffline) }, }, { name: "normal operations mode", setMockExpectations: func(b *mocks.Backend) { latestHeight := int64(1492) syncToHeight := int64(1492) b.EXPECT().GetSyncData().Return(latestHeight, syncToHeight).Once() }, check: func(t *testing.T, res any, err error) { t.Helper() require.NoError(t, err) require.NotNil(t, res) require.IsType(t, types.DataResponse{}, res) dr, _ := res.(types.DataResponse) require.IsType(t, &types.SyncingData{}, dr.Data) data, _ := dr.Data.(*types.SyncingData) latestHeight := int64(1492) // duplicated from setMockExpectations syncToHeight := int64(1492) // duplicated from setMockExpectations require.Equal(t, latestHeight, data.HeadSlot) require.Equal(t, syncToHeight-latestHeight, data.SyncDistance) require.False(t, data.IsSyncing) require.False(t, data.IsOptimistic) require.False(t, data.ELOffline) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() // setup test backend := mocks.NewBackend(t) h := node.NewHandler(backend, noop.NewLogger[log.Logger]()) tc.setMockExpectations(backend) // test res, err := h.Syncing(nil) // input does not matter here tc.check(t, res, err) }) } } func TestNodeVersion(t *testing.T) { t.Parallel() // setup test backend := mocks.NewBackend(t) h := node.NewHandler(backend, noop.NewLogger[log.Logger]()) var ( appName = "testing-beacond" version = "x.x.x-rc-14-gebeee824a" os = "theOs" arch = "theArch" ) backend.EXPECT().GetVersionData().Return(appName, version, os, arch).Once() // test res, err := h.Version(nil) // input does not matter here // checks require.NoError(t, err) require.NotNil(t, res) require.IsType(t, types.DataResponse{}, res) dr, _ := res.(types.DataResponse) require.IsType(t, &types.VersionData{}, dr.Data) data, _ := dr.Data.(*types.VersionData) require.Contains(t, data.Version, appName) require.Contains(t, data.Version, version) require.Contains(t, data.Version, os) require.Contains(t, data.Version, arch) } ================================================ FILE: node-api/handlers/node/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package node import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodGet, Path: "/eth/v1/node/identity", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/node/peers", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/node/peers/:peer_id", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/node/peer_count", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/node/version", Handler: h.Version, }, { Method: http.MethodGet, Path: "/eth/v1/node/syncing", Handler: h.Syncing, }, { Method: http.MethodGet, Path: "/eth/v1/node/health", Handler: h.NotImplemented, }, }) } ================================================ FILE: node-api/handlers/node/types/response.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "encoding/json" "strconv" ) type DataResponse struct { Data any `json:"data"` } func Wrap(data any) DataResponse { return DataResponse{ Data: data, } } type VersionData struct { Version string `json:"version"` } type SyncingData struct { HeadSlot int64 `json:"head_slot"` SyncDistance int64 `json:"sync_distance"` IsSyncing bool `json:"is_syncing"` IsOptimistic bool `json:"is_optimistic"` ELOffline bool `json:"el_offline"` } type syncingJSON struct { HeadSlot string `json:"head_slot"` SyncDistance string `json:"sync_distance"` IsSyncing bool `json:"is_syncing"` IsOptimistic bool `json:"is_optimistic"` ELOffline bool `json:"el_offline"` } func (s *SyncingData) MarshalJSON() ([]byte, error) { return json.Marshal(syncingJSON{ HeadSlot: strconv.FormatInt(s.HeadSlot, 10), SyncDistance: strconv.FormatInt(s.SyncDistance, 10), IsSyncing: s.IsSyncing, IsOptimistic: s.IsOptimistic, ELOffline: s.ELOffline, }) } ================================================ FILE: node-api/handlers/proof/backend.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package proof import ( "github.com/berachain/beacon-kit/node-api/backend" "github.com/berachain/beacon-kit/primitives/math" ) // Backend is the interface for backend of the proof API. type Backend interface { StateBackend GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) } type StateBackend interface { StateAndSlotFromHeight(height int64) (backend.ReadOnlyBeaconState, math.Slot, error) } ================================================ FILE: node-api/handlers/proof/block_proposer.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package proof import ( "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/node-api/handlers/proof/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" ) // GetBlockProposer returns the block proposer pubkey for the given timestamp // id along with a merkle proof that can be verified against the beacon block // root. It also returns the merkle proof of the proposer index. func (h *Handler) GetBlockProposer(c handlers.Context) (any, error) { params, err := utils.BindAndValidate[types.BlockProposerRequest](c, h.Logger()) if err != nil { return nil, err } slot, beaconState, blockHeader, err := h.resolveTimestampID(params.TimestampID) if err != nil { return nil, err } h.Logger().Info("Generating block proposer proofs", "slot", slot) // Generate the proof (along with the "correct" beacon block root to verify against) for the // proposer validator's pubkey. bsm, err := beaconState.GetMarshallable() if err != nil { return nil, err } pubkeyProof, beaconBlockRoot, err := merkle.ProveProposerPubkeyInBlock(blockHeader, bsm) if err != nil { return nil, err } // Generate the proof for the proposer index. proposerIndexProof, _, err := merkle.ProveProposerIndexInBlock(blockHeader) if err != nil { return nil, err } // Get the pubkey of the proposer validator. proposerValidator, err := beaconState.ValidatorByIndex(blockHeader.GetProposerIndex()) if err != nil { return nil, err } return types.BlockProposerResponse{ BeaconBlockHeader: blockHeader, BeaconBlockRoot: beaconBlockRoot, ValidatorPubkey: proposerValidator.GetPubkey(), ValidatorPubkeyProof: pubkeyProof, ProposerIndexProof: proposerIndexProof, }, nil } ================================================ FILE: node-api/handlers/proof/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package proof import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/backend" "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/math" ) // Handler is the handler for the proof API. type Handler struct { *handlers.BaseHandler backend Backend } // NewHandler creates a new handler for the proof API. func NewHandler(backend Backend, logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), backend: backend, } registerRoutes(h) return h } // Get the slot from the given input of timestamp id, beacon state, and beacon // block header for the resolved slot. func (h *Handler) resolveTimestampID(timestampID string) ( math.Slot, backend.ReadOnlyBeaconState, *ctypes.BeaconBlockHeader, error, ) { var ( beaconState backend.ReadOnlyBeaconState blockHeader *ctypes.BeaconBlockHeader slot math.Slot ) height, err := utils.TimestampIDToParentHeight(timestampID, h.backend) if err != nil { return 0, beaconState, blockHeader, err } beaconState, slot, err = h.backend.StateAndSlotFromHeight(height) if err != nil { return 0, beaconState, blockHeader, err } // Return after updating the state root in the block header. blockHeader, err = beaconState.GetLatestBlockHeader() if err != nil { return 0, beaconState, blockHeader, err } blockHeader.SetStateRoot(beaconState.HashTreeRoot()) return slot, beaconState, blockHeader, nil } ================================================ FILE: node-api/handlers/proof/merkle/beacon_state.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/merkle" ) // ProveBeaconStateInBlock generates a proof for the beacon state in the // beacon block. It uses the fastssz library to generate the proof. func ProveBeaconStateInBlock( bbh *ctypes.BeaconBlockHeader, verifyProof bool, ) ([]common.Root, error) { blockProofTree, err := bbh.GetTree() if err != nil { return nil, err } stateInBlockProof, err := blockProofTree.Prove(StateGIndexBlock) if err != nil { return nil, err } proof := make([]common.Root, len(stateInBlockProof.Hashes)) for i, hash := range stateInBlockProof.Hashes { proof[i] = common.NewRootFromBytes(hash) } if verifyProof { if err = verifyBeaconStateInBlock( bbh, proof, common.NewRootFromBytes(stateInBlockProof.Leaf), ); err != nil { return nil, err } } return proof, nil } // verifyBeaconStateInBlock verifies the beacon state proof in the block. // // TODO: verifying the proof is not absolutely necessary. func verifyBeaconStateInBlock( bbh *ctypes.BeaconBlockHeader, proof []common.Root, leaf common.Root, ) error { beaconRoot := bbh.HashTreeRoot() if !merkle.VerifyProof(beaconRoot, leaf, StateGIndexBlock, proof) { return errors.Wrapf( errors.New("beacon stateproof failed to verify against beacon root"), "beacon root: 0x%s", beaconRoot, ) } return nil } ================================================ FILE: node-api/handlers/proof/merkle/beacon_state_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) // TestProveBeaconStateInBlock tests the ProveBeaconStateInBlock function and // that the generated proof correctly verifies. func TestProveBeaconStateInBlock(t *testing.T) { t.Parallel() bbh := &types.BeaconBlockHeader{} testCases := []struct { name string slot math.Slot proposerIndex math.ValidatorIndex parentBlockRoot common.Root bodyRoot common.Root stateRoot common.Root expectedProofFile string }{ { name: "Empty block with non-empty state root", stateRoot: common.Root{1, 2, 3, 4, 5, 6, 7, 8, 9}, expectedProofFile: "empty_state_proof.json", }, { name: "Non-empty block with empty state root", slot: 4, proposerIndex: 5, parentBlockRoot: common.Root{1, 2, 3, 4, 5, 6, 7, 8, 9}, bodyRoot: common.Root{9, 8, 7, 6, 5, 4, 3, 2, 1}, expectedProofFile: "non_empty_state_proof.json", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { bbh.SetSlot(tc.slot) bbh.SetProposerIndex(tc.proposerIndex) bbh.SetParentBlockRoot(tc.parentBlockRoot) bbh.SetBodyRoot(tc.bodyRoot) bbh.SetStateRoot(tc.stateRoot) proof, err := merkle.ProveBeaconStateInBlock(bbh, true) require.NoError(t, err) expectedProof := ReadProofFromFile(t, tc.expectedProofFile) require.Equal(t, expectedProof, proof) }) } } ================================================ FILE: node-api/handlers/proof/merkle/generalized_indexes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( "fmt" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/version" ) const ( // ProposerIndexGIndexBlock is the generalized index of the proposer index in the beacon block. // This value remains consistent for all Deneb and Electra forks. ProposerIndexGIndexBlock = 9 // StateGIndexBlock is the generalized index of the beacon state in the beacon block. This // value remains consistent for all Deneb and Electra forks. StateGIndexBlock = 11 // ZeroValidatorPubkeyGIndexDenebState is the generalized index of the 0 // validator's pubkey in the beacon state in the Deneb forks. To get the // GIndex of the pubkey of validator at index n, the formula is: // GIndex = ZeroValidatorPubkeyGIndexDenebState + (ValidatorPubkeyGIndexOffset * n) ZeroValidatorPubkeyGIndexDenebState = 439804651110400 // ZeroValidatorPubkeyGIndexDenebBlock is the generalized index of the 0 // validator's pubkey in the beacon block in the Deneb forks. This is // calculated by concatenating the (ZeroValidatorPubkeyGIndexDenebState, StateGIndexBlock) // GIndices. To get the GIndex of the pubkey of validator at index n, the formula is: // GIndex = ZeroValidatorPubkeyGIndexDenebBlock + (ValidatorPubkeyGIndexOffset * n) ZeroValidatorPubkeyGIndexDenebBlock = 3254554418216960 // ValidatorGIndexOffset is the offset of a validator's GIndex. ValidatorGIndexOffset = 8 // ZeroValidatorPubkeyGIndexElectraState is the generalized index of the 0 // validator's pubkey in the beacon state in the Electra forks. To get the // GIndex of the pubkey of validator at index n, the formula is: // GIndex = ZeroValidatorPubkeyGIndexElectraState + (ValidatorPubkeyGIndexOffset * n) ZeroValidatorPubkeyGIndexElectraState = 721279627821056 // ZeroValidatorPubkeyGIndexElectraBlock is the generalized index of the 0 // validator's pubkey in the beacon block in the Electra forks. This is // calculated by concatenating the (ZeroValidatorPubkeyGIndexElectraState, StateGIndexBlock) // GIndices. To get the GIndex of the pubkey of validator at index n, the formula is: // GIndex = ZeroValidatorPubkeyGIndexElectraBlock + (ValidatorPubkeyGIndexOffset * n) ZeroValidatorPubkeyGIndexElectraBlock = 6350779162034176 // ZeroValidatoCredentialsGIndexElectraState is the generalized index of the 0 // validator's withdrawal credentials in the beacon state in the Electra forks. To get the // GIndex of the withdrawal credentials of validator at index n, the formula is: // GIndex = ZeroValidatorCredentialsGIndexElectraState + (ValidatorGIndexOffset * n) ZeroValidatorCredentialsGIndexElectraState = 721279627821057 // ZeroValidatorCredentialsGIndexElectraBlock is the generalized index of the 0 // validator's withdrawal credentials in the beacon block in the Electra forks. This is // calculated by concatenating the (ZeroValidatorCredentialsGIndexElectraState, StateGIndexBlock) // GIndices. To get the GIndex of the withdrawal credentials of validator at index n, the formula is: // GIndex = ZeroValidatorCredentialsGIndexElectraBlock + (ValidatorGIndexOffset * n) ZeroValidatorCredentialsGIndexElectraBlock = 6350779162034177 // ZeroValidatorBalanceGIndexElectraState is the generalized index of the 0-3 // validators' balances in the beacon state in the Electra forks. Balances are // packed 4 per leaf (uint64 values, 32 bytes per leaf). To get the GIndex of // the balance of validator at index n, the formula is: // GIndex = ZeroValidatorBalanceGIndexElectraState + (n / 4) ZeroValidatorBalanceGIndexElectraState = 23089744183296 // ZeroValidatorBalanceGIndexElectraBlock is the generalized index of the 0-3 // validators' balances in the beacon block in the Electra forks. This is // calculated by concatenating the (ZeroValidatorBalanceGIndexElectraState, StateGIndexBlock) // GIndices. To get the GIndex of the balance of validator at index n, the formula is: // GIndex = ZeroValidatorBalanceGIndexElectraBlock + (n / 4) ZeroValidatorBalanceGIndexElectraBlock = 199011604627456 // BalancesPerLeaf is the number of validator balances packed into a single leaf. BalancesPerLeaf = 4 ) // GetZeroValidatorPubkeyGIndexState determines the generalized index of the 0 // validator's pubkey in the beacon state based on the fork version. func GetZeroValidatorPubkeyGIndexState(forkVersion common.Version) (int, error) { if version.EqualsOrIsAfter(forkVersion, version.Electra()) { return ZeroValidatorPubkeyGIndexElectraState, nil } else if version.EqualsOrIsAfter(forkVersion, version.Deneb()) { return ZeroValidatorPubkeyGIndexDenebState, nil } return 0, fmt.Errorf("unsupported fork version: %s", forkVersion) } // GetZeroValidatorPubkeyGIndexBlock determines the generalized index of the 0 // validator's pubkey in the beacon block based on the fork version. func GetZeroValidatorPubkeyGIndexBlock(forkVersion common.Version) (uint64, error) { if version.EqualsOrIsAfter(forkVersion, version.Electra()) { return ZeroValidatorPubkeyGIndexElectraBlock, nil } else if version.EqualsOrIsAfter(forkVersion, version.Deneb()) { return ZeroValidatorPubkeyGIndexDenebBlock, nil } return 0, fmt.Errorf("unsupported fork version: %s", forkVersion) } // GetZeroValidatorCredentialsGIndexState determines the generalized // index of the 0-th validator's withdrawal credentials in the beacon state // based on the fork version. func GetZeroValidatorCredentialsGIndexState(forkVersion common.Version) (int, error) { if version.EqualsOrIsAfter(forkVersion, version.Electra()) { return ZeroValidatorCredentialsGIndexElectraState, nil } return 0, fmt.Errorf("unsupported fork version: %s", forkVersion) } // GetZeroValidatorCredentialsGIndexBlock determines the generalized // index of the 0-th validator's withdrawal credentials in the beacon block // based on the fork version. func GetZeroValidatorCredentialsGIndexBlock(forkVersion common.Version) (uint64, error) { if version.EqualsOrIsAfter(forkVersion, version.Electra()) { return ZeroValidatorCredentialsGIndexElectraBlock, nil } return 0, fmt.Errorf("unsupported fork version: %s", forkVersion) } // GetZeroValidatorBalanceGIndexState determines the generalized // index of the 0-3 validators' balances in the beacon state // based on the fork version. func GetZeroValidatorBalanceGIndexState(forkVersion common.Version) (int, error) { if version.EqualsOrIsAfter(forkVersion, version.Electra()) { return ZeroValidatorBalanceGIndexElectraState, nil } return 0, fmt.Errorf("unsupported fork version: %s", forkVersion) } // GetZeroValidatorBalanceGIndexBlock determines the generalized // index of the 0-3 validators' balances in the beacon block // based on the fork version. func GetZeroValidatorBalanceGIndexBlock(forkVersion common.Version) (uint64, error) { if version.EqualsOrIsAfter(forkVersion, version.Electra()) { return ZeroValidatorBalanceGIndexElectraBlock, nil } return 0, fmt.Errorf("unsupported fork version: %s", forkVersion) } ================================================ FILE: node-api/handlers/proof/merkle/generalized_indexes_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "fmt" "testing" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/encoding/ssz/schema" mlib "github.com/berachain/beacon-kit/primitives/merkle" "github.com/stretchr/testify/require" ) var ( beaconStateFieldsDeneb = []*schema.Field{ schema.NewField("GenesisValidatorsRoot", schema.B32()), schema.NewField("Slot", schema.U64()), schema.NewField("Fork", schema.DefineContainer( schema.NewField("PreviousVersion", schema.B4()), schema.NewField("CurrentVersion", schema.B4()), schema.NewField("Epoch", schema.U64()), )), schema.NewField("LatestBlockHeader", schema.DefineContainer( schema.NewField("Slot", schema.U64()), schema.NewField("ProposerIndex", schema.U64()), schema.NewField("ParentBlockRoot", schema.B32()), schema.NewField("StateRoot", schema.B32()), schema.NewField("BodyRoot", schema.B32()), )), schema.NewField("BlockRoots", schema.DefineList(schema.B32(), 8192)), schema.NewField("StateRoots", schema.DefineList(schema.B32(), 8192)), schema.NewField("Eth1Data", schema.DefineContainer( schema.NewField("DepositRoot", schema.B32()), schema.NewField("DepositCount", schema.U64()), schema.NewField("BlockHash", schema.B32()), )), schema.NewField("Eth1DepositIndex", schema.U64()), schema.NewField("LatestExecutionPayloadHeader", schema.DefineContainer( schema.NewField("ParentHash", schema.B32()), schema.NewField("FeeRecipient", schema.B20()), schema.NewField("StateRoot", schema.B32()), schema.NewField("ReceiptsRoot", schema.B32()), schema.NewField("LogsBloom", schema.B256()), schema.NewField("Random", schema.B32()), schema.NewField("Number", schema.U64()), schema.NewField("GasLimit", schema.U64()), schema.NewField("GasUsed", schema.U64()), schema.NewField("Timestamp", schema.U64()), schema.NewField("ExtraData", schema.DefineByteList(32)), schema.NewField("BaseFeePerGas", schema.U256()), schema.NewField("BlockHash", schema.B32()), schema.NewField("TransactionsRoot", schema.B32()), schema.NewField("WithdrawalsRoot", schema.B32()), schema.NewField("BlobGasUsed", schema.U64()), schema.NewField("ExcessBlobGas", schema.U64()), )), schema.NewField("Validators", schema.DefineList(schema.DefineContainer( schema.NewField("Pubkey", schema.B48()), schema.NewField("WithdrawalCredentials", schema.B32()), schema.NewField("EffectiveBalance", schema.U64()), schema.NewField("Slashed", schema.Bool()), schema.NewField("ActivationEligibilityEpoch", schema.U64()), schema.NewField("ActivationEpoch", schema.U64()), schema.NewField("ExitEpoch", schema.U64()), schema.NewField("WithdrawableEpoch", schema.U64()), ), constants.ValidatorsRegistryLimit)), schema.NewField( "Balances", schema.DefineList(schema.U64(), constants.ValidatorsRegistryLimit), ), schema.NewField("RandaoMixes", schema.DefineList(schema.B32(), 65536)), schema.NewField("NextWithdrawalIndex", schema.U64()), schema.NewField("NextWithdrawalValidatorIndex", schema.U64()), schema.NewField( "Slashings", schema.DefineList(schema.U64(), constants.ValidatorsRegistryLimit), ), schema.NewField("TotalSlashing", schema.U64()), } additionalBeaconStateFieldsElectra = []*schema.Field{ schema.NewField("PendingPartialWithdrawals", schema.DefineList(schema.DefineContainer( schema.NewField("ValidatorIndex", schema.U64()), schema.NewField("Amount", schema.U64()), schema.NewField("WithdrawableEpoch", schema.U64()), ), constants.PendingPartialWithdrawalsLimit)), } // beaconStateSchemaDeneb is the schema for the BeaconState struct in the Deneb forks. beaconStateSchemaDeneb = schema.DefineContainer(beaconStateFieldsDeneb...) // beaconStateSchemaElectra is the schema for the BeaconState struct in the Electra forks. beaconStateSchemaElectra = schema.DefineContainer( append(beaconStateFieldsDeneb, additionalBeaconStateFieldsElectra...)..., ) ) var ( // beaconHeaderSchemaDeneb is the schema for the BeaconBlockHeader in the Deneb forks, with the // SSZ expansion of StateRoot to use the BeaconState. beaconHeaderSchemaDeneb = schema.DefineContainer( schema.NewField("Slot", schema.U64()), schema.NewField("ProposerIndex", schema.U64()), schema.NewField("ParentRoot", schema.B32()), schema.NewField("State", beaconStateSchemaDeneb), schema.NewField("BodyRoot", schema.B32()), ) // beaconHeaderSchemaElectra is the schema for the BeaconBlockHeader in the Electra forks, with // the SSZ expansion of StateRoot to use the BeaconState. beaconHeaderSchemaElectra = schema.DefineContainer( schema.NewField("Slot", schema.U64()), schema.NewField("ProposerIndex", schema.U64()), schema.NewField("ParentRoot", schema.B32()), schema.NewField("State", beaconStateSchemaElectra), schema.NewField("BodyRoot", schema.B32()), ) ) // TestGIndexProposerIndex tests the generalized index of the proposer // index in the beacon block. func TestGIndexProposerIndex(t *testing.T) { t.Parallel() // Deneb forks. _, proposerIndexGIndexBlock, _, err := mlib.ObjectPath( "ProposerIndex", ).GetGeneralizedIndex(beaconHeaderSchemaDeneb) require.NoError(t, err) require.Equal( t, merkle.ProposerIndexGIndexBlock, int(proposerIndexGIndexBlock), ) // Electra forks. _, proposerIndexGIndexBlockElectra, _, err := mlib.ObjectPath( "ProposerIndex", ).GetGeneralizedIndex(beaconHeaderSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ProposerIndexGIndexBlock, int(proposerIndexGIndexBlockElectra), ) } // TestGIndicesValidatorPubkeyDeneb tests the generalized indices used by // beacon state proofs for validator pubkeys on the Deneb forks. func TestGIndicesValidatorPubkeyDeneb(t *testing.T) { t.Parallel() // GIndex of state in the block. _, stateGIndexBlock, _, err := mlib.ObjectPath( "State", ).GetGeneralizedIndex(beaconHeaderSchemaDeneb) require.NoError(t, err) require.Equal(t, merkle.StateGIndexBlock, int(stateGIndexBlock)) // GIndex of the 0 validator's pubkey in the state. _, zeroValidatorPubkeyGIndexState, _, err := mlib.ObjectPath( "Validators/0/Pubkey", ).GetGeneralizedIndex(beaconStateSchemaDeneb) require.NoError(t, err) require.Equal(t, merkle.ZeroValidatorPubkeyGIndexDenebState, int(zeroValidatorPubkeyGIndexState), ) // GIndex of the 0 validator's pubkey in the block. _, zeroValidatorPubkeyGIndexBlock, _, err := mlib.ObjectPath( "State/Validators/0/Pubkey", ).GetGeneralizedIndex(beaconHeaderSchemaDeneb) require.NoError(t, err) require.Equal(t, merkle.ZeroValidatorPubkeyGIndexDenebBlock, int(zeroValidatorPubkeyGIndexBlock), ) // Concatenation is consistent. concatValidatorPubkeyStateToBlock := mlib.GeneralizedIndices{ mlib.GeneralizedIndex(stateGIndexBlock), mlib.GeneralizedIndex(zeroValidatorPubkeyGIndexState), }.Concat() require.Equal(t, zeroValidatorPubkeyGIndexBlock, uint64(concatValidatorPubkeyStateToBlock), ) // GIndex offset of the next validator's pubkey. _, oneValidatorPubkeyGIndexState, _, err := mlib.ObjectPath( "Validators/1/Pubkey", ).GetGeneralizedIndex(beaconStateSchemaDeneb) require.NoError(t, err) require.Equal(t, merkle.ValidatorGIndexOffset, int(oneValidatorPubkeyGIndexState-zeroValidatorPubkeyGIndexState), ) } // TestGIndicesValidatorPubkeyElectra tests the generalized indices used by // beacon state proofs for validator pubkeys on the Electra forks. func TestGIndicesValidatorPubkeyElectra(t *testing.T) { t.Parallel() // GIndex of state in the block. _, stateGIndexBlock, _, err := mlib.ObjectPath( "State", ).GetGeneralizedIndex(beaconHeaderSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.StateGIndexBlock, int(stateGIndexBlock)) // GIndex of the 0 validator's pubkey in the state. _, zeroValidatorPubkeyGIndexState, _, err := mlib.ObjectPath( "Validators/0/Pubkey", ).GetGeneralizedIndex(beaconStateSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ZeroValidatorPubkeyGIndexElectraState, int(zeroValidatorPubkeyGIndexState), ) // GIndex of the 0 validator's pubkey in the block. _, zeroValidatorPubkeyGIndexBlock, _, err := mlib.ObjectPath( "State/Validators/0/Pubkey", ).GetGeneralizedIndex(beaconHeaderSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ZeroValidatorPubkeyGIndexElectraBlock, int(zeroValidatorPubkeyGIndexBlock), ) // Concatenation is consistent. concatValidatorPubkeyStateToBlock := mlib.GeneralizedIndices{ mlib.GeneralizedIndex(stateGIndexBlock), mlib.GeneralizedIndex(zeroValidatorPubkeyGIndexState), }.Concat() require.Equal(t, zeroValidatorPubkeyGIndexBlock, uint64(concatValidatorPubkeyStateToBlock), ) // GIndex offset of the next validator's pubkey. _, oneValidatorPubkeyGIndexState, _, err := mlib.ObjectPath( "Validators/1/Pubkey", ).GetGeneralizedIndex(beaconStateSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ValidatorGIndexOffset, int(oneValidatorPubkeyGIndexState-zeroValidatorPubkeyGIndexState), ) } func TestValidatorWithdrawalCredentialsGIndexElectra(t *testing.T) { t.Parallel() // GIndex of the 0 validator's withdrawal credentials in the state. _, zeroValidatorWithdrawalCredentialsGIndexState, _, err := mlib.ObjectPath( "Validators/0/WithdrawalCredentials", ).GetGeneralizedIndex(beaconStateSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ZeroValidatorCredentialsGIndexElectraState, int(zeroValidatorWithdrawalCredentialsGIndexState), ) // GIndex of the 0 validator's withdrawal credentials in the block. _, zeroValidatorWithdrawalCredentialsGIndexBlock, _, err := mlib.ObjectPath( "State/Validators/0/WithdrawalCredentials", ).GetGeneralizedIndex(beaconHeaderSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ZeroValidatorCredentialsGIndexElectraBlock, int(zeroValidatorWithdrawalCredentialsGIndexBlock), ) // Concatenation is consistent. concatValidatorWithdrawalCredentialsStateToBlock := mlib.GeneralizedIndices{ mlib.GeneralizedIndex(merkle.StateGIndexBlock), mlib.GeneralizedIndex(zeroValidatorWithdrawalCredentialsGIndexState), }.Concat() require.Equal(t, zeroValidatorWithdrawalCredentialsGIndexBlock, uint64(concatValidatorWithdrawalCredentialsStateToBlock), ) // GIndex offset of the next validator's withdrawal credentials. _, oneValidatorWithdrawalCredentialsGIndexState, _, err := mlib.ObjectPath( "Validators/1/WithdrawalCredentials", ).GetGeneralizedIndex(beaconStateSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ValidatorGIndexOffset, int(oneValidatorWithdrawalCredentialsGIndexState-zeroValidatorWithdrawalCredentialsGIndexState), ) } func TestValidatorBalanceGIndexElectra(t *testing.T) { t.Parallel() // GIndex of the 0 validator's balance in the state. _, zeroValidatorBalanceGIndexState, _, err := mlib.ObjectPath( "Balances/0", ).GetGeneralizedIndex(beaconStateSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ZeroValidatorBalanceGIndexElectraState, int(zeroValidatorBalanceGIndexState), ) // GIndex of the 0 validator's balance in the block. _, zeroValidatorBalanceGIndexBlock, _, err := mlib.ObjectPath( "State/Balances/0", ).GetGeneralizedIndex(beaconHeaderSchemaElectra) require.NoError(t, err) require.Equal(t, merkle.ZeroValidatorBalanceGIndexElectraBlock, int(zeroValidatorBalanceGIndexBlock), ) // Concatenation is consistent. concatValidatorBalanceStateToBlock := mlib.GeneralizedIndices{ mlib.GeneralizedIndex(merkle.StateGIndexBlock), mlib.GeneralizedIndex(zeroValidatorBalanceGIndexState), }.Concat() require.Equal(t, zeroValidatorBalanceGIndexBlock, uint64(concatValidatorBalanceStateToBlock), ) // Verify that balances 0-3 share the same GIndex (packed in same leaf) for i := range merkle.BalancesPerLeaf { path := fmt.Sprintf("Balances/%d", i) _, balanceGIndex, _, gIndexErr := mlib.ObjectPath(path).GetGeneralizedIndex(beaconStateSchemaElectra) require.NoError(t, gIndexErr) require.Equal(t, zeroValidatorBalanceGIndexState, balanceGIndex) } // GIndex offset of the next validator's balance. // Balances are packed 4 per leaf (uint64 values, 32 bytes per leaf) balance4Path := fmt.Sprintf("Balances/%d", merkle.BalancesPerLeaf) _, balanceGIndex4, _, err := mlib.ObjectPath(balance4Path).GetGeneralizedIndex(beaconStateSchemaElectra) require.NoError(t, err) require.Equal(t, 1, int(balanceGIndex4-zeroValidatorBalanceGIndexState)) balance8Path := fmt.Sprintf("Balances/%d", merkle.BalancesPerLeaf*2) _, balanceGIndex8, _, err := mlib.ObjectPath(balance8Path).GetGeneralizedIndex(beaconStateSchemaElectra) require.NoError(t, err) require.Equal(t, 1, int(balanceGIndex8-balanceGIndex4)) } ================================================ FILE: node-api/handlers/proof/merkle/merkle_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "encoding/json" "os" "path/filepath" "testing" "github.com/berachain/beacon-kit/primitives/common" "github.com/stretchr/testify/require" ) // ReadProofFromFile reads a proof from a JSON file in the testdata directory. func ReadProofFromFile(t *testing.T, filename string) []common.Root { t.Helper() path := filepath.Join("testdata", filename) data, err := os.ReadFile(path) require.NoError(t, err) var proof []common.Root err = json.Unmarshal(data, &proof) require.NoError(t, err) return proof } ================================================ FILE: node-api/handlers/proof/merkle/mock/beacon_state.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package mock import ( "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" ) // NewBeaconStateWith creates a new mock beacon state with only the given fork version, // slot, validators, execution number, and execution fee recipient populated. func NewBeaconStateWith( slot math.Slot, vals types.Validators, executionNumber math.U64, executionFeeRecipient common.ExecutionAddress, forkVersion common.Version, ) *types.BeaconState { // If no validators are provided, create an empty slice. if len(vals) == 0 { vals = make(types.Validators, 0) } // Create an empty execution payload header with the given execution number and fee recipient. execPayloadHeader := types.NewEmptyExecutionPayloadHeaderWithVersion(forkVersion) execPayloadHeader.Number = executionNumber execPayloadHeader.FeeRecipient = executionFeeRecipient bsm := types.NewEmptyBeaconStateWithVersion(forkVersion) bsm.Slot = slot bsm.GenesisValidatorsRoot = common.Root{} bsm.Fork = &types.Fork{} bsm.LatestBlockHeader = types.NewEmptyBeaconBlockHeader() bsm.BlockRoots = []common.Root{} bsm.StateRoots = []common.Root{} bsm.LatestExecutionPayloadHeader = execPayloadHeader bsm.Eth1Data = &types.Eth1Data{} bsm.Eth1DepositIndex = 0 bsm.Validators = vals bsm.Balances = []uint64{} bsm.RandaoMixes = []common.Bytes32{} bsm.NextWithdrawalIndex = 0 bsm.NextWithdrawalValidatorIndex = 0 bsm.Slashings = []math.Gwei{} bsm.TotalSlashing = 0 if version.EqualsOrIsAfter(bsm.GetForkVersion(), version.Electra()) { bsm.PendingPartialWithdrawals = []*types.PendingPartialWithdrawal{} } return bsm } ================================================ FILE: node-api/handlers/proof/merkle/proposer_index.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/merkle" ) // ProveProposerIndexInBlock generates a proof for the proposer index in the // beacon block. The proof is then verified against the beacon block root as a // sanity check. Returns the proof along with the beacon block root. It uses // the fastssz library to generate the proof. func ProveProposerIndexInBlock( bbh *ctypes.BeaconBlockHeader, ) ([]common.Root, common.Root, error) { blockProofTree, err := bbh.GetTree() if err != nil { return nil, common.Root{}, err } proposerIndexProof, err := blockProofTree.Prove(ProposerIndexGIndexBlock) if err != nil { return nil, common.Root{}, err } proof := make([]common.Root, len(proposerIndexProof.Hashes)) for i, hash := range proposerIndexProof.Hashes { proof[i] = common.NewRootFromBytes(hash) } beaconRoot, err := verifyProposerIndexInBlock( bbh, proof, common.NewRootFromBytes(proposerIndexProof.Leaf), ) if err != nil { return nil, common.Root{}, err } return proof, beaconRoot, nil } // verifyProposerIndexInBlock verifies the proposer index proof in the block. // // TODO: verifying the proof is not absolutely necessary. func verifyProposerIndexInBlock( bbh *ctypes.BeaconBlockHeader, proof []common.Root, leaf common.Root, ) (common.Root, error) { beaconRoot := bbh.HashTreeRoot() if !merkle.VerifyProof(beaconRoot, leaf, ProposerIndexGIndexBlock, proof) { return common.Root{}, errors.Wrapf( errors.New("proposer index proof failed to verify against beacon root"), "beacon root: 0x%s", beaconRoot, ) } return beaconRoot, nil } ================================================ FILE: node-api/handlers/proof/merkle/proposer_index_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/stretchr/testify/require" ) // TestBlockProposerIndexProof tests the ProveProposerIndexInBlock function // and that the generated proof correctly verifies. func TestBlockProposerIndexProof(t *testing.T) { t.Parallel() testCases := []struct { name string slot math.Slot proposerIndex math.ValidatorIndex parentBlockRoot common.Root stateRoot common.Root bodyRoot common.Root expectedProofFile string }{ { name: "1 Validator Set", slot: 69, proposerIndex: 0, parentBlockRoot: common.Root{1, 2, 3}, stateRoot: common.Root{4, 5, 6}, bodyRoot: common.Root{7, 8, 9}, expectedProofFile: "one_validator_proposer_index_proof.json", }, { name: "Many Validator Set", slot: 420, proposerIndex: 69, parentBlockRoot: common.Root{1, 2, 3}, stateRoot: common.Root{4, 5, 6}, bodyRoot: common.Root{7, 8, 9}, expectedProofFile: "many_validators_proposer_index_proof.json", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() bbh := types.NewBeaconBlockHeader( tc.slot, tc.proposerIndex, tc.parentBlockRoot, tc.stateRoot, tc.bodyRoot, ) proof, beaconRoot, err := merkle.ProveProposerIndexInBlock(bbh) require.NoError(t, err) require.Equal(t, bbh.HashTreeRoot(), beaconRoot) expectedProof := ReadProofFromFile(t, tc.expectedProofFile) require.Equal(t, expectedProof, proof) }) } } ================================================ FILE: node-api/handlers/proof/merkle/testdata/empty_state_proof.json ================================================ [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/many_validators_proposer_index_proof.json ================================================ [ "0xa401000000000000000000000000000000000000000000000000000000000000", "0x5ca6b806bfaf4c5c16be71ea6ee96e4e05b172144c1e6c2eb5646535896a30ac", "0xfbfd75335009f40216a1ca7e1e9306e76194a2cebd6f7f9e88ea5a471d86b5f9" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/many_validators_proposer_pubkey_proof_deneb.json ================================================ [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0xfa324a462bcb0f10c24c9e17c326a4e0ebad204feced523eccaf346c686f06ee", "0x4b71985b48d4d27159fb953494feef9e7eeba75f5acd2d03b1c306a186d0537c", "0x11740281865e8d784f81fc4de65e85e38a6aadd4983586ffeff99d326439a834", "0xb5d7f6be4d62c17c85aad66691b3c8a8ab3efe4305c5c4d09a58c4fce699b191", "0xcba76b0fd6edcfd2c74f6020fa3a249f27f07d0c96237d5826f5c5dddf87d2fc", "0x02460b6ea65b13017a2b5dcd11e5b615b12da48e980ac55b1bc1fbbd7bde8d63", "0x5d91c749461f080b40700a41b1468944bb58fa69ffe0c24af202cefb903b9f6f", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7", "0xc6f67e02e6e4e1bdefb994c6098953f34636ba2b6ca20a4721d2b26a886722ff", "0x1c9a7e5ff1cf48b4ad1582d3f4e4a1004f3b20d8c5a2b71387a4254ad933ebc5", "0x2f075ae229646b6f6aed19a5e372cf295081401eb893ff599b3f9acc0c0d3e7d", "0x328921deb59612076801e8cd61592107b5c67c79b846595cc6320c395b46362c", "0xbfb909fdb236ad2411b4e4883810a074b840464689986c3f8a8091827e17c327", "0x55d8fb3687ba3ba49f342c77f5a1f89bec83d811446e1a467139213d640b6a74", "0xf7210d4f8e7e1039790e7bf4efa207555a10a6db1dd4b95da313aaa88b88fe76", "0xad21b516cbc645ffe34ab5de1c8aef8cd4e7f8d2b51e8e1456adc7563cda206f", "0x6400000000000000000000000000000000000000000000000000000000000000", "0x54b4b8b897929a1ede97d29e9551d610229f22c1a59d186d95aed203333b4e5e", "0x4019708b8a442b0e6fc88b6531e2420811d4833db8e862d75a65501695afed1c", "0x1b8afbf6f0034f939f0cfc6e3b03362631bdce35a43b65cbb8f732fa08373b69", "0x70ccdae9a06cda39d93eba92e2692bec147a29ef7e31ad9f4bebb347792d9204", "0x0102030405060000000000000000000000000000000000000000000000000000", "0xe38c573641a369b49f1e77043562c3b6b3932c2cce7fcd4d71d494b4b8d08012", "0xa3df0acb0b3d50f9b7f569ffb440f3a5891a2723a35bd825d6cf271298e616b6" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/many_validators_proposer_pubkey_proof_electra.json ================================================ [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0xfa324a462bcb0f10c24c9e17c326a4e0ebad204feced523eccaf346c686f06ee", "0x4b71985b48d4d27159fb953494feef9e7eeba75f5acd2d03b1c306a186d0537c", "0x11740281865e8d784f81fc4de65e85e38a6aadd4983586ffeff99d326439a834", "0xb5d7f6be4d62c17c85aad66691b3c8a8ab3efe4305c5c4d09a58c4fce699b191", "0xcba76b0fd6edcfd2c74f6020fa3a249f27f07d0c96237d5826f5c5dddf87d2fc", "0x02460b6ea65b13017a2b5dcd11e5b615b12da48e980ac55b1bc1fbbd7bde8d63", "0x5d91c749461f080b40700a41b1468944bb58fa69ffe0c24af202cefb903b9f6f", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7", "0xc6f67e02e6e4e1bdefb994c6098953f34636ba2b6ca20a4721d2b26a886722ff", "0x1c9a7e5ff1cf48b4ad1582d3f4e4a1004f3b20d8c5a2b71387a4254ad933ebc5", "0x2f075ae229646b6f6aed19a5e372cf295081401eb893ff599b3f9acc0c0d3e7d", "0x328921deb59612076801e8cd61592107b5c67c79b846595cc6320c395b46362c", "0xbfb909fdb236ad2411b4e4883810a074b840464689986c3f8a8091827e17c327", "0x55d8fb3687ba3ba49f342c77f5a1f89bec83d811446e1a467139213d640b6a74", "0xf7210d4f8e7e1039790e7bf4efa207555a10a6db1dd4b95da313aaa88b88fe76", "0xad21b516cbc645ffe34ab5de1c8aef8cd4e7f8d2b51e8e1456adc7563cda206f", "0x6400000000000000000000000000000000000000000000000000000000000000", "0x54b4b8b897929a1ede97d29e9551d610229f22c1a59d186d95aed203333b4e5e", "0x4019708b8a442b0e6fc88b6531e2420811d4833db8e862d75a65501695afed1c", "0x1b8afbf6f0034f939f0cfc6e3b03362631bdce35a43b65cbb8f732fa08373b69", "0x70ccdae9a06cda39d93eba92e2692bec147a29ef7e31ad9f4bebb347792d9204", "0x58f6c4a556e87b8de03a64800211685b11e4e6e05e001b65d5f0a588e4985be3", "0x0102030405060000000000000000000000000000000000000000000000000000", "0xe38c573641a369b49f1e77043562c3b6b3932c2cce7fcd4d71d494b4b8d08012", "0xa3df0acb0b3d50f9b7f569ffb440f3a5891a2723a35bd825d6cf271298e616b6" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/many_validators_validator_balance_proof.json ================================================ [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7", "0xc6f67e02e6e4e1bdefb994c6098953f34636ba2b6ca20a4721d2b26a886722ff", "0x1c9a7e5ff1cf48b4ad1582d3f4e4a1004f3b20d8c5a2b71387a4254ad933ebc5", "0x2f075ae229646b6f6aed19a5e372cf295081401eb893ff599b3f9acc0c0d3e7d", "0x328921deb59612076801e8cd61592107b5c67c79b846595cc6320c395b46362c", "0xbfb909fdb236ad2411b4e4883810a074b840464689986c3f8a8091827e17c327", "0x55d8fb3687ba3ba49f342c77f5a1f89bec83d811446e1a467139213d640b6a74", "0x6400000000000000000000000000000000000000000000000000000000000000", "0x6080a24df6cb76f31cacdf4419ac9bf0ac092087f40ec93f10c4608f967ca23a", "0xdb4261da1f55277e8d739af87ee3f2757b11de49e3021abcafe2d73ae3dd5ad1", "0x1b8afbf6f0034f939f0cfc6e3b03362631bdce35a43b65cbb8f732fa08373b69", "0x70ccdae9a06cda39d93eba92e2692bec147a29ef7e31ad9f4bebb347792d9204", "0x58f6c4a556e87b8de03a64800211685b11e4e6e05e001b65d5f0a588e4985be3", "0x0102030405060000000000000000000000000000000000000000000000000000", "0xe38c573641a369b49f1e77043562c3b6b3932c2cce7fcd4d71d494b4b8d08012", "0xa3df0acb0b3d50f9b7f569ffb440f3a5891a2723a35bd825d6cf271298e616b6" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/many_validators_validator_credentials_proof.json ================================================ [ "0xbbd454dfd62ecc85d24a755a14cd5019ddfc64043d0ffd0e2efd23fdec124e30", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0xfa324a462bcb0f10c24c9e17c326a4e0ebad204feced523eccaf346c686f06ee", "0x4b71985b48d4d27159fb953494feef9e7eeba75f5acd2d03b1c306a186d0537c", "0x11740281865e8d784f81fc4de65e85e38a6aadd4983586ffeff99d326439a834", "0xb5d7f6be4d62c17c85aad66691b3c8a8ab3efe4305c5c4d09a58c4fce699b191", "0xcba76b0fd6edcfd2c74f6020fa3a249f27f07d0c96237d5826f5c5dddf87d2fc", "0x02460b6ea65b13017a2b5dcd11e5b615b12da48e980ac55b1bc1fbbd7bde8d63", "0x5d91c749461f080b40700a41b1468944bb58fa69ffe0c24af202cefb903b9f6f", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7", "0xc6f67e02e6e4e1bdefb994c6098953f34636ba2b6ca20a4721d2b26a886722ff", "0x1c9a7e5ff1cf48b4ad1582d3f4e4a1004f3b20d8c5a2b71387a4254ad933ebc5", "0x2f075ae229646b6f6aed19a5e372cf295081401eb893ff599b3f9acc0c0d3e7d", "0x328921deb59612076801e8cd61592107b5c67c79b846595cc6320c395b46362c", "0xbfb909fdb236ad2411b4e4883810a074b840464689986c3f8a8091827e17c327", "0x55d8fb3687ba3ba49f342c77f5a1f89bec83d811446e1a467139213d640b6a74", "0xf7210d4f8e7e1039790e7bf4efa207555a10a6db1dd4b95da313aaa88b88fe76", "0xad21b516cbc645ffe34ab5de1c8aef8cd4e7f8d2b51e8e1456adc7563cda206f", "0x6400000000000000000000000000000000000000000000000000000000000000", "0x54b4b8b897929a1ede97d29e9551d610229f22c1a59d186d95aed203333b4e5e", "0x4019708b8a442b0e6fc88b6531e2420811d4833db8e862d75a65501695afed1c", "0x1b8afbf6f0034f939f0cfc6e3b03362631bdce35a43b65cbb8f732fa08373b69", "0x70ccdae9a06cda39d93eba92e2692bec147a29ef7e31ad9f4bebb347792d9204", "0x58f6c4a556e87b8de03a64800211685b11e4e6e05e001b65d5f0a588e4985be3", "0x0102030405060000000000000000000000000000000000000000000000000000", "0xe38c573641a369b49f1e77043562c3b6b3932c2cce7fcd4d71d494b4b8d08012", "0xa3df0acb0b3d50f9b7f569ffb440f3a5891a2723a35bd825d6cf271298e616b6" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/non_empty_state_proof.json ================================================ [ "0x0102030405060708090000000000000000000000000000000000000000000000", "0xbd50456d5ad175ae99a1612a53ca229124b65d3eaabd9ff9c7ab979a385cf6b3", "0x2137a0ff622bd6e30728bc64e7deed6ea418596c772143e232cfea9d88babd58" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/one_validator_proposer_index_proof.json ================================================ [ "0x4500000000000000000000000000000000000000000000000000000000000000", "0x5ca6b806bfaf4c5c16be71ea6ee96e4e05b172144c1e6c2eb5646535896a30ac", "0xfbfd75335009f40216a1ca7e1e9306e76194a2cebd6f7f9e88ea5a471d86b5f9" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/one_validator_proposer_pubkey_proof_deneb.json ================================================ [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7", "0xc6f67e02e6e4e1bdefb994c6098953f34636ba2b6ca20a4721d2b26a886722ff", "0x1c9a7e5ff1cf48b4ad1582d3f4e4a1004f3b20d8c5a2b71387a4254ad933ebc5", "0x2f075ae229646b6f6aed19a5e372cf295081401eb893ff599b3f9acc0c0d3e7d", "0x328921deb59612076801e8cd61592107b5c67c79b846595cc6320c395b46362c", "0xbfb909fdb236ad2411b4e4883810a074b840464689986c3f8a8091827e17c327", "0x55d8fb3687ba3ba49f342c77f5a1f89bec83d811446e1a467139213d640b6a74", "0xf7210d4f8e7e1039790e7bf4efa207555a10a6db1dd4b95da313aaa88b88fe76", "0xad21b516cbc645ffe34ab5de1c8aef8cd4e7f8d2b51e8e1456adc7563cda206f", "0x0100000000000000000000000000000000000000000000000000000000000000", "0x54b4b8b897929a1ede97d29e9551d610229f22c1a59d186d95aed203333b4e5e", "0x4019708b8a442b0e6fc88b6531e2420811d4833db8e862d75a65501695afed1c", "0x1b8afbf6f0034f939f0cfc6e3b03362631bdce35a43b65cbb8f732fa08373b69", "0xda5a83fdae2974416e891f268f5d29d45f071bb414304bdff46aaaa07a7403cb", "0x0102030000000000000000000000000000000000000000000000000000000000", "0xd6e497b816c27a31acd5d9f3ed670639fef7842fee51f044dfbfb6319c760a5f", "0x7b85fe2a9afab51dcca12b224e10bf25e6cb1cb99ac5d24be8a55fac862b6c90" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/one_validator_proposer_pubkey_proof_electra.json ================================================ [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7", "0xc6f67e02e6e4e1bdefb994c6098953f34636ba2b6ca20a4721d2b26a886722ff", "0x1c9a7e5ff1cf48b4ad1582d3f4e4a1004f3b20d8c5a2b71387a4254ad933ebc5", "0x2f075ae229646b6f6aed19a5e372cf295081401eb893ff599b3f9acc0c0d3e7d", "0x328921deb59612076801e8cd61592107b5c67c79b846595cc6320c395b46362c", "0xbfb909fdb236ad2411b4e4883810a074b840464689986c3f8a8091827e17c327", "0x55d8fb3687ba3ba49f342c77f5a1f89bec83d811446e1a467139213d640b6a74", "0xf7210d4f8e7e1039790e7bf4efa207555a10a6db1dd4b95da313aaa88b88fe76", "0xad21b516cbc645ffe34ab5de1c8aef8cd4e7f8d2b51e8e1456adc7563cda206f", "0x0100000000000000000000000000000000000000000000000000000000000000", "0x54b4b8b897929a1ede97d29e9551d610229f22c1a59d186d95aed203333b4e5e", "0x4019708b8a442b0e6fc88b6531e2420811d4833db8e862d75a65501695afed1c", "0x1b8afbf6f0034f939f0cfc6e3b03362631bdce35a43b65cbb8f732fa08373b69", "0xda5a83fdae2974416e891f268f5d29d45f071bb414304bdff46aaaa07a7403cb", "0x58f6c4a556e87b8de03a64800211685b11e4e6e05e001b65d5f0a588e4985be3", "0x0102030000000000000000000000000000000000000000000000000000000000", "0xd6e497b816c27a31acd5d9f3ed670639fef7842fee51f044dfbfb6319c760a5f", "0x7b85fe2a9afab51dcca12b224e10bf25e6cb1cb99ac5d24be8a55fac862b6c90" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/one_validator_validator_balance_proof.json ================================================ [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7", "0xc6f67e02e6e4e1bdefb994c6098953f34636ba2b6ca20a4721d2b26a886722ff", "0x1c9a7e5ff1cf48b4ad1582d3f4e4a1004f3b20d8c5a2b71387a4254ad933ebc5", "0x2f075ae229646b6f6aed19a5e372cf295081401eb893ff599b3f9acc0c0d3e7d", "0x328921deb59612076801e8cd61592107b5c67c79b846595cc6320c395b46362c", "0xbfb909fdb236ad2411b4e4883810a074b840464689986c3f8a8091827e17c327", "0x55d8fb3687ba3ba49f342c77f5a1f89bec83d811446e1a467139213d640b6a74", "0x0100000000000000000000000000000000000000000000000000000000000000", "0x6080a24df6cb76f31cacdf4419ac9bf0ac092087f40ec93f10c4608f967ca23a", "0xd8fa0aadb22a3b0fbc808b72568e1ee6a4e189a09f5caf344277c96e6fa474fd", "0x1b8afbf6f0034f939f0cfc6e3b03362631bdce35a43b65cbb8f732fa08373b69", "0xda5a83fdae2974416e891f268f5d29d45f071bb414304bdff46aaaa07a7403cb", "0x58f6c4a556e87b8de03a64800211685b11e4e6e05e001b65d5f0a588e4985be3", "0x0102030000000000000000000000000000000000000000000000000000000000", "0xd6e497b816c27a31acd5d9f3ed670639fef7842fee51f044dfbfb6319c760a5f", "0x7b85fe2a9afab51dcca12b224e10bf25e6cb1cb99ac5d24be8a55fac862b6c90" ] ================================================ FILE: node-api/handlers/proof/merkle/testdata/one_validator_validator_credentials_proof.json ================================================ [ "0x292f7782a5d9c4cc3c0d5b5dcdbaeba0f07736ff8ad2f68c57e2dcd832f444f1", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0x0000000000000000000000000000000000000000000000000000000000000000", "0xf5a5fd42d16a20302798ef6ed309979b43003d2320d9f0e8ea9831a92759fb4b", "0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71", "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "0x9efde052aa15429fae05bad4d0b1d7c64da64d03d7a1854a588c2cb8430c0d30", "0xd88ddfeed400a8755596b21942c1497e114c302e6118290f91e6772976041fa1", "0x87eb0ddba57e35f6d286673802a4af5975e22506c7cf4c64bb6be5ee11527f2c", "0x26846476fd5fc54a5d43385167c95144f2643f533cc85bb9d16b782f8d7db193", "0x506d86582d252405b840018792cad2bf1259f1ef5aa5f887e13cb2f0094f51e1", "0xffff0ad7e659772f9534c195c815efc4014ef1e1daed4404c06385d11192e92b", "0x6cf04127db05441cd833107a52be852868890e4317e6a02ab47683aa75964220", "0xb7d05f875f140027ef5118a2247bbb84ce8f2f0f1123623085daf7960c329f5f", "0xdf6af5f5bbdb6be9ef8aa618e4bf8073960867171e29676f8b284dea6a08a85e", "0xb58d900f5e182e3c50ef74969ea16c7726c549757cc23523c369587da7293784", "0xd49a7502ffcfb0340b1d7885688500ca308161a7f96b62df9d083b71fcc8f2bb", "0x8fe6b1689256c0d385f42f5bbe2027a22c1996e110ba97c171d3e5948de92beb", "0x8d0d63c39ebade8509e0ae3c9c3876fb5fa112be18f905ecacfecb92057603ab", "0x95eec8b2e541cad4e91de38385f2e046619f54496c2382cb6cacd5b98c26f5a4", "0xf893e908917775b62bff23294dbbe3a1cd8e6cc1c35b4801887b646a6f81f17f", "0xcddba7b592e3133393c16194fac7431abf2f5485ed711db282183c819e08ebaa", "0x8a8d7fe3af8caa085a7639a832001457dfb9128a8061142ad0335629ff23ff9c", "0xfeb3c337d7a51a6fbf00b9e34c52e1c9195c969bd4e7a0bfd51d5c5bed9c1167", "0xe71f0aa83cc32edfbefa9f4d3e0174ca85182eec9f3a09f6a6c0df6377a510d7", "0x31206fa80a50bb6abe29085058f16212212a60eec8f049fecb92d8c8e0a84bc0", "0x21352bfecbeddde993839f614c3dac0a3ee37543f9b412b16199dc158e23b544", "0x619e312724bb6d7c3153ed9de791d764a366b389af13c58bf8a8d90481a46765", "0x7cdd2986268250628d0c10e385c58c6191e6fbe05191bcc04f133f2cea72c1c4", "0x848930bd7ba8cac54661072113fb278869e07bb8587f91392933374d017bcbe1", "0x8869ff2c22b28cc10510d9853292803328be4fb0e80495e8bb8d271f5b889636", "0xb5fe28e79f1b850f8658246ce9b6a1e7b49fc06db7143e8fe0b4f2b0c5523a5c", "0x985e929f70af28d0bdd1a90a808f977f597c7c778c489e98d3bd8910d31ac0f7", "0xc6f67e02e6e4e1bdefb994c6098953f34636ba2b6ca20a4721d2b26a886722ff", "0x1c9a7e5ff1cf48b4ad1582d3f4e4a1004f3b20d8c5a2b71387a4254ad933ebc5", "0x2f075ae229646b6f6aed19a5e372cf295081401eb893ff599b3f9acc0c0d3e7d", "0x328921deb59612076801e8cd61592107b5c67c79b846595cc6320c395b46362c", "0xbfb909fdb236ad2411b4e4883810a074b840464689986c3f8a8091827e17c327", "0x55d8fb3687ba3ba49f342c77f5a1f89bec83d811446e1a467139213d640b6a74", "0xf7210d4f8e7e1039790e7bf4efa207555a10a6db1dd4b95da313aaa88b88fe76", "0xad21b516cbc645ffe34ab5de1c8aef8cd4e7f8d2b51e8e1456adc7563cda206f", "0x0100000000000000000000000000000000000000000000000000000000000000", "0x54b4b8b897929a1ede97d29e9551d610229f22c1a59d186d95aed203333b4e5e", "0x4019708b8a442b0e6fc88b6531e2420811d4833db8e862d75a65501695afed1c", "0x1b8afbf6f0034f939f0cfc6e3b03362631bdce35a43b65cbb8f732fa08373b69", "0xda5a83fdae2974416e891f268f5d29d45f071bb414304bdff46aaaa07a7403cb", "0x58f6c4a556e87b8de03a64800211685b11e4e6e05e001b65d5f0a588e4985be3", "0x0102030000000000000000000000000000000000000000000000000000000000", "0xd6e497b816c27a31acd5d9f3ed670639fef7842fee51f044dfbfb6319c760a5f", "0x7b85fe2a9afab51dcca12b224e10bf25e6cb1cb99ac5d24be8a55fac862b6c90" ] ================================================ FILE: node-api/handlers/proof/merkle/validator_balance.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-api/handlers/proof/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/merkle" "github.com/pkg/errors" ) // bytesPerBalance is the number of bytes in a single balance (uint64). const bytesPerBalance uint64 = 8 // ProveBalanceInState generates a proof for a validator's balance in the beacon state. func ProveBalanceInState( forkVersion common.Version, bsm types.BeaconStateMarshallable, validatorIndex math.U64, ) ([]common.Root, common.Root, error) { stateProofTree, err := bsm.GetTree() if err != nil { return nil, common.Root{}, err } // Determine the starting generalized index for the 0-th validator's // balance for this fork. zeroBalanceGIndexState, err := GetZeroValidatorBalanceGIndexState(forkVersion) if err != nil { return nil, common.Root{}, err } // Since balances are packed 4 per leaf, calculate the leaf offset leafOffset := validatorIndex / BalancesPerLeaf // Calculate the generalized index for the target validator's balance leaf. // The offset multiplication is bounded by the number of validators, so // converting to int is safe on 64-bit architectures. gIndex := zeroBalanceGIndexState + int(leafOffset) // #nosec G115 balanceProof, err := stateProofTree.Prove(gIndex) if err != nil { return nil, common.Root{}, err } proof := make([]common.Root, len(balanceProof.Hashes)) for i, hash := range balanceProof.Hashes { proof[i] = common.NewRootFromBytes(hash) } // The leaf contains 4 packed uint64 balances return proof, common.NewRootFromBytes(balanceProof.Leaf), nil } // ProveBalanceInBlock generates a proof for a validator's balance in the beacon block. // Returns the proof, the leaf containing the packed balances, and the beacon block root. func ProveBalanceInBlock( validatorIndex math.U64, bbh *ctypes.BeaconBlockHeader, bsm types.BeaconStateMarshallable, allBalances []uint64, ) ([]common.Root, common.Root, common.Root, error) { forkVersion := bsm.GetForkVersion() // 1. Proof inside the state. balanceInStateProof, leaf, err := ProveBalanceInState( forkVersion, bsm, validatorIndex, ) if err != nil { return nil, common.Root{}, common.Root{}, err } // 2. Build the balance leaf and assert that it matches the proof's leaf. builtLeaf := buildBalanceLeaf(allBalances, validatorIndex) if !leaf.Equals(builtLeaf) { return nil, common.Root{}, common.Root{}, fmt.Errorf( "balance leaf mismatch -- proof tree leaf: 0x%s, built leaf: 0x%s", leaf, builtLeaf, ) } // 3. Proof of the state inside the block. stateInBlockProof, err := ProveBeaconStateInBlock(bbh, false) if err != nil { return nil, common.Root{}, common.Root{}, err } // 4. Combine proofs: state-level hashes come first, followed by block-level // hashes (same order as ProveProposerPubkeyInBlock). // //nolint:gocritic // ok. combinedProof := append(balanceInStateProof, stateInBlockProof...) // 5. Verify the combined proof against the beacon block root. // Since balances are packed 4 per leaf, calculate the leaf offset. leafOffset := validatorIndex / BalancesPerLeaf beaconRoot, err := verifyBalanceInBlock( forkVersion, bbh, leafOffset.Unwrap(), combinedProof, leaf, ) if err != nil { return nil, common.Root{}, common.Root{}, err } return combinedProof, leaf, beaconRoot, nil } // buildBalanceLeaf constructs the 32-byte leaf containing the packed balances // for the group of validators that includes `validatorIndex`. Balances are // packed 4 per leaf (little-endian uint64s). func buildBalanceLeaf(allBalances []uint64, validatorIndex math.U64) common.Root { var leafBytes common.Root // Determine which leaf the validator belongs to and the starting index in // the balances slice. leafIndex := validatorIndex / BalancesPerLeaf startIdx := leafIndex * BalancesPerLeaf // Pack up to 4 balances (little-endian) into the 32-byte array. for i := range uint64(BalancesPerLeaf) { idx := startIdx.Unwrap() + i if idx >= uint64(len(allBalances)) { break } bal := allBalances[idx] for j := range bytesPerBalance { leafBytes[i*bytesPerBalance+j] = byte(bal >> (j * bytesPerBalance)) // #nosec G115 -- intentional byte extraction from uint64. } } return leafBytes } // verifyBalanceInBlock verifies the provided Merkle proof of a // validator's balance inside the beacon block and returns the // beacon block root that the proof was verified against. // // NOTE: Proof verification is not strictly necessary for operation, but we do // it as a sanity check to avoid propagating malformed proofs downstream. func verifyBalanceInBlock( forkVersion common.Version, bbh *ctypes.BeaconBlockHeader, balanceOffset uint64, proof []common.Root, leaf common.Root, ) (common.Root, error) { zeroBalanceGIndexBlock, err := GetZeroValidatorBalanceGIndexBlock(forkVersion) if err != nil { return common.Root{}, err } beaconRoot := bbh.HashTreeRoot() if !merkle.VerifyProof( beaconRoot, leaf, zeroBalanceGIndexBlock+balanceOffset, proof, ) { return common.Root{}, errors.Wrapf( errors.New("balance proof failed to verify against beacon root"), "beacon root: 0x%s", beaconRoot, ) } return beaconRoot, nil } ================================================ FILE: node-api/handlers/proof/merkle/validator_balance_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "testing" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle/mock" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) // TestValidatorBalanceProof_Comparison tests the balance function // and that the generated proof matches the expected proof. func TestValidatorBalanceProof_Comparison(t *testing.T) { t.Parallel() testCases := []struct { name string forkVersion common.Version numValidators int slot math.Slot valIndex math.ValidatorIndex parentBlockRoot common.Root bodyRoot common.Root balance uint64 expectedProofFile string }{ { name: "1 Validator Set", forkVersion: version.Electra(), numValidators: 1, slot: 4, valIndex: 0, parentBlockRoot: common.Root{1, 2, 3}, bodyRoot: common.Root{3, 2, 1}, balance: 1000000000000000000, expectedProofFile: "one_validator_validator_balance_proof.json", }, { name: "Many Validator Set", forkVersion: version.Electra(), numValidators: 100, slot: 5, valIndex: 95, parentBlockRoot: common.Root{1, 2, 3, 4, 5, 6}, bodyRoot: common.Root{3, 2, 1, 9, 8, 7}, balance: 2000000000000000000, expectedProofFile: "many_validators_validator_balance_proof.json", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { vals := make(ctypes.Validators, tc.numValidators) for i := range vals { vals[i] = &ctypes.Validator{} } bs := mock.NewBeaconStateWith( tc.slot, vals, 0, common.ExecutionAddress{}, tc.forkVersion, ) bs.Balances = make([]uint64, tc.numValidators) bs.Balances[tc.valIndex] = tc.balance bbh := ctypes.NewBeaconBlockHeader( tc.slot, tc.valIndex, tc.parentBlockRoot, bs.HashTreeRoot(), tc.bodyRoot, ) proof, _, _, err := merkle.ProveBalanceInBlock(tc.valIndex, bbh, bs, bs.Balances) require.NoError(t, err) expectedProof := ReadProofFromFile(t, tc.expectedProofFile) require.Equal(t, expectedProof, proof) }) } } func TestValidatorBalanceProof(t *testing.T) { t.Parallel() tests := []struct { name string numValidators int validatorIndex math.U64 fork common.Version slot math.Slot parentBlockRoot common.Root bodyRoot common.Root }{ { name: "Single Validator Balance - Electra", numValidators: 1, validatorIndex: 0, fork: version.Electra(), slot: 4, parentBlockRoot: common.Root{1, 2, 3}, bodyRoot: common.Root{3, 2, 1}, }, { name: "Multiple Validators Balance - First Leaf - Electra", numValidators: 10, validatorIndex: 2, // Within first leaf (0-3) fork: version.Electra(), slot: 5, parentBlockRoot: common.Root{1, 2, 3, 4}, bodyRoot: common.Root{4, 3, 2, 1}, }, { name: "Multiple Validators Balance - Second Leaf - Electra", numValidators: 10, validatorIndex: 5, // In second leaf (4-7) fork: version.Electra(), slot: 6, parentBlockRoot: common.Root{1, 2, 3, 4, 5}, bodyRoot: common.Root{5, 4, 3, 2, 1}, }, { name: "Many Validators Balance - Electra", numValidators: 100, validatorIndex: 47, // Tests a validator in a later leaf fork: version.Electra(), slot: 7, parentBlockRoot: common.Root{1, 2, 3, 4, 5, 6}, bodyRoot: common.Root{6, 5, 4, 3, 2, 1}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create validators vals := make(ctypes.Validators, tt.numValidators) for i := range tt.numValidators { vals[i] = &ctypes.Validator{} } // Create beacon state with validators bs := mock.NewBeaconStateWith( tt.slot, vals, 0, common.ExecutionAddress{}, tt.fork, ) // Set balances manually since the mock doesn't set them bs.Balances = make([]uint64, tt.numValidators) for i := range tt.numValidators { bs.Balances[i] = uint64(32000000000 + i*1000000000) // 32 ETH + i ETH } // Create beacon block header bbh := ctypes.NewBeaconBlockHeader( tt.slot, 0, // proposer index tt.parentBlockRoot, bs.HashTreeRoot(), tt.bodyRoot, ) // Generate the proof proof, _, beaconRoot, err := merkle.ProveBalanceInBlock( tt.validatorIndex, bbh, bs, bs.Balances, ) require.NoError(t, err) require.NotEmpty(t, proof) require.NotEqual(t, [32]byte{}, beaconRoot) // Verify the proof is valid (this is done internally in ProveBalanceInBlock) // but we can double-check the returned beacon root matches expectedRoot := bbh.HashTreeRoot() require.Equal(t, expectedRoot, beaconRoot) }) } } func TestValidatorBalanceProofEdgeCases(t *testing.T) { t.Parallel() // Test with validators at leaf boundaries numValidators := 17 // This gives us 5 leaves (0-3, 4-7, 8-11, 12-15, 16) vals := make(ctypes.Validators, numValidators) for i := range numValidators { vals[i] = &ctypes.Validator{} } bs := mock.NewBeaconStateWith( 10, vals, 0, common.ExecutionAddress{}, version.Electra(), ) // Set balances bs.Balances = make([]uint64, numValidators) for i := range numValidators { bs.Balances[i] = uint64(32000000000) } bbh := ctypes.NewBeaconBlockHeader( 10, 0, // proposer index common.Root{1, 2, 3}, bs.HashTreeRoot(), common.Root{3, 2, 1}, ) // Test validators at different positions within leaves testCases := []struct { name string validatorIndex math.U64 leafIndex uint64 positionInLeaf uint64 }{ {"First in first leaf", 0, 0, 0}, {"Last in first leaf", 3, 0, 3}, {"First in second leaf", 4, 1, 0}, {"Last in second leaf", 7, 1, 3}, {"First in last partial leaf", 16, 4, 0}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { proof, _, beaconRoot, err := merkle.ProveBalanceInBlock( tc.validatorIndex, bbh, bs, bs.Balances, ) require.NoError(t, err) require.NotEmpty(t, proof) require.NotEqual(t, [32]byte{}, beaconRoot) // Verify the leaf index calculation calculatedLeafIndex := tc.validatorIndex / 4 require.Equal(t, tc.leafIndex, calculatedLeafIndex.Unwrap()) // Verify position within leaf positionInLeaf := tc.validatorIndex % 4 require.Equal(t, tc.positionInLeaf, positionInLeaf.Unwrap()) }) } } ================================================ FILE: node-api/handlers/proof/merkle/validator_credentials.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-api/handlers/proof/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/merkle" ) // ProveWithdrawalCredentialsInState generates a proof for a validator's // withdrawal credentials in the beacon state. The validatorOffset must be // computed as (ValidatorWithdrawalCredentialsGIndexOffset * validatorIndex). func ProveWithdrawalCredentialsInState( forkVersion common.Version, bsm types.BeaconStateMarshallable, validatorOffset math.U64, ) ([]common.Root, common.Root, error) { stateProofTree, err := bsm.GetTree() if err != nil { return nil, common.Root{}, err } // Determine the starting generalized index for the 0-th validator's // withdrawal credentials for this fork. zeroWithdrawalGIndexState, err := GetZeroValidatorCredentialsGIndexState(forkVersion) if err != nil { return nil, common.Root{}, err } // Calculate the generalized index for the target validator. The offset // multiplication is bounded by (2^40-1)*8 < 2^43 < 2^63, so converting to // int is safe on 64-bit architectures. gIndex := zeroWithdrawalGIndexState + int(validatorOffset) // #nosec G115 withdrawalProof, err := stateProofTree.Prove(gIndex) if err != nil { return nil, common.Root{}, err } proof := make([]common.Root, len(withdrawalProof.Hashes)) for i, hash := range withdrawalProof.Hashes { proof[i] = common.NewRootFromBytes(hash) } return proof, common.NewRootFromBytes(withdrawalProof.Leaf), nil } // ProveWithdrawalCredentialsInBlock generates a proof for a validator's // withdrawal credentials in the beacon block. The proof is verified against // the beacon block root as a sanity check and the "correct" beacon block root // is returned alongside the proof. func ProveWithdrawalCredentialsInBlock( validatorIndex math.U64, bbh *ctypes.BeaconBlockHeader, bsm types.BeaconStateMarshallable, ) ([]common.Root, common.Root, error) { forkVersion := bsm.GetForkVersion() // Calculate the validator-specific offset. validatorOffset := ValidatorGIndexOffset * validatorIndex // 1. Proof inside the state. withdrawalInStateProof, leaf, err := ProveWithdrawalCredentialsInState( forkVersion, bsm, validatorOffset, ) if err != nil { return nil, common.Root{}, err } // 2. Proof of the state inside the block. stateInBlockProof, err := ProveBeaconStateInBlock(bbh, false) if err != nil { return nil, common.Root{}, err } // 3. Combine proofs: state-level hashes come first, followed by block-level // hashes (same order as ProveProposerPubkeyInBlock). // //nolint:gocritic // ok. combinedProof := append(withdrawalInStateProof, stateInBlockProof...) // 4. Verify the combined proof against the beacon block root. beaconRoot, err := verifyWithdrawalCredentialsInBlock( forkVersion, bbh, validatorOffset, combinedProof, leaf, ) if err != nil { return nil, common.Root{}, err } return combinedProof, beaconRoot, nil } // verifyWithdrawalCredentialsInBlock verifies the provided Merkle proof of a // validator's withdrawal credentials inside the beacon block and returns the // beacon block root that the proof was verified against. // // NOTE: Proof verification is not strictly necessary for operation, but we do // it as a sanity check to avoid propagating malformed proofs downstream. func verifyWithdrawalCredentialsInBlock( forkVersion common.Version, bbh *ctypes.BeaconBlockHeader, validatorOffset math.U64, proof []common.Root, leaf common.Root, ) (common.Root, error) { zeroWithdrawalGIndexBlock, err := GetZeroValidatorCredentialsGIndexBlock(forkVersion) if err != nil { return common.Root{}, err } beaconRoot := bbh.HashTreeRoot() if !merkle.VerifyProof( beaconRoot, leaf, zeroWithdrawalGIndexBlock+validatorOffset.Unwrap(), proof, ) { return common.Root{}, errors.Wrapf( errors.New("withdrawal credentials proof failed to verify against beacon root"), "beacon root: 0x%s", beaconRoot, ) } return beaconRoot, nil } ================================================ FILE: node-api/handlers/proof/merkle/validator_credentials_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle/mock" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) // TestValidatorCredentialsProof tests the ProveWithdrawalCredentialsInBlock function // and that the generated proof correctly verifies. func TestValidatorCredentialsProof(t *testing.T) { t.Parallel() testCases := []struct { name string forkVersion common.Version numValidators int slot math.Slot valIndex math.ValidatorIndex parentBlockRoot common.Root bodyRoot common.Root pubKey crypto.BLSPubkey withdrawalAddress common.ExecutionAddress expectedProofFile string }{ { name: "1 Validator Set", forkVersion: version.Electra(), numValidators: 1, slot: 4, valIndex: 0, parentBlockRoot: common.Root{1, 2, 3}, bodyRoot: common.Root{3, 2, 1}, pubKey: [48]byte{9, 8, 7, 6, 5, 4, 3, 2, 1}, withdrawalAddress: common.ExecutionAddress{1, 2, 3}, expectedProofFile: "one_validator_validator_credentials_proof.json", }, { name: "Many Validator Set", forkVersion: version.Electra(), numValidators: 100, slot: 5, valIndex: 95, parentBlockRoot: common.Root{1, 2, 3, 4, 5, 6}, bodyRoot: common.Root{3, 2, 1, 9, 8, 7}, pubKey: [48]byte{9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2}, withdrawalAddress: common.ExecutionAddress{1, 2, 3}, expectedProofFile: "many_validators_validator_credentials_proof.json", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { vals := make(types.Validators, tc.numValidators) for i := range vals { vals[i] = &types.Validator{} } vals[tc.valIndex] = &types.Validator{ Pubkey: tc.pubKey, WithdrawalCredentials: types.NewCredentialsFromExecutionAddress(tc.withdrawalAddress), } bs := mock.NewBeaconStateWith( tc.slot, vals, 0, common.ExecutionAddress{}, tc.forkVersion, ) bbh := types.NewBeaconBlockHeader( tc.slot, tc.valIndex, tc.parentBlockRoot, bs.HashTreeRoot(), tc.bodyRoot, ) proof, _, err := merkle.ProveWithdrawalCredentialsInBlock( tc.valIndex, bbh, bs, ) require.NoError(t, err) expectedProof := ReadProofFromFile(t, tc.expectedProofFile) require.Equal(t, expectedProof, proof) }) } } ================================================ FILE: node-api/handlers/proof/merkle/validator_pubkey.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-api/handlers/proof/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/merkle" ) // ProveProposerPubkeyInBlock generates a proof for the proposer pubkey in the // beacon block. func ProveProposerPubkeyInBlock( bbh *ctypes.BeaconBlockHeader, bsm types.BeaconStateMarshallable, ) ([]common.Root, common.Root, error) { return ProveValidatorPubkeyInBlock(bbh.GetProposerIndex(), bbh, bsm) } // ProveValidatorPubkeyInBlock generates a proof for a validator's pubkey in the // beacon block. The proof is verified against the beacon block root as a sanity // check and the beacon block root is returned alongside the proof. func ProveValidatorPubkeyInBlock( validatorIndex math.U64, bbh *ctypes.BeaconBlockHeader, bsm types.BeaconStateMarshallable, ) ([]common.Root, common.Root, error) { forkVersion := bsm.GetForkVersion() // Calculate the validator-specific offset. validatorOffset := ValidatorGIndexOffset * validatorIndex // 1. Proof inside the state. pubkeyInStateProof, leaf, err := ProveValidatorPubkeyInState( forkVersion, bsm, validatorOffset, ) if err != nil { return nil, common.Root{}, err } // 2. Proof of the state inside the block. stateInBlockProof, err := ProveBeaconStateInBlock(bbh, false) if err != nil { return nil, common.Root{}, err } // 3. Combine proofs: state-level hashes come first, followed by block-level hashes. // //nolint:gocritic // ok. combinedProof := append(pubkeyInStateProof, stateInBlockProof...) // 4. Verify the combined proof against the beacon block root. beaconRoot, err := verifyPubkeyInBlock( forkVersion, bbh, validatorOffset, combinedProof, leaf, ) if err != nil { return nil, common.Root{}, err } return combinedProof, beaconRoot, nil } // ProveValidatorPubkeyInState generates a proof for a validator's pubkey // in the beacon state. The validatorOffset must be computed as // (ValidatorGIndexOffset * validatorIndex). func ProveValidatorPubkeyInState( forkVersion common.Version, bsm types.BeaconStateMarshallable, validatorOffset math.U64, ) ([]common.Root, common.Root, error) { stateProofTree, err := bsm.GetTree() if err != nil { return nil, common.Root{}, err } // Determine the correct gIndex based on the fork version. gIndex := int(validatorOffset) // #nosec G115 -- max validator offset is 8 * (2^40 - 1). zeroValidatorPubkeyGIndexState, err := GetZeroValidatorPubkeyGIndexState(forkVersion) if err != nil { return nil, common.Root{}, err } gIndex += zeroValidatorPubkeyGIndexState valPubkeyInStateProof, err := stateProofTree.Prove(gIndex) if err != nil { return nil, common.Root{}, err } proof := make([]common.Root, len(valPubkeyInStateProof.Hashes)) for i, hash := range valPubkeyInStateProof.Hashes { proof[i] = common.NewRootFromBytes(hash) } return proof, common.NewRootFromBytes(valPubkeyInStateProof.Leaf), nil } // verifyPubkeyInBlock verifies the validator pubkey in the beacon block, // returning the beacon block root used to verify against. // // TODO: verifying the proof is not absolutely necessary. func verifyPubkeyInBlock( forkVersion common.Version, bbh *ctypes.BeaconBlockHeader, valOffset math.U64, proof []common.Root, leaf common.Root, ) (common.Root, error) { zeroValidatorPubkeyGIndexBlock, err := GetZeroValidatorPubkeyGIndexBlock(forkVersion) if err != nil { return common.Root{}, err } beaconRoot := bbh.HashTreeRoot() if !merkle.VerifyProof( beaconRoot, leaf, zeroValidatorPubkeyGIndexBlock+valOffset.Unwrap(), proof, ) { return common.Root{}, fmt.Errorf( "proposer pubkey proof failed to verify against beacon root: %s", beaconRoot, ) } return beaconRoot, nil } ================================================ FILE: node-api/handlers/proof/merkle/validator_pubkey_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "testing" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle/mock" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) // TestValidatorPubkeyProof tests the ProveValidatorPubkeyInBlock function // and that the generated proof correctly verifies. func TestValidatorPubkeyProof(t *testing.T) { t.Parallel() testCases := []struct { name string forkVersion common.Version numValidators int slot math.Slot proposerIndex math.ValidatorIndex parentBlockRoot common.Root bodyRoot common.Root pubKey crypto.BLSPubkey expectedProofFile string }{ { name: "1 Validator Set - Deneb", forkVersion: version.Deneb(), numValidators: 1, slot: 4, proposerIndex: 0, parentBlockRoot: common.Root{1, 2, 3}, bodyRoot: common.Root{3, 2, 1}, pubKey: [48]byte{9, 8, 7, 6, 5, 4, 3, 2, 1}, expectedProofFile: "one_validator_proposer_pubkey_proof_deneb.json", }, { name: "Many Validator Set - Deneb", forkVersion: version.Deneb(), numValidators: 100, slot: 5, proposerIndex: 95, parentBlockRoot: common.Root{1, 2, 3, 4, 5, 6}, bodyRoot: common.Root{3, 2, 1, 9, 8, 7}, pubKey: [48]byte{9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2}, expectedProofFile: "many_validators_proposer_pubkey_proof_deneb.json", }, { name: "1 Validator Set - Electra", forkVersion: version.Electra(), numValidators: 1, slot: 4, proposerIndex: 0, parentBlockRoot: common.Root{1, 2, 3}, bodyRoot: common.Root{3, 2, 1}, pubKey: [48]byte{9, 8, 7, 6, 5, 4, 3, 2, 1}, expectedProofFile: "one_validator_proposer_pubkey_proof_electra.json", }, { name: "Many Validator Set - Electra", forkVersion: version.Electra(), numValidators: 100, slot: 5, proposerIndex: 95, parentBlockRoot: common.Root{1, 2, 3, 4, 5, 6}, bodyRoot: common.Root{3, 2, 1, 9, 8, 7}, pubKey: [48]byte{9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 1, 2}, expectedProofFile: "many_validators_proposer_pubkey_proof_electra.json", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { vals := make(types.Validators, tc.numValidators) for i := range vals { vals[i] = &types.Validator{} } vals[tc.proposerIndex] = &types.Validator{Pubkey: tc.pubKey} bs := mock.NewBeaconStateWith( tc.slot, vals, 0, common.ExecutionAddress{}, tc.forkVersion, ) bbh := types.NewBeaconBlockHeader( tc.slot, tc.proposerIndex, tc.parentBlockRoot, bs.HashTreeRoot(), tc.bodyRoot, ) // Use the proposer pubkey helper function to prove validator pubkey of block proposer. proof, _, err := merkle.ProveProposerPubkeyInBlock(bbh, bs) require.NoError(t, err) expectedProof := ReadProofFromFile(t, tc.expectedProofFile) require.Equal(t, expectedProof, proof) }) } } ================================================ FILE: node-api/handlers/proof/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package proof import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodGet, Path: "bkit/v1/proof/block_proposer/:timestamp_id", Handler: h.GetBlockProposer, }, { Method: http.MethodGet, Path: "bkit/v1/proof/validator_pubkey/:timestamp_id/:validator_index", Handler: h.GetValidatorPubkey, }, { Method: http.MethodGet, Path: "bkit/v1/proof/validator_credentials/:timestamp_id/:validator_index", Handler: h.GetValidatorCredentials, }, { Method: http.MethodGet, Path: "bkit/v1/proof/validator_balance/:timestamp_id/:validator_index", Handler: h.GetValidatorBalance, }, }) } ================================================ FILE: node-api/handlers/proof/types/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "github.com/berachain/beacon-kit/primitives/constraints" fastssz "github.com/ferranbt/fastssz" ) // BeaconStateMarshallable is the interface for a beacon state that can be // marshalled or hash tree rooted. type BeaconStateMarshallable interface { constraints.Versionable // GetTree is kept for FastSSZ compatibility. GetTree() (*fastssz.Node, error) } ================================================ FILE: node-api/handlers/proof/types/request.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import "github.com/berachain/beacon-kit/node-api/handlers/types" // BlockProposerRequest is the request for the // `/proof/block_proposer/{timestamp_id}` endpoint. type BlockProposerRequest struct { types.TimestampIDRequest } // ValidatorIndexRequest is a request that uses timestamp_id and validator_index. type ValidatorIndexRequest struct { types.TimestampIDRequest ValidatorIndex string `param:"validator_index" validate:"required,numeric"` } // ValidatorCredentialsRequest is the request for the // `/proof/validator_credentials/{timestamp_id}/{validator_index}` endpoint. type ValidatorCredentialsRequest = ValidatorIndexRequest // ValidatorBalanceRequest is the request for the // `/proof/validator_balance/{timestamp_id}/{validator_index}` endpoint. type ValidatorBalanceRequest = ValidatorIndexRequest // ValidatorPubkeyRequest is the request for the // `/proof/validator_pubkey/{timestamp_id}/{validator_index}` endpoint. type ValidatorPubkeyRequest = ValidatorIndexRequest ================================================ FILE: node-api/handlers/proof/types/response.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" ) // BlockProposerResponse is the response for the // `/proof/block_proposer/{timestamp_id}` endpoint. type BlockProposerResponse struct { // BeaconBlockHeader is the block header of which the hash tree root is the // beacon block root to verify against. BeaconBlockHeader *ctypes.BeaconBlockHeader `json:"beacon_block_header"` // BeaconBlockRoot is the beacon block root for this slot. BeaconBlockRoot common.Root `json:"beacon_block_root"` // ValidatorPubkey is the pubkey of the block proposer. ValidatorPubkey crypto.BLSPubkey `json:"validator_pubkey"` // ValidatorPubkeyProof can be verified against the beacon block root. Use // a Generalized Index of `z + (8 * ValidatorIndex)`, where z is the // Generalized Index of the 0 validator pubkey in the beacon block. In // the Deneb fork, z is 3254554418216960. ValidatorPubkeyProof []common.Root `json:"validator_pubkey_proof"` // ProposerIndexProof can be verified against the beacon block root. Use // a Generalized Index of 9 in the Deneb fork. ProposerIndexProof []common.Root `json:"proposer_index_proof"` } // ValidatorWithdrawalCredentialsResponse is the response for the // `/proof/validator_withdrawal_credentials/{timestamp_id}/{validator_index}` endpoint. type ValidatorWithdrawalCredentialsResponse struct { // BeaconBlockHeader is the block header of which the hash tree root is the // beacon block root to verify against. BeaconBlockHeader *ctypes.BeaconBlockHeader `json:"beacon_block_header"` // BeaconBlockRoot is the beacon block root for this slot. BeaconBlockRoot common.Root `json:"beacon_block_root"` // WithdrawalCredentials are the credentials of the requested validator. ValidatorWithdrawalCredentials ctypes.WithdrawalCredentials `json:"validator_withdrawal_credentials"` // WithdrawalCredentialsProof can be verified against the beacon block root. // Use a Generalized Index of `z + (8 * ValidatorIndex)`, where z is the // Generalized Index of the 0 validator withdrawal credentials in the beacon // block. In the Electra fork, z is 6350779162034177. WithdrawalCredentialsProof []common.Root `json:"withdrawal_credentials_proof"` } // ValidatorBalanceResponse is the response for the // `/proof/validator_balance/{timestamp_id}/{validator_index}` endpoint. type ValidatorBalanceResponse struct { // BeaconBlockHeader is the block header of which the hash tree root is the // beacon block root to verify against. BeaconBlockHeader *ctypes.BeaconBlockHeader `json:"beacon_block_header"` // BeaconBlockRoot is the beacon block root for this slot. BeaconBlockRoot common.Root `json:"beacon_block_root"` // ValidatorBalance is the balance of the requested validator. ValidatorBalance math.Gwei `json:"validator_balance"` // BalanceLeaf is the leaf containing the validator's balance along with up // to 3 other validators' balances (packed 4 per leaf). BalanceLeaf common.Root `json:"balance_leaf"` // BalanceProof can be verified against the beacon block root. // Use a Generalized Index of `z + (1 * (ValidatorIndex / 4))`, where z is the // Generalized Index of the 0-3 validators' balances in the beacon block. // In the Electra fork, z is 199011604627456. BalanceProof []common.Root `json:"balance_proof"` } // ValidatorPubkeyResponse is the response for the // `/proof/validator_pubkey/{timestamp_id}/{validator_index}` endpoint. type ValidatorPubkeyResponse struct { // BeaconBlockHeader is the block header of which the hash tree root is the // beacon block root to verify against. BeaconBlockHeader *ctypes.BeaconBlockHeader `json:"beacon_block_header"` // BeaconBlockRoot is the beacon block root for this slot. BeaconBlockRoot common.Root `json:"beacon_block_root"` // ValidatorPubkey is the pubkey of the requested validator. ValidatorPubkey crypto.BLSPubkey `json:"validator_pubkey"` // ValidatorPubkeyProof can be verified against the beacon block root. Use // a Generalized Index of `z + (8 * ValidatorIndex)`, where z is the // Generalized Index of the 0 validator pubkey in the beacon block. In // the Deneb fork, z is 3254554418216960; in the Electra fork, z is // 6350779162034176. ValidatorPubkeyProof []common.Root `json:"validator_pubkey_proof"` } ================================================ FILE: node-api/handlers/proof/validator_balance.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package proof import ( "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/node-api/handlers/proof/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/math" ) // GetValidatorBalance returns the balance of a validator along with a // Merkle proof that can be verified against the beacon block root. func (h *Handler) GetValidatorBalance(c handlers.Context) (any, error) { params, err := utils.BindAndValidate[types.ValidatorBalanceRequest](c, h.Logger()) if err != nil { return nil, err } // Validator index is provided as a string path parameter; convert to math.U64. validatorIndex, err := math.U64FromString(params.ValidatorIndex) if err != nil { return nil, err } slot, beaconState, blockHeader, err := h.resolveTimestampID(params.TimestampID) if err != nil { return nil, err } h.Logger().Info( "Generating balance proof", "slot", slot, "validator_index", validatorIndex, ) // Generate proof for balance in the block. bsm, err := beaconState.GetMarshallable() if err != nil { return nil, err } // Fetch all balances from state and construct the balance leaf using the // helper in the merkle package. allBalances, err := beaconState.GetBalances() if err != nil { return nil, err } balanceProof, balanceLeaf, beaconBlockRoot, err := merkle.ProveBalanceInBlock( validatorIndex, blockHeader, bsm, allBalances, ) if err != nil { return nil, err } // Fetch the balance to include in the response. balance, err := beaconState.GetBalance(validatorIndex) if err != nil { return nil, err } return types.ValidatorBalanceResponse{ BeaconBlockHeader: blockHeader, BeaconBlockRoot: beaconBlockRoot, ValidatorBalance: balance, BalanceLeaf: balanceLeaf, BalanceProof: balanceProof, }, nil } ================================================ FILE: node-api/handlers/proof/validator_credentials.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // False positive detected. package proof import ( "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/node-api/handlers/proof/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/math" ) // GetValidatorCredentials returns the withdrawal credentials of a validator along with a // Merkle proof that can be verified against the beacon block root. func (h *Handler) GetValidatorCredentials(c handlers.Context) (any, error) { params, err := utils.BindAndValidate[types.ValidatorCredentialsRequest](c, h.Logger()) if err != nil { return nil, err } // Validator index is provided as a string path parameter; convert to math.U64. validatorIndex, err := math.U64FromString(params.ValidatorIndex) if err != nil { return nil, err } slot, beaconState, blockHeader, err := h.resolveTimestampID(params.TimestampID) if err != nil { return nil, err } h.Logger().Info( "Generating withdrawal credential proof", "slot", slot, "validator_index", validatorIndex, ) // Generate proof for withdrawal credentials in the block. bsm, err := beaconState.GetMarshallable() if err != nil { return nil, err } credsProof, beaconBlockRoot, err := merkle.ProveWithdrawalCredentialsInBlock( validatorIndex, blockHeader, bsm, ) if err != nil { return nil, err } // Fetch the validator to get the withdrawal credentials to include in the response. validator, err := beaconState.ValidatorByIndex(validatorIndex) if err != nil { return nil, err } return types.ValidatorWithdrawalCredentialsResponse{ BeaconBlockHeader: blockHeader, BeaconBlockRoot: beaconBlockRoot, ValidatorWithdrawalCredentials: validator.GetWithdrawalCredentials(), WithdrawalCredentialsProof: credsProof, }, nil } ================================================ FILE: node-api/handlers/proof/validator_pubkey.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:dupl // False positive detected. package proof import ( "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" ptypes "github.com/berachain/beacon-kit/node-api/handlers/proof/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/math" ) // GetValidatorPubkey returns the pubkey of a validator along with a // Merkle proof that can be verified against the beacon block root. func (h *Handler) GetValidatorPubkey(c handlers.Context) (any, error) { params, err := utils.BindAndValidate[ptypes.ValidatorPubkeyRequest](c, h.Logger()) if err != nil { return nil, err } // Validator index is provided as a string path parameter; convert to math.U64. validatorIndex, err := math.U64FromString(params.ValidatorIndex) if err != nil { return nil, err } slot, beaconState, blockHeader, err := h.resolveTimestampID(params.TimestampID) if err != nil { return nil, err } h.Logger().Info( "Generating validator pubkey proof", "slot", slot, "validator_index", validatorIndex, ) // Generate proof for validator pubkey in the block. bsm, err := beaconState.GetMarshallable() if err != nil { return nil, err } pubkeyProof, beaconBlockRoot, err := merkle.ProveValidatorPubkeyInBlock( validatorIndex, blockHeader, bsm, ) if err != nil { return nil, err } // Fetch the validator to include the pubkey in the response. validator, err := beaconState.ValidatorByIndex(validatorIndex) if err != nil { return nil, err } return ptypes.ValidatorPubkeyResponse{ BeaconBlockHeader: blockHeader, BeaconBlockRoot: beaconBlockRoot, ValidatorPubkey: validator.GetPubkey(), ValidatorPubkeyProof: pubkeyProof, }, nil } ================================================ FILE: node-api/handlers/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package handlers import ( "github.com/berachain/beacon-kit/log" "github.com/labstack/echo/v4" ) type Context = echo.Context // handlerFn enforces a signature for all handler functions. type handlerFn func(c Context) (any, error) // Route is a route for the node API. type Route struct { Method string Path string Handler handlerFn } // DecorateWithLogs adds logging to the route's handler function as soon as // a request is received and when a response is ready. func (r *Route) DecorateWithLogs(logger log.Logger) { handler := r.Handler r.Handler = func(ctx Context) (any, error) { logger.Info("received request", "method", r.Method, "path", r.Path) res, err := handler(ctx) if err != nil { logger.Error("error handling request", "error", err) } logger.Info("request handled") return res, err } } // RouteSet is a set of routes for the node API. type RouteSet struct { BasePath string Routes []*Route } // NewRouteSet creates a new route set. func NewRouteSet(basePath string, routes ...*Route) *RouteSet { return &RouteSet{ BasePath: basePath, Routes: routes, } } ================================================ FILE: node-api/handlers/types/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import "errors" var ( ErrNotFound = errors.New("not found") ErrNotImplemented = errors.New("not implemented") ErrInvalidRequest = errors.New("invalid request") ) ================================================ FILE: node-api/handlers/types/request.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types type StateIDRequest struct { StateID string `param:"state_id" validate:"required,state_id"` } type BlockIDRequest struct { BlockID string `param:"block_id" validate:"required,block_id"` } type TimestampIDRequest struct { TimestampID string `param:"timestamp_id" validate:"required,timestamp_id"` } ================================================ FILE: node-api/handlers/utils/constants.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package utils const ( StateIDGenesis = "genesis" StateIDFinalized = "finalized" StateIDJustified = "justified" StateIDHead = "head" TimestampIDPrefix = "t" ) const ( Head int64 = -1 Genesis int64 = 0 ) ================================================ FILE: node-api/handlers/utils/context.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package utils import ( "fmt" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/types" ) // BindAndValidate binds the request to the context and validates it. func BindAndValidate[RequestT any](c handlers.Context, logger log.Logger) (RequestT, error) { var req RequestT if err := c.Bind(&req); err != nil { return req, fmt.Errorf("%w: failed to bind request: %s", types.ErrInvalidRequest, err.Error()) } if err := c.Validate(&req); err != nil { return req, fmt.Errorf("%w: failed to validate request: %s", types.ErrInvalidRequest, err.Error()) } logger.Info("Request validation successful", "params", req) return req, nil } ================================================ FILE: node-api/handlers/utils/mappings.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package utils import ( "fmt" stdmath "math" "strings" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) var ( ErrNoSlotForStateRoot = errors.New("slot not found at state root") ErrFailedMappingHeightTooHigh = errors.New("failed mapping height too high") ) // TODO: define unique types for each of the query-able IDs (state & block from // spec, execution unique to beacon-kit). For each type define validation // functions and resolvers to slot number. // StateIDToHeight returns a slot from the state ID. // // NOTE: Right now, `stateID` only supports querying by "head" (all of "head", // "finalized", "justified" are the same), "genesis", and . func StateIDToHeight[StorageBackendT interface { GetSlotByStateRoot(root common.Root) (math.Slot, error) }](stateID string, storage StorageBackendT) (int64, error) { if slot, err := stateIDToHeight(stateID); err == nil { return slot, nil } // We assume that the state ID is a state hash. root, err := common.NewRootFromHex(stateID) if err != nil { return 0, err } slot, err := storage.GetSlotByStateRoot(root) if err != nil { return 0, ErrNoSlotForStateRoot } if slot > stdmath.MaxInt64 { // appease linters return 0, fmt.Errorf("%w: slot %d", ErrFailedMappingHeightTooHigh, slot) } return int64(slot), nil //#nosec: G115 // practically safe } // BlockIDToHeight returns a height from the block ID. // // NOTE: `blockID` shares the same semantics as `stateID`, with the modification // of being able to query by beacon instead of . func BlockIDToHeight[StorageBackendT interface { GetSlotByBlockRoot(root common.Root) (math.Slot, error) }](blockID string, storage StorageBackendT) (int64, error) { if slot, err := stateIDToHeight(blockID); err == nil { return slot, nil } // We assume that the block ID is a block hash. root, err := common.NewRootFromHex(blockID) if err != nil { return 0, err } slot, err := storage.GetSlotByBlockRoot(root) if slot > stdmath.MaxInt64 { // appease linters return 0, fmt.Errorf("%w: slot %d", ErrFailedMappingHeightTooHigh, slot) } return int64(slot), err //#nosec: G115 // practically safe } // TimestampIDToParentHeight returns the parent slot corresponding to the // timestamp ID. // // NOTE: `timestampID` shares the same semantics as `stateID`, with the // modification of being able to query by next block's instead of // the current block's . // // The must be prefixed by the 't', followed by the timestamp // in decimal UNIX notation. For example 't1728681738' corresponds to the slot // which has the next block with a timestamp of 1728681738. Providing just the // string '1728681738' (without the prefix 't') will query for the beacon block // for slot 1728681738. func TimestampIDToParentHeight[StorageBackendT interface { GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) }](timestampID string, storage StorageBackendT) (int64, error) { if !IsTimestampIDPrefix(timestampID) { return stateIDToHeight(timestampID) } // Parse the timestamp from the timestampID. timestamp, err := math.U64FromString(timestampID[1:]) if err != nil { return 0, errors.Wrapf( err, "failed to parse timestamp from timestampID: %s", timestampID, ) } slot, err := storage.GetParentSlotByTimestamp(timestamp) if slot > stdmath.MaxInt64 { // appease linters return 0, fmt.Errorf("%w: slot %d", ErrFailedMappingHeightTooHigh, slot) } return int64(slot), err //#nosec: G115 // practically safe } // IsTimestampIDPrefix checks if the given timestampID is prefixed with the // correct prefix 't'. func IsTimestampIDPrefix(timestampID string) bool { return strings.HasPrefix(timestampID, TimestampIDPrefix) } // stateIDToHeight returns a slot number from the given state ID. // Returns -1 if chain tip is requested // Returns 0 if genesis is requested // Returns a positive integer if any chain slot is requested func stateIDToHeight(id string) (int64, error) { switch id { case StateIDFinalized, StateIDJustified, StateIDHead: return Head, nil case StateIDGenesis: return Genesis, nil default: slot, err := math.U64FromString(id) if err != nil { return 0, errors.Wrapf(err, "failed mapping stateID %q to slot", id) } if slot > stdmath.MaxInt64 { // appease linters return 0, fmt.Errorf("%w: slot %d", ErrFailedMappingHeightTooHigh, slot) } return int64(slot), nil //#nosec: G115 // practically safe } } ================================================ FILE: node-api/handlers/validator/handler.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package validator import ( "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" ) type Handler struct { *handlers.BaseHandler } func NewHandler(logger log.Logger) *Handler { h := &Handler{ BaseHandler: handlers.NewBaseHandler(logger), } registerRoutes(h) return h } ================================================ FILE: node-api/handlers/validator/routes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package validator import ( "net/http" "github.com/berachain/beacon-kit/node-api/handlers" ) func registerRoutes(h *Handler) { h.BaseHandler.AddRoutes([]*handlers.Route{ { Method: http.MethodPost, Path: "/eth/v1/validator/duties/attester/:epoch", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/validator/duties/proposer/:epoch", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/duties/sync/:epoch", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v3/validator/blocks/:slot", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/attestation_data", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/validator/aggregate_attestation", Handler: h.Deprecated, }, { Method: http.MethodGet, Path: "/eth/v2/validator/aggregate_attestation", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/aggregate_and_proofs", Handler: h.Deprecated, }, { Method: http.MethodPost, Path: "/eth/v2/validator/aggregate_and_proofs", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/beacon_committee_subscriptions", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/sync_committee_subscriptions", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/beacon_committee_selections", Handler: h.NotImplemented, }, { Method: http.MethodGet, Path: "/eth/v1/validator/sync_committee_contribution", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/contribution_and_proofs", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/prepare_beacon_proposer", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/register_validator", Handler: h.NotImplemented, }, { Method: http.MethodPost, Path: "/eth/v1/validator/liveness/:epoch", Handler: h.NotImplemented, }, }) } ================================================ FILE: node-api/middleware/middleware.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package middleware import ( "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/node-api/handlers" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" ) // Middleware is an implementation of the API engine interface using Echo. type Middleware struct { *echo.Echo logger log.Logger } // NewDefaultMiddleware returns a new default Echo Engine instance. func NewDefaultMiddleware(logger log.Logger) *Middleware { engine := echo.New() engine.Use(middleware.CORSWithConfig( middleware.DefaultCORSConfig, )) engine.Validator = &CustomValidator{ Validator: ConstructValidator(), } engine.HideBanner = true return &Middleware{ Echo: engine, logger: logger, } } // Run starts the Echo engine at the given address. func (e *Middleware) Run(addr string) error { return e.Echo.Start(addr) } // RegisterRoutes registers the given route set with the Echo engine. func (e *Middleware) RegisterRoutes(hs *handlers.RouteSet) { group := e.Group(hs.BasePath) for _, route := range hs.Routes { route.DecorateWithLogs(e.logger) group.Add( route.Method, route.Path, responseMiddleware(route), ) } } ================================================ FILE: node-api/middleware/request.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package middleware import ( "errors" "fmt" "net/http" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/math" "github.com/go-playground/validator/v10" "github.com/labstack/echo/v4" ) // TODO: these validators need to be un-janked to 1) not use `FieldLevel` for // repeated `.Field().String()` calls and 2) strongly type the allowed IDs, // putting validation logic on each type. // CustomValidator is a custom validator for the API. type CustomValidator struct { Validator *validator.Validate } // Validate validates the given interface. func (cv *CustomValidator) Validate(i interface{}) error { if err := cv.Validator.Struct(i); err != nil { var validationErrors validator.ValidationErrors hasValidationErrors := errors.As(err, &validationErrors) if !hasValidationErrors || len(validationErrors) == 0 { return nil } firstError := validationErrors[0] field := firstError.Field() value := firstError.Value() return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid %s: %s", field, value)) } return nil } func ConstructValidator() *validator.Validate { validators := map[string](func(fl validator.FieldLevel) bool){ "state_id": ValidateStateID, "block_id": ValidateBlockID, "timestamp_id": ValidateTimestampID, "validator_id": ValidateValidatorID, "epoch": ValidateUint64, "slot": ValidateUint64, "validator_status": ValidateValidatorStatus, "hex": ValidateHex, } validate := validator.New() for tag, fn := range validators { err := validate.RegisterValidation(tag, fn) if err != nil { panic(err) } } return validate } func ValidateStateID(fl validator.FieldLevel) bool { allowedValues := map[string]bool{ "head": true, "genesis": true, "finalized": true, "justified": true, } return validateStateBlockIDs(fl.Field().String(), allowedValues) } func ValidateBlockID(fl validator.FieldLevel) bool { allowedValues := map[string]bool{ "head": true, "genesis": true, "finalized": true, } return validateStateBlockIDs(fl.Field().String(), allowedValues) } func ValidateTimestampID(fl validator.FieldLevel) bool { allowedValues := map[string]bool{ utils.StateIDHead: true, utils.StateIDGenesis: true, utils.StateIDFinalized: true, utils.StateIDJustified: true, } value := fl.Field().String() if utils.IsTimestampIDPrefix(value) { return ValidateUint64Dec(value[1:]) } return validateStateBlockIDs(value, allowedValues) } func ValidateUint64Dec(value string) bool { if value == "" { return true } _, err := math.U64FromString(value) return err == nil } func ValidateUint64(fl validator.FieldLevel) bool { return ValidateUint64Dec(fl.Field().String()) } // ValidateValidatorID checks if the provided field is a valid // validator identifier. It validates against a hex-encoded public key // or a numeric validator index. func ValidateValidatorID(fl validator.FieldLevel) bool { var key crypto.BLSPubkey err := key.UnmarshalText([]byte(fl.Field().String())) if err == nil { return true } if ValidateUint64(fl) { return true } return false } // ValidateRoot checks if the provided field is a valid root. // It validates against a 32 byte hex-encoded root with "0x" prefix. func ValidateRoot(value string) bool { _, err := common.NewRootFromHex(value) return err == nil } func ValidateValidatorStatus(fl validator.FieldLevel) bool { // Eth Beacon Node API specs: https://hackmd.io/ofFJ5gOmQpu1jjHilHbdQQ allowedStatuses := map[string]bool{ constants.ValidatorStatusActiveExiting: true, constants.ValidatorStatusActiveOngoing: true, constants.ValidatorStatusActiveSlashed: true, constants.ValidatorStatusExitedSlashed: true, constants.ValidatorStatusExitedUnslashed: true, constants.ValidatorStatusPendingInitialized: true, constants.ValidatorStatusPendingQueued: true, constants.ValidatorStatusWithdrawalDone: true, constants.ValidatorStatusWithdrawalPossible: true, } return validateAllowedStrings(fl.Field().String(), allowedStatuses) } func validateAllowedStrings( value string, allowedValues map[string]bool, ) bool { if value == "" { return true } return allowedValues[value] } func validateStateBlockIDs(value string, allowedValues map[string]bool) bool { // Check if value is one of the allowed values if validateAllowedStrings(value, allowedValues) { return true } // Check if value is a slot (unsigned 64-bit integer) if ValidateUint64Dec(value) { return true } // Check if value is a hex-encoded 32 byte root with "0x" prefix if ValidateRoot(value) { return true } return false } func ValidateHex(fl validator.FieldLevel) bool { _, err := hex.IsValidHex(fl.Field().String()) return err == nil } ================================================ FILE: node-api/middleware/response.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package middleware import ( "net/http" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/node-api/handlers" "github.com/berachain/beacon-kit/node-api/handlers/types" "github.com/labstack/echo/v4" ) // ErrorResponse is a response that is returned when an error occurs. type ErrorResponse struct { Code int `json:"code"` Message string `json:"message"` } // responseMiddleware is a middleware that converts errors to an HTTP status // code and response. func responseMiddleware(handler *handlers.Route) echo.HandlerFunc { return func(c handlers.Context) error { data, err := handler.Handler(c) code, response := responseFromError(data, err) return c.JSON(code, response) } } // responseFromError converts an error to an HTTP status code and response. If // the error is nil, the response is returned as is. func responseFromError(data any, err error) (int, any) { switch { case err == nil: return http.StatusOK, data case errors.Is(err, types.ErrNotFound): return http.StatusNotFound, ErrorResponse{ Code: http.StatusNotFound, Message: err.Error(), } case errors.Is(err, types.ErrInvalidRequest): return http.StatusBadRequest, ErrorResponse{ Code: http.StatusBadRequest, Message: err.Error(), } case errors.Is(err, types.ErrNotImplemented): return http.StatusNotImplemented, ErrorResponse{ Code: http.StatusNotImplemented, Message: err.Error(), } default: return http.StatusInternalServerError, ErrorResponse{ Code: http.StatusInternalServerError, Message: err.Error(), } } } ================================================ FILE: node-api/server/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package server const ( defaultAddress = "127.0.0.1:3500" ) // Config is the configuration for the node API server. type Config struct { // Enabled is the flag to enable the node API server. Enabled bool `mapstructure:"enabled"` // Address is the address to bind the node API server to. Address string `mapstructure:"address"` // Logging is the flag to enable API logging. Logging bool `mapstructure:"logging"` } // DefaultConfig returns the default configuration for the node API server. func DefaultConfig() Config { return Config{ Enabled: false, Address: defaultAddress, Logging: false, } } ================================================ FILE: node-api/server/server.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package server import ( "context" "fmt" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/node-api/backend" beaconapi "github.com/berachain/beacon-kit/node-api/handlers/beacon" builderapi "github.com/berachain/beacon-kit/node-api/handlers/builder" cometbftapi "github.com/berachain/beacon-kit/node-api/handlers/cometbft" configapi "github.com/berachain/beacon-kit/node-api/handlers/config" debugapi "github.com/berachain/beacon-kit/node-api/handlers/debug" eventsapi "github.com/berachain/beacon-kit/node-api/handlers/events" nodeapi "github.com/berachain/beacon-kit/node-api/handlers/node" proofapi "github.com/berachain/beacon-kit/node-api/handlers/proof" "github.com/berachain/beacon-kit/node-api/middleware" "github.com/berachain/beacon-kit/node-core/components/storage" "github.com/berachain/beacon-kit/node-core/types" "github.com/berachain/beacon-kit/state-transition/core" cmtcfg "github.com/cometbft/cometbft/config" ) // Server is the API Server service. type Server struct { config Config logger log.Logger middleware *middleware.Middleware b *backend.Backend // exposed via getter for some tests. // TODO: consider extending this to other handlers beaconHandler *beaconapi.Handler } // New initializes a new API Server with the given config, engine, and logger. // It will inject a noop logger into the API handlers and engine if logging is // disabled. func New( config Config, logger log.Logger, // attributes to build handlers backend storageBackend *storage.Backend, sp *core.StateProcessor, cs chain.Spec, cmtCfg *cmtcfg.Config, // consensusService allows apis to access node state // and carry out all sorts of queries, including hystorical ones consensusService types.ConsensusService, ) *Server { apiLogger := logger if !config.Logging { apiLogger = noop.NewLogger[log.Logger]() } mware := middleware.NewDefaultMiddleware(apiLogger) // instantiate handlers and register their routes in the middleware b := backend.New(storageBackend, sp, cs, cmtCfg, consensusService) beaconHandler := beaconapi.NewHandler(b, cs, apiLogger) mware.RegisterRoutes(beaconHandler.RouteSet()) mware.RegisterRoutes(builderapi.NewHandler(apiLogger).RouteSet()) mware.RegisterRoutes(cometbftapi.NewHandler(b, apiLogger).RouteSet()) mware.RegisterRoutes(configapi.NewHandler(cs, apiLogger).RouteSet()) mware.RegisterRoutes(debugapi.NewHandler(b, apiLogger).RouteSet()) mware.RegisterRoutes(eventsapi.NewHandler(apiLogger).RouteSet()) mware.RegisterRoutes(nodeapi.NewHandler(b, apiLogger).RouteSet()) mware.RegisterRoutes(proofapi.NewHandler(b, apiLogger).RouteSet()) return &Server{ config: config, logger: logger, middleware: mware, b: b, beaconHandler: beaconHandler, } } // Start starts the API Server at the configured address. func (s *Server) Start(ctx context.Context) error { if !s.config.Enabled { return nil } // pre-load and cache all relevant node-api backend data if err := s.b.LoadData(ctx); err != nil { return fmt.Errorf("failed loading api backend data: %w", err) } go s.start(ctx) return nil } func (s *Server) start(ctx context.Context) { errCh := make(chan error) go func() { errCh <- s.middleware.Run(s.config.Address) }() for { select { case err := <-errCh: s.logger.Error(err.Error()) case <-ctx.Done(): return } } } func (s *Server) Stop() error { return s.b.Close() } // Name returns the name of the API server service. func (s *Server) Name() string { return "node-api-server" } func (s *Server) GetBeaconHandler() *beaconapi.Handler { return s.beaconHandler } ================================================ FILE: node-core/builder/baseapp_options.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "errors" "fmt" "os" "path/filepath" "cosmossdk.io/store" storetypes "cosmossdk.io/store/types" server "github.com/berachain/beacon-kit/cli/commands/server" "github.com/berachain/beacon-kit/config" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/cosmos/cosmos-sdk/client/flags" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" "github.com/spf13/cast" ) // This file contains Options that extend our default Service options to be // called by cosmos when building the app. // TODO: refactor into consensus_options for serverv2 migration. // DefaultServiceOptions returns the default Service options provided by the // Cosmos SDK. func DefaultServiceOptions( appOpts config.AppOptions, ) []func(*cometbft.Service) { var cache storetypes.MultiStorePersistentCache if cast.ToBool(appOpts.Get(server.FlagInterBlockCache)) { cache = store.NewCommitKVStoreCacheManager() } pruningOpts, err := server.GetPruningOptionsFromFlags(appOpts) if err != nil { panic(err) } // get chainID, possibly falling back to genesis if flag is not set chainID := cast.ToString(appOpts.Get(flags.FlagChainID)) if chainID == "" { chainID, err = loadChainIDFromGenesis(appOpts) if err != nil { panic(err) } } return []func(*cometbft.Service){ cometbft.SetPruning(pruningOpts), cometbft.SetMinRetainBlocks( cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks)), ), cometbft.SetInterBlockCache(cache), cometbft.SetIAVLCacheSize( cast.ToInt(appOpts.Get(server.FlagIAVLCacheSize)), ), cometbft.SetIAVLDisableFastNode( // default to true true, ), cometbft.SetChainID(chainID), } } func loadChainIDFromGenesis(appOpts config.AppOptions) (string, error) { var ( homeDir = cast.ToString(appOpts.Get(flags.FlagHome)) // TODO: This is quite inflexible and demands a genesis.json file name and directory fp = filepath.Join(homeDir, "config", "genesis.json") ) f, err := os.Open(filepath.Clean(fp)) if err != nil { return "", err } chainID, err := genutiltypes.ParseChainIDFromGenesis(f) if err != nil { return "", errors.Join( f.Close(), fmt.Errorf( "failed to parse chain-id from genesis file: %w", err, ), ) } return chainID, f.Close() } ================================================ FILE: node-core/builder/builder.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "io" "cosmossdk.io/depinject" servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/types" cmtcfg "github.com/cometbft/cometbft/config" dbm "github.com/cosmos/cosmos-db" ) // NodeBuilder is a construction helper for creating nodes that implement // the types.NodeI interface. // TODO: #Make nodebuilder build a node. Currently this is just a builder for // the AppCreator function, which is eventually called by cosmos to build a // node. type NodeBuilder struct { // components is a list of components to provide. components []any } // New returns a new NodeBuilder. func New(opts ...Opt) *NodeBuilder { nb := &NodeBuilder{} for _, opt := range opts { opt(nb) } return nb } // Build uses the node builder options and runtime parameters to // build a new instance of the node. // It is necessary to adhere to the types.AppCreator[T] interface. func (nb *NodeBuilder) Build( logger *phuslu.Logger, db dbm.DB, _ io.Writer, cmtCfg *cmtcfg.Config, appOpts servertypes.AppOptions, ) types.Node { // variables to hold the components needed to set up BeaconApp var ( beaconNode types.Node cmtService types.ConsensusService config *config.Config ) chainSpec, err := spec.Create(appOpts) if err != nil { panic(err) } // build all node components using depinject if err = depinject.Inject( depinject.Configs( depinject.Provide( nb.components..., ), depinject.Supply( appOpts, logger, db, cmtCfg, chainSpec, ), ), &beaconNode, &cmtService, &config, ); err != nil { panic(err) } if config == nil { panic("config is nil") } logger.WithConfig(config.GetLogger()) return beaconNode } ================================================ FILE: node-core/builder/options.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder // Opt is a type that defines a function that modifies NodeBuilder. type Opt func(*NodeBuilder) // WithComponents is a function that sets the components for the NodeBuilder. func WithComponents(components []any) Opt { return func(nb *NodeBuilder) { nb.components = components } } ================================================ FILE: node-core/components/api.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-api/server" "github.com/berachain/beacon-kit/node-core/components/storage" "github.com/berachain/beacon-kit/node-core/types" "github.com/berachain/beacon-kit/state-transition/core" cmtcfg "github.com/cometbft/cometbft/config" ) type NodeAPIServerInput struct { depinject.In Config *config.Config Logger *phuslu.Logger ChainSpec chain.Spec StorageBackend *storage.Backend StateProcessor *core.StateProcessor CometConfig *cmtcfg.Config ConsensusService types.ConsensusService } func ProvideNodeAPIServer(in NodeAPIServerInput) *server.Server { in.Logger.AddKeyValColor( "service", "node-api-server", log.Blue, ) return server.New( in.Config.NodeAPI, in.Logger.With("service", "node-api-server"), in.StorageBackend, in.StateProcessor, in.ChainSpec, in.CometConfig, in.ConsensusService, ) } ================================================ FILE: node-core/components/attributes_factory.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/payload/attributes" ) type AttributesFactoryInput struct { depinject.In ChainSpec chain.Spec Config *config.Config Logger *phuslu.Logger } // ProvideAttributesFactory provides an AttributesFactory for the client. func ProvideAttributesFactory(in AttributesFactoryInput) (*attributes.Factory, error) { return attributes.NewAttributesFactory( in.ChainSpec, in.Logger, in.Config.PayloadBuilder.SuggestedFeeRecipient, ), nil } ================================================ FILE: node-core/components/availability_store.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "os" "path/filepath" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/config" dastore "github.com/berachain/beacon-kit/da/store" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/storage/filedb" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cast" ) // AvailabilityStoreInput is the input for the ProviderAvailabilityStore // function for the depinject framework. type AvailabilityStoreInput struct { depinject.In AppOpts config.AppOptions Logger *phuslu.Logger } // ProvideAvailabilityStore provides the availability store. func ProvideAvailabilityStore(in AvailabilityStoreInput) (*dastore.Store, error) { var ( rootDir = cast.ToString(in.AppOpts.Get(flags.FlagHome)) blobsDir = filepath.Join(rootDir, "data", "blobs") ) return dastore.New( filedb.NewRangeDB( filedb.NewDB( filedb.WithRootDirectory(blobsDir), filedb.WithFileExtension("ssz"), filedb.WithDirectoryPermissions(os.ModePerm), filedb.WithLogger(in.Logger), ), ), in.Logger.With("service", "da-store"), ), nil } ================================================ FILE: node-core/components/backend.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/consensus-types/types" dastore "github.com/berachain/beacon-kit/da/store" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/node-core/components/storage" "github.com/berachain/beacon-kit/storage/beacondb" "github.com/berachain/beacon-kit/storage/block" "github.com/berachain/beacon-kit/storage/deposit" ) // StorageBackendInput is the input for the ProvideStorageBackend function. type StorageBackendInput struct { depinject.In AvailabilityStore *dastore.Store BlockStore *block.KVStore[*types.BeaconBlock] ChainSpec chain.Spec DepositStore deposit.StoreManager BeaconStore *beacondb.KVStore Logger *phuslu.Logger TelemetrySink *metrics.TelemetrySink } // ProvideStorageBackend is the depinject provider that returns a beacon storage // backend. func ProvideStorageBackend( in StorageBackendInput, ) *storage.Backend { return storage.NewBackend( in.ChainSpec, in.AvailabilityStore, in.BeaconStore, in.DepositStore, in.BlockStore, in.Logger.With("service", "storage-backend"), in.TelemetrySink, ) } ================================================ FILE: node-core/components/blobs.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/cli/flags" "github.com/berachain/beacon-kit/config" dablob "github.com/berachain/beacon-kit/da/blob" "github.com/berachain/beacon-kit/da/kzg" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/components/metrics" gokzg4844 "github.com/crate-crypto/go-kzg-4844" "github.com/spf13/cast" ) // BlobProofVerifierInput is the input for the // dep inject framework. type BlobProofVerifierInput struct { depinject.In AppOpts config.AppOptions JSONTrustedSetup *gokzg4844.JSONTrustedSetup } // ProvideBlobProofVerifier is a function that provides the module to the // application. func ProvideBlobProofVerifier( in BlobProofVerifierInput, ) (kzg.BlobProofVerifier, error) { return kzg.NewBlobProofVerifier( cast.ToString(in.AppOpts.Get(flags.KZGImplementation)), in.JSONTrustedSetup, ) } // BlobProcessorIn is the input for the BlobProcessor. type BlobProcessorIn struct { depinject.In BlobProofVerifier kzg.BlobProofVerifier Logger *phuslu.Logger TelemetrySink *metrics.TelemetrySink } // ProvideBlobProcessor is a function that provides the BlobProcessor to the // depinject framework. func ProvideBlobProcessor(in BlobProcessorIn) *dablob.Processor { return dablob.NewProcessor( in.Logger.With("service", "blob-processor"), in.BlobProofVerifier, in.TelemetrySink, ) } ================================================ FILE: node-core/components/block_store.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/config" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/storage/block" ) // BlockStoreInput is the input for the dep inject framework. type BlockStoreInput struct { depinject.In Config *config.Config Logger *phuslu.Logger } // ProvideBlockStore is a function that provides the module to the // application. func ProvideBlockStore(in BlockStoreInput) (*block.KVStore[*ctypes.BeaconBlock], error) { return block.NewStore[*ctypes.BeaconBlock]( in.Logger.With("service", "block-store"), in.Config.BlockStoreService.AvailabilityWindow, ), nil } ================================================ FILE: node-core/components/chain_service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/beacon/blockchain" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/execution/deposit" "github.com/berachain/beacon-kit/execution/engine" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/node-core/components/storage" ) // ChainServiceInput is the input for the chain service provider. type ChainServiceInput struct { depinject.In ChainSpec chain.Spec ExecutionEngine *engine.Engine LocalBuilder LocalBuilder Logger *phuslu.Logger StateProcessor StateProcessor StorageBackend *storage.Backend BlobProcessor BlobProcessor TelemetrySink *metrics.TelemetrySink BeaconDepositContract deposit.Contract } // ProvideChainService is a depinject provider for the blockchain service. func ProvideChainService(in ChainServiceInput) *blockchain.Service { return blockchain.NewService( in.StorageBackend, in.BlobProcessor, in.BeaconDepositContract, in.Logger.With("service", "blockchain"), in.ChainSpec, in.ExecutionEngine, in.LocalBuilder, in.StateProcessor, in.TelemetrySink, ) } ================================================ FILE: node-core/components/cometbft_service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "github.com/berachain/beacon-kit/beacon/blockchain" "github.com/berachain/beacon-kit/beacon/validator" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/builder" "github.com/berachain/beacon-kit/node-core/components/metrics" cmtcfg "github.com/cometbft/cometbft/config" dbm "github.com/cosmos/cosmos-db" ) // ProvideCometBFTService provides the CometBFT service component. func ProvideCometBFTService( logger *phuslu.Logger, blockchain blockchain.BlockchainI, blockBuilder validator.BlockBuilderI, db dbm.DB, cs chain.Spec, cmtCfg *cmtcfg.Config, appOpts config.AppOptions, telemetrySink *metrics.TelemetrySink, ) *cometbft.Service { return cometbft.NewService( logger, db, blockchain, blockBuilder, cs, cmtCfg, telemetrySink, builder.DefaultServiceOptions(appOpts)..., ) } ================================================ FILE: node-core/components/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/config" ) // ConfigInput is the input for the dependency injection framework. type ConfigInput struct { depinject.In AppOpts config.AppOptions } // ProvideConfig is a function that provides the BeaconConfig to the // application. func ProvideConfig(in ConfigInput) (*config.Config, error) { // AppOpts is not populated when called from CLI // Read the directory return config.ReadConfigFromAppOpts(in.AppOpts) } ================================================ FILE: node-core/components/config_server.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "errors" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/config" sdkconfig "github.com/berachain/beacon-kit/config/config" "github.com/mitchellh/mapstructure" "github.com/spf13/viper" ) // ServerConfigInput is the input for the dependency injection framework. type ServerConfigInput struct { depinject.In AppOpts config.AppOptions } // ProvideConfig is a function that provides the BeaconConfig to the // application. func ProvideServerConfig(in ConfigInput) (*sdkconfig.Config, error) { v, ok := in.AppOpts.(*viper.Viper) if !ok { return nil, errors.New("invalid application options type") } cfg := sdkconfig.Config{} if err := v.Unmarshal(&cfg, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), ))); err != nil { return nil, err } return &cfg, nil } ================================================ FILE: node-core/components/deposit_contract.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/execution/deposit" ) // DepositContractInput is the input for the deposit contract // for the dep inject framework. type DepositContractInput struct { depinject.In ChainSpec chain.Spec EngineClient *client.EngineClient } // ProvideDepositContract provides a deposit contract through the // dep inject framework. func ProvideDepositContract( in DepositContractInput, ) (*deposit.WrappedDepositContract, error) { // Build the deposit contract. return deposit.NewWrappedDepositContract( in.ChainSpec.DepositContractAddress(), in.EngineClient, ) } ================================================ FILE: node-core/components/deposit_store.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "path/filepath" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/storage/deposit" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cast" ) // DepositStoreInput is the input for the dep inject framework. type DepositStoreInput struct { depinject.In Logger *phuslu.Logger AppOpts config.AppOptions } // ProvideDepositStore is a function that provides the module to the // application. func ProvideDepositStore(in DepositStoreInput) (deposit.StoreManager, error) { var ( rootDir = cast.ToString(in.AppOpts.Get(flags.FlagHome)) dataDir = filepath.Join(rootDir, "data") nameV1 = "deposits" ) dbV1, err := dbm.NewDB(nameV1, dbm.PebbleDBBackend, dataDir) if err != nil { return nil, err } return deposit.NewStore( dbV1, in.Logger.With("service", "deposit-store"), ), nil } ================================================ FILE: node-core/components/engine.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "math/big" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/execution/engine" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/net/jwt" ) // EngineClientInputs is the input for the EngineClient. type EngineClientInputs struct { depinject.In ChainSpec chain.Spec Config *config.Config // TODO: this feels like a hood way to handle it. JWTSecret *jwt.Secret `optional:"true"` Logger *phuslu.Logger TelemetrySink *metrics.TelemetrySink } // ProvideEngineClient creates a new EngineClient. func ProvideEngineClient(in EngineClientInputs) *client.EngineClient { return client.New( in.Config.GetEngine(), in.Logger.With("service", "engine.client"), in.JWTSecret, in.TelemetrySink, new(big.Int).SetUint64(in.ChainSpec.DepositEth1ChainID()), ) } // EngineClientInputs is the input for the EngineClient. type ExecutionEngineInputs struct { depinject.In EngineClient *client.EngineClient Logger *phuslu.Logger TelemetrySink *metrics.TelemetrySink } // ProvideExecutionEngine provides the execution engine to the depinject // framework. func ProvideExecutionEngine(in ExecutionEngineInputs) *engine.Engine { return engine.New( in.EngineClient, in.Logger.With("service", "execution-engine"), in.TelemetrySink, ) } ================================================ FILE: node-core/components/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "context" "github.com/berachain/beacon-kit/chain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" dastore "github.com/berachain/beacon-kit/da/store" datypes "github.com/berachain/beacon-kit/da/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/node-api/backend" "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/state-transition/core" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage/block" "github.com/berachain/beacon-kit/storage/deposit" ) type ( // AttributesFactory is the interface for the attributes factory. AttributesFactory interface { BuildPayloadAttributes( timestamp math.U64, payloadWithdrawals engineprimitives.Withdrawals, prevRandao common.Bytes32, prevHeadRoot common.Root, parentProposerPubkey *crypto.BLSPubkey, ) (*engineprimitives.PayloadAttributes, error) } // BlobProcessor is the interface for the blobs processor. BlobProcessor interface { // ProcessSidecars processes the blobs and ensures they match the local // state. ProcessSidecars( avs *dastore.Store, sidecars datypes.BlobSidecars, ) error // VerifySidecars verifies the blobs and ensures they match the local // state. VerifySidecars( ctx context.Context, sidecars datypes.BlobSidecars, blkHeader *ctypes.BeaconBlockHeader, kzgCommitments eip4844.KZGCommitments[common.ExecutionHash], ) error } // LocalBuilder is the interface for the builder service. LocalBuilder interface { // Enabled returns true if the local builder is enabled. Enabled() bool // RequestPayloadAsync requests a new payload for the given slot. RequestPayloadAsync( ctx context.Context, r *builder.RequestPayloadData, ) (*engineprimitives.PayloadID, common.Version, error) // RetrievePayload retrieves the payload for the given slot and parentBlockRoot. // If returned error is nil, payload is guaranteed to have expectedForkVersion version. RetrievePayload( ctx context.Context, slot math.Slot, parentBlockRoot common.Root, expectedForkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) // RequestPayloadSync requests a payload for the given slot and // blocks until the payload is delivered. RequestPayloadSync( ctx context.Context, r *builder.RequestPayloadData, ) (ctypes.BuiltExecutionPayloadEnv, error) CacheLatestVerifiedPayload( latestEnvelopeSlot math.Slot, latestEnvelope ctypes.BuiltExecutionPayloadEnv, ) } // // PayloadAttributes is the interface for the payload attributes. // PayloadAttributes[T any, WithdrawalT any] interface { // engineprimitives.PayloadAttributer // // New creates a new payload attributes instance. // New( // uint32, // uint64, // common.Bytes32, // common.ExecutionAddress, // []WithdrawalT, // common.Root, // ) (T, error) // }. // StateProcessor defines the interface for processing the state. StateProcessor interface { // InitializeBeaconStateFromEth1 initializes the premined beacon // state // from the eth1 deposits. InitializeBeaconStateFromEth1( *statedb.StateDB, ctypes.Deposits, *ctypes.ExecutionPayloadHeader, common.Version, ) (transition.ValidatorUpdates, error) // ProcessFork prepares the state for the fork version at the given timestamp. ProcessFork( st *statedb.StateDB, timestamp math.U64, logUpgrade bool, ) error // ProcessSlot processes the slot. ProcessSlots( st *statedb.StateDB, slot math.Slot, ) (transition.ValidatorUpdates, error) // Transition performs the core state transition. Transition( ctx core.ReadOnlyContext, st *statedb.StateDB, blk *ctypes.BeaconBlock, ) (transition.ValidatorUpdates, error) GetSignatureVerifierFn(st *statedb.StateDB) ( func(blk *ctypes.BeaconBlock, signature crypto.BLSSignature) error, error, ) } SidecarFactory interface { // BuildSidecars builds sidecars for a given block and blobs bundle. BuildSidecars( signedBlk *ctypes.SignedBeaconBlock, blobs engineprimitives.BlobsBundle, ) (datypes.BlobSidecars, error) } // StorageBackend defines an interface for accessing various storage // components required by the beacon node. StorageBackend interface { AvailabilityStore() *dastore.Store BlockStore() *block.KVStore[*ctypes.BeaconBlock] DepositStore() deposit.StoreManager // StateFromContext retrieves the beacon state from the given context. StateFromContext(context.Context) *statedb.StateDB } // // TelemetrySink is an interface for sending metrics to a telemetry // backend. // TelemetrySink interface { // // MeasureSince measures the time since the given time. // MeasureSince(key string, start time.Time, args ...string) // } // // Validator represents an interface for a validator with generic type // // ValidatorT. // Validator[ // ValidatorT any, // WithdrawalCredentialsT any, // ] interface { // constraints.Empty[ValidatorT] // constraints.SSZMarshallableRootable // SizeSSZ() uint32 // // New creates a new validator with the given parameters. // New( // pubkey crypto.BLSPubkey, // withdrawalCredentials WithdrawalCredentialsT, // amount math.Gwei, // effectiveBalanceIncrement math.Gwei, // maxEffectiveBalance math.Gwei, // ) ValidatorT // // IsSlashed returns true if the validator is slashed. // IsSlashed() bool // // IsActive checks if the validator is active at the given epoch. // IsActive(epoch math.Epoch) bool // // GetPubkey returns the public key of the validator. // GetPubkey() crypto.BLSPubkey // // GetEffectiveBalance returns the effective balance of the validator // in // // Gwei. // GetEffectiveBalance() math.Gwei // // SetEffectiveBalance sets the effective balance of the validator in // // Gwei. // SetEffectiveBalance(math.Gwei) // // GetWithdrawableEpoch returns the epoch when the validator can // // withdraw. // GetWithdrawableEpoch() math.Epoch // // GetWithdrawalCredentials returns the withdrawal credentials of the // // validator. // GetWithdrawalCredentials() WithdrawalCredentialsT // // IsFullyWithdrawable checks if the validator is fully withdrawable // // given a // // certain Gwei amount and epoch. // IsFullyWithdrawable(amount math.Gwei, epoch math.Epoch) bool // // IsPartiallyWithdrawable checks if the validator is partially // // withdrawable // // given two Gwei amounts. // IsPartiallyWithdrawable(amount1 math.Gwei, amount2 math.Gwei) bool // } // Validators[ValidatorT any] interface { // ~[]ValidatorT // HashTreeRoot() common.Root // } // Withdrawal is the interface for a withdrawal. Withdrawal[T any] interface { New( index math.U64, validatorIndex math.ValidatorIndex, address common.ExecutionAddress, amount math.Gwei, ) T // Equals returns true if the withdrawal is equal to the other. Equals(T) bool // GetAmount returns the amount of the withdrawal. GetAmount() math.Gwei // GetIndex returns the public key of the validator. GetIndex() math.U64 // GetValidatorIndex returns the index of the validator. GetValidatorIndex() math.ValidatorIndex // GetAddress returns the address of the withdrawal. GetAddress() common.ExecutionAddress } // // WithdrawalCredentials represents an interface for withdrawal // credentials. // // WithdrawalCredentials interface { // ~[32]byte // // ToExecutionAddress converts the withdrawal credentials to an // // execution // // address. // ToExecutionAddress() (common.ExecutionAddress, error) // } ) /* -------------------------------------------------------------------------- */ /* BeaconState */ /* -------------------------------------------------------------------------- */ type ( // BeaconStore is the interface for the beacon store. BeaconStore[ T any, ] interface { // Context returns the context of the key-value store. Context() context.Context // WithContext returns a new key-value store with the given context. WithContext( ctx context.Context, ) T // Copy returns a copy of the key-value store. Copy(context.Context) T // GetLatestExecutionPayloadHeader retrieves the latest execution // payload // header. GetLatestExecutionPayloadHeader() (*ctypes.ExecutionPayloadHeader, error) // SetLatestExecutionPayloadHeader sets the latest execution payload // header. SetLatestExecutionPayloadHeader(payloadHeader *ctypes.ExecutionPayloadHeader) error // GetEth1DepositIndex retrieves the eth1 deposit index. GetEth1DepositIndex() (uint64, error) // SetEth1DepositIndex sets the eth1 deposit index. SetEth1DepositIndex( index uint64, ) error // GetBalance retrieves the balance of a validator. GetBalance(idx math.ValidatorIndex) (math.Gwei, error) // SetBalance sets the balance of a validator. SetBalance(idx math.ValidatorIndex, balance math.Gwei) error // GetSlot retrieves the current slot. GetSlot() (math.Slot, error) // SetSlot sets the current slot. SetSlot(slot math.Slot) error // GetFork retrieves the fork. GetFork() (*ctypes.Fork, error) // SetFork sets the fork. SetFork(fork *ctypes.Fork) error // GetGenesisValidatorsRoot retrieves the genesis validators root. GetGenesisValidatorsRoot() (common.Root, error) // SetGenesisValidatorsRoot sets the genesis validators root. SetGenesisValidatorsRoot(root common.Root) error // GetLatestBlockHeader retrieves the latest block header. GetLatestBlockHeader() (*ctypes.BeaconBlockHeader, error) // SetLatestBlockHeader sets the latest block header. SetLatestBlockHeader(header *ctypes.BeaconBlockHeader) error // GetBlockRootAtIndex retrieves the block root at the given index. GetBlockRootAtIndex(index uint64) (common.Root, error) // StateRootAtIndex retrieves the state root at the given index. StateRootAtIndex(index uint64) (common.Root, error) // GetEth1Data retrieves the eth1 data. GetEth1Data() (*ctypes.Eth1Data, error) // SetEth1Data sets the eth1 data. SetEth1Data(data *ctypes.Eth1Data) error // GetValidators retrieves all validators. GetValidators() (ctypes.Validators, error) // GetBalances retrieves all balances. GetBalances() ([]uint64, error) // GetNextWithdrawalIndex retrieves the next withdrawal index. GetNextWithdrawalIndex() (uint64, error) // SetNextWithdrawalIndex sets the next withdrawal index. SetNextWithdrawalIndex(index uint64) error // GetNextWithdrawalValidatorIndex retrieves the next withdrawal // validator // index. GetNextWithdrawalValidatorIndex() (math.ValidatorIndex, error) // SetNextWithdrawalValidatorIndex sets the next withdrawal validator // index. SetNextWithdrawalValidatorIndex(index math.ValidatorIndex) error // GetTotalSlashing retrieves the total slashing. GetTotalSlashing() (math.Gwei, error) // SetTotalSlashing sets the total slashing. SetTotalSlashing(total math.Gwei) error // GetRandaoMixAtIndex retrieves the randao mix at the given index. GetRandaoMixAtIndex(index uint64) (common.Bytes32, error) // GetSlashings retrieves all slashings. GetSlashings() ([]math.Gwei, error) // SetSlashingAtIndex sets the slashing at the given index. SetSlashingAtIndex(index uint64, amount math.Gwei) error // GetSlashingAtIndex retrieves the slashing at the given index. GetSlashingAtIndex(index uint64) (math.Gwei, error) // GetTotalValidators retrieves the total validators. GetTotalValidators() (uint64, error) // ValidatorByIndex retrieves the validator at the given index. ValidatorByIndex(index math.ValidatorIndex) (*ctypes.Validator, error) // UpdateBlockRootAtIndex updates the block root at the given index. UpdateBlockRootAtIndex(index uint64, root common.Root) error // UpdateStateRootAtIndex updates the state root at the given index. UpdateStateRootAtIndex(index uint64, root common.Root) error // UpdateRandaoMixAtIndex updates the randao mix at the given index. UpdateRandaoMixAtIndex(index uint64, mix common.Bytes32) error // UpdateValidatorAtIndex updates the validator at the given index. UpdateValidatorAtIndex( index math.ValidatorIndex, validator *ctypes.Validator, ) error // ValidatorIndexByPubkey retrieves the validator index by the given // pubkey. ValidatorIndexByPubkey( pubkey crypto.BLSPubkey, ) (math.ValidatorIndex, error) // AddValidator adds a validator. AddValidator(val *ctypes.Validator) error // ValidatorIndexByCometBFTAddress retrieves the validator index by the // given comet BFT address. ValidatorIndexByCometBFTAddress( cometBFTAddress []byte, ) (math.ValidatorIndex, error) } // ReadOnlyBeaconState is the interface for a read-only beacon state. ReadOnlyBeaconState interface { ReadOnlyEth1Data ReadOnlyRandaoMixes ReadOnlyStateRoots ReadOnlyValidators ReadOnlyWithdrawals // GetBalances retrieves all balances. GetBalances() ([]uint64, error) GetBalance(math.ValidatorIndex) (math.Gwei, error) GetSlot() (math.Slot, error) GetFork() (*ctypes.Fork, error) GetGenesisValidatorsRoot() (common.Root, error) GetBlockRootAtIndex(uint64) (common.Root, error) GetLatestBlockHeader() (*ctypes.BeaconBlockHeader, error) GetValidators() (ctypes.Validators, error) GetSlashingAtIndex(uint64) (math.Gwei, error) GetTotalSlashing() (math.Gwei, error) GetNextWithdrawalIndex() (uint64, error) GetNextWithdrawalValidatorIndex() (math.ValidatorIndex, error) GetTotalValidators() (math.U64, error) ValidatorIndexByCometBFTAddress( cometBFTAddress []byte, ) (math.ValidatorIndex, error) } // WriteOnlyBeaconState is the interface for a write-only beacon state. WriteOnlyBeaconState interface { WriteOnlyEth1Data WriteOnlyRandaoMixes WriteOnlyStateRoots WriteOnlyValidators SetGenesisValidatorsRoot(root common.Root) error SetFork(*ctypes.Fork) error SetSlot(math.Slot) error UpdateBlockRootAtIndex(uint64, common.Root) error SetLatestBlockHeader(*ctypes.BeaconBlockHeader) error IncreaseBalance(math.ValidatorIndex, math.Gwei) error DecreaseBalance(math.ValidatorIndex, math.Gwei) error SetNextWithdrawalIndex(uint64) error SetNextWithdrawalValidatorIndex(math.ValidatorIndex) error SetTotalSlashing(math.Gwei) error } // WriteOnlyStateRoots defines a struct which only has write access to state // roots methods. WriteOnlyStateRoots interface { UpdateStateRootAtIndex(uint64, common.Root) error } // ReadOnlyStateRoots defines a struct which only has read access to state // roots // methods. ReadOnlyStateRoots interface { StateRootAtIndex(uint64) (common.Root, error) } // WriteOnlyRandaoMixes defines a struct which only has write access to // randao // mixes methods. WriteOnlyRandaoMixes interface { UpdateRandaoMixAtIndex(uint64, common.Bytes32) error } // ReadOnlyRandaoMixes defines a struct which only has read access to randao // mixes methods. ReadOnlyRandaoMixes interface { GetRandaoMixAtIndex(uint64) (common.Bytes32, error) } // WriteOnlyValidators has write access to validator methods. WriteOnlyValidators interface { UpdateValidatorAtIndex( math.ValidatorIndex, *ctypes.Validator, ) error AddValidator(*ctypes.Validator) error } // ReadOnlyValidators has read access to validator methods. ReadOnlyValidators interface { ValidatorIndexByPubkey( crypto.BLSPubkey, ) (math.ValidatorIndex, error) ValidatorByIndex( math.ValidatorIndex, ) (*ctypes.Validator, error) } // WriteOnlyEth1Data has write access to eth1 data. WriteOnlyEth1Data interface { SetEth1Data(*ctypes.Eth1Data) error SetEth1DepositIndex(uint64) error SetLatestExecutionPayloadHeader(*ctypes.ExecutionPayloadHeader) error } // ReadOnlyEth1Data has read access to eth1 data. ReadOnlyEth1Data interface { GetEth1Data() (*ctypes.Eth1Data, error) GetEth1DepositIndex() (uint64, error) GetLatestExecutionPayloadHeader() (*ctypes.ExecutionPayloadHeader, error) } // ReadOnlyWithdrawals only has read access to withdrawal methods. ReadOnlyWithdrawals interface { EVMInflationWithdrawal(math.Slot) *engineprimitives.Withdrawal } ) // /* -------------------------------------------------------------------------- // */ /* NodeAPI // */ /* // -------------------------------------------------------------------------- */ type ( NodeAPIContext interface { Bind(any) error Validate(any) error } NodeAPIBackend interface { GetSlotByBlockRoot(root common.Root) (math.Slot, error) GetSlotByStateRoot(root common.Root) (math.Slot, error) GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) NodeAPIBeaconBackend NodeAPIProofBackend NodeAPINodeBackend NodeAPIConfigBackend } // NodeAPIBeaconBackend is the interface for backend of the beacon API. NodeAPIBeaconBackend interface { GenesisBackend BlockBackend StateBackend // GetSlotByBlockRoot retrieves the slot by a given root from the store. GetSlotByBlockRoot(root common.Root) (math.Slot, error) // GetSlotByStateRoot retrieves the slot by a given root from the store. GetSlotByStateRoot(root common.Root) (math.Slot, error) } // NodeAPIConfigBackend is the interface for backend of the config API. NodeAPIConfigBackend interface { Spec() (chain.Spec, error) } // NodeAPIProofBackend is the interface for backend of the proof API. NodeAPIProofBackend interface { BlockBackend StateBackend GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) } NodeAPINodeBackend interface { GetSyncData() (latestHeight int64, syncToHeight int64) GetVersionData() ( appName, version, os, arch string, ) } GenesisBackend interface { GenesisValidatorsRoot() (common.Root, error) GenesisForkVersion() (common.Version, error) GenesisTime() (math.U64, error) } BlockBackend interface { BlockRootAtSlot(slot math.Slot) (common.Root, error) BlockRewardsAtSlot(slot math.Slot) (*types.BlockRewardsData, error) BlockHeaderAtSlot(slot math.Slot) (*ctypes.BeaconBlockHeader, error) } StateBackend interface { StateAndSlotFromHeight(height int64) (backend.ReadOnlyBeaconState, math.Slot, error) } ) ================================================ FILE: node-core/components/jwt_secret.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "fmt" "strings" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/cli/flags" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/primitives/net/jwt" "github.com/spf13/afero" "github.com/spf13/cast" ) // JWTSecretInput is the input for the dep inject framework. type JWTSecretInput struct { depinject.In AppOpts config.AppOptions } // ProvideJWTSecret is a function that provides the module to the application. func ProvideJWTSecret(in JWTSecretInput) (*jwt.Secret, error) { return LoadJWTFromFile(cast.ToString(in.AppOpts.Get(flags.JWTSecretPath))) } // LoadJWTFromFile reads the JWT secret from a file and returns it. func LoadJWTFromFile(filePath string) (*jwt.Secret, error) { data, err := afero.ReadFile(afero.NewOsFs(), filePath) if err != nil { return nil, fmt.Errorf("failed reading path '%s', err: %w", filePath, err) } return jwt.NewFromHex(strings.TrimSpace(string(data))) } ================================================ FILE: node-core/components/metrics/sink.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package metrics import ( "time" "github.com/cosmos/cosmos-sdk/telemetry" "github.com/hashicorp/go-metrics" ) type TelemetrySink struct{} // NewTelemetrySink creates a new TelemetrySink. func NewTelemetrySink() TelemetrySink { return TelemetrySink{} } // IncrementCounter increments a counter metric identified by the provided // keys. func (TelemetrySink) IncrementCounter(key string, args ...string) { telemetry.IncrCounterWithLabels([]string{key}, 1, argsToLabels(args...)) } // SetGauge sets a gauge metric to the specified value, identified by the // provided keys. func (TelemetrySink) SetGauge(key string, value int64, args ...string) { telemetry.SetGaugeWithLabels( []string{key}, float32(value), argsToLabels(args...), ) } // MeasureSince measures the time since the provided start time and records // the duration in a metric identified by the provided key. func (TelemetrySink) MeasureSince(key string, start time.Time, args ...string) { if !telemetry.IsTelemetryEnabled() { return } // TODO: Make PR to SDK, currently this will not have any globalLabels. metrics.MeasureSinceWithLabels( []string{key}, start.UTC(), argsToLabels(args...), ) } // argsToLabels converts a list of key-value pairs to a list of metrics labels. // //nolint:mnd // its okay. func argsToLabels(args ...string) []metrics.Label { labels := make([]metrics.Label, len(args)/2) for i := 0; i < len(args); i += 2 { labels[i/2] = metrics.Label{ Name: args[i], Value: args[i+1], } } return labels } // NoOpTelemetrySink is a no-op implementation of the TelemetrySink interface. type NoOpTelemetrySink struct{} // NewNoOpTelemetrySink creates a new NoOpTelemetrySink. func NewNoOpTelemetrySink() NoOpTelemetrySink { return NoOpTelemetrySink{} } // IncrementCounter is a no-op implementation of the TelemetrySink interface. func (NoOpTelemetrySink) IncrementCounter(string, ...string) {} // SetGauge is a no-op implementation of the TelemetrySink interface. func (NoOpTelemetrySink) SetGauge(string, int64, ...string) {} // MeasureSince is a no-op implementation of the TelemetrySink interface. func (NoOpTelemetrySink) MeasureSince(string, time.Time, ...string) {} ================================================ FILE: node-core/components/node.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/node" service "github.com/berachain/beacon-kit/node-core/services/registry" "github.com/berachain/beacon-kit/node-core/types" ) type ProvideNodeInputs struct { depinject.In Config *config.Config Registry *service.Registry Logger *phuslu.Logger } // ProvideNode returns a new node with the given options. func ProvideNode(in ProvideNodeInputs) types.Node { return node.New[types.Node](in.Config.ShutdownTimeout, in.Registry, in.Logger) } ================================================ FILE: node-core/components/payload_builder.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/execution/engine" "github.com/berachain/beacon-kit/log/phuslu" payloadbuilder "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/payload/cache" ) // LocalBuilderInput is an input for the dep inject framework. type LocalBuilderInput struct { depinject.In AttributesFactory AttributesFactory Cfg *config.Config ChainSpec chain.Spec ExecutionEngine *engine.Engine Logger *phuslu.Logger } // ProvideLocalBuilder provides a local payload builder for the // depinject framework. func ProvideLocalBuilder(in LocalBuilderInput) *payloadbuilder.PayloadBuilder { return payloadbuilder.New( &in.Cfg.PayloadBuilder, in.ChainSpec, in.Logger.With("service", "payload-builder"), in.ExecutionEngine, cache.NewPayloadIDCache(), in.AttributesFactory, ) } ================================================ FILE: node-core/components/reporting_service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/node-core/services/version" sdkversion "github.com/cosmos/cosmos-sdk/version" ) type ReportingServiceInput struct { depinject.In Logger *phuslu.Logger TelemetrySink *metrics.TelemetrySink EngineClient *client.EngineClient ChainSpec chain.Spec } func ProvideReportingService(in ReportingServiceInput) *version.ReportingService { return version.NewReportingService( in.Logger.With("service", "reporting"), in.TelemetrySink, sdkversion.Version, in.EngineClient, in.ChainSpec, ) } ================================================ FILE: node-core/components/service_registry.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/beacon/blockchain" "github.com/berachain/beacon-kit/beacon/validator" "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-api/server" "github.com/berachain/beacon-kit/node-core/components/metrics" service "github.com/berachain/beacon-kit/node-core/services/registry" "github.com/berachain/beacon-kit/node-core/services/shutdown" "github.com/berachain/beacon-kit/node-core/services/version" "github.com/berachain/beacon-kit/node-core/types" "github.com/berachain/beacon-kit/observability/telemetry" ) // ServiceRegistryInput is the input for the service registry provider. type ServiceRegistryInput struct { depinject.In ChainService *blockchain.Service EngineClient *client.EngineClient Logger *phuslu.Logger NodeAPIServer *server.Server ReportingService *version.ReportingService TelemetrySink *metrics.TelemetrySink TelemetryService *telemetry.Service ValidatorService *validator.Service CometBFTService types.ConsensusService ShutdownService *shutdown.Service } // ProvideServiceRegistry is the depinject provider for the service registry. func ProvideServiceRegistry(in ServiceRegistryInput) *service.Registry { // Note: the order of opts matters since the registry will start these services // in the order they are declared in this slice, and in reverse order // during shutdown. opts := []service.RegistryOption{ // we want shutdownservice to be the first service to start and the last to stop service.WithService(in.ShutdownService), service.WithService(in.ValidatorService), service.WithService(in.NodeAPIServer), service.WithService(in.ReportingService), service.WithService(in.TelemetryService), // engineClient will block until it connects to the execution layer service.WithService(in.EngineClient), // only once we connect to an execution client will we start the // chain service and cometbft service service.WithService(in.ChainService), service.WithService(in.CometBFTService), } return service.NewRegistry(in.Logger, opts...) } ================================================ FILE: node-core/components/shutdown_service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "path/filepath" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/services/shutdown" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cast" ) // ShutDownServiceInput is the input for the shuchdown service provider. type ShutDownServiceInput struct { depinject.In Logger *phuslu.Logger AppOpts config.AppOptions } func ProvideShutDownService(in ShutDownServiceInput) *shutdown.Service { pidFile := filepath.Join(cast.ToString(in.AppOpts.Get(flags.FlagHome)), "data/beacond.pid") return shutdown.NewService( in.Logger.With("service", "shutdown"), pidFile) } ================================================ FILE: node-core/components/sidecars.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" dablob "github.com/berachain/beacon-kit/da/blob" "github.com/berachain/beacon-kit/node-core/components/metrics" ) type SidecarFactoryInput struct { depinject.In TelemetrySink *metrics.TelemetrySink } func ProvideSidecarFactory(in SidecarFactoryInput) *dablob.SidecarFactory { return dablob.NewSidecarFactory( in.TelemetrySink, ) } ================================================ FILE: node-core/components/signer/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package signer import "errors" var ( // ErrInvalidSignature is returned when a signature is invalid. ErrInvalidSignature = errors.New("signer returned an invalid signature") // ErrValidatorPrivateKeyRequired is returned when the validator private key // is required but not provided. ErrValidatorPrivateKeyRequired = errors.New( "validator private key required", ) // ErrInvalidValidatorPrivateKeyLength is returned when the validator // private key has an invalid length. ErrInvalidValidatorPrivateKeyLength = errors.New( "invalid validator private key length", ) ) ================================================ FILE: node-core/components/signer/legacy.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package signer import ( "encoding/hex" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/cometbft/cometbft/crypto/bls12381" ) // LegacySigner is a BLS12-381 signer that uses a bls.PrivKey for signing. type LegacySigner struct { bls12381.PrivKey } // NewLegacySigner creates a new Signer instance given a secret key. func NewLegacySigner( keyBz LegacyKey, ) (*LegacySigner, error) { pk, err := bls12381.NewPrivateKeyFromBytes(keyBz[:]) if err != nil { return nil, err } return &LegacySigner{PrivKey: *pk}, nil } // PublicKey returns the public key of the signer. func (b *LegacySigner) PublicKey() crypto.BLSPubkey { return crypto.BLSPubkey(b.PubKey().Bytes()) } // Sign generates a signature for a given message using the signer's secret key. // It returns the signature and any error encountered during the signing // process. func (b *LegacySigner) Sign(msg []byte) (crypto.BLSSignature, error) { sig, err := b.PrivKey.Sign(msg) if err != nil { return crypto.BLSSignature{}, err } return crypto.BLSSignature(sig), nil } // VerifySignature verifies a signature against a message and public key. func (LegacySigner) VerifySignature( pubKey crypto.BLSPubkey, msg []byte, signature crypto.BLSSignature, ) error { pk, err := bls12381.NewPublicKeyFromBytes(pubKey[:]) if err != nil { return err } if !pk.VerifySignature(msg, signature[:]) { return ErrInvalidSignature } return nil } // LegacyKey is a byte array that represents a BLS12-381 secret key. type LegacyKey [constants.BLSSecretKeyLength]byte // LegacyKeyFromString returns a LegacyKey from a hex-encoded string. func LegacyKeyFromString(privKey string) (LegacyKey, error) { privKeyBz, err := hex.DecodeString(privKey) if err != nil { return LegacyKey{}, err } if len(privKeyBz) != constants.BLSSecretKeyLength { return LegacyKey{}, ErrInvalidValidatorPrivateKeyLength } return LegacyKey(privKeyBz), nil } ================================================ FILE: node-core/components/signer/signer.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package signer import ( "fmt" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/cometbft/cometbft/crypto/bls12381" "github.com/cometbft/cometbft/privval" "github.com/cometbft/cometbft/types" ) // BLSSigner utilize an underlying PrivValidator signer using data persisted to // disk to prevent double signing. type BLSSigner struct { types.PrivValidator } // NewBLSSigner creates a new BLSSigner instance using the provided key and // state // file paths. // If the key file does not exist, the program will exit. func NewBLSSigner(keyFilePath string, stateFilePath string) *BLSSigner { filePV := privval.LoadFilePV(keyFilePath, stateFilePath) return &BLSSigner{PrivValidator: filePV} } // ========================== Implements BLS Signer ========================== // PublicKey returns the public key of the signer. func (f BLSSigner) PublicKey() crypto.BLSPubkey { key, err := f.PrivValidator.GetPubKey() if err != nil { return crypto.BLSPubkey{} } blsKey, err := bls12381.NewPublicKeyFromBytes(key.Bytes()) if err != nil { return crypto.BLSPubkey{} } return crypto.BLSPubkey(blsKey.Compress()) } // Sign generates a signature for a given message using the signer's secret key. func (f BLSSigner) Sign(msg []byte) (crypto.BLSSignature, error) { sig, err := f.PrivValidator.SignBytes(msg) if err != nil { return crypto.BLSSignature{}, err } else if len(sig) != constants.BLSSignatureLength { return crypto.BLSSignature{}, errors.Wrapf( ErrInvalidSignature, "expected signature length %d, got %d", constants.BLSSignatureLength, len(sig), ) } return crypto.BLSSignature(sig), nil } // VerifySignature verifies a signature against a message and a public key. func (f BLSSigner) VerifySignature( pubKey crypto.BLSPubkey, msg []byte, signature crypto.BLSSignature, ) error { pk, err := bls12381.NewPublicKeyFromCompressedBytes(pubKey[:]) if err != nil { return fmt.Errorf("verifying signature: %w", err) } if !pk.VerifySignature(msg, signature[:]) { return ErrInvalidSignature } return nil } ================================================ FILE: node-core/components/signer.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "fmt" "os" "path/filepath" "cosmossdk.io/depinject" beaconflags "github.com/berachain/beacon-kit/cli/flags" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cast" ) // BlsSignerInput is the input for the dep inject framework. type BlsSignerInput struct { depinject.In AppOpts config.AppOptions PrivKey LegacyKey `optional:"true"` } // ProvideBlsSigner is a function that provides the module to the application. func ProvideBlsSigner(in BlsSignerInput) (crypto.BLSSigner, error) { if in.PrivKey == [constants.BLSSecretKeyLength]byte{} { // if no private key is provided, use privval signer homeDir := cast.ToString(in.AppOpts.Get(flags.FlagHome)) privValKeyFile := cast.ToString( in.AppOpts.Get(beaconflags.PrivValidatorKeyFile), ) privValStateFile := cast.ToString( in.AppOpts.Get(beaconflags.PrivValidatorStateFile), ) // If privValKeyFile is not an absolute path, join with homeDir if !filepath.IsAbs(privValKeyFile) { privValKeyFile = filepath.Join(homeDir, privValKeyFile) } // If privValStateFile is not an absolute path, join with homeDir if !filepath.IsAbs(privValStateFile) { privValStateFile = filepath.Join(homeDir, privValStateFile) } // Check key file existence here as the error in NewBLSSigner is vague. if _, err := os.Stat(privValKeyFile); os.IsNotExist(err) { return nil, fmt.Errorf("key file does not exist at path: %s", privValKeyFile) } // Check state file existence as the error in NewBLSSigner is vague. if _, err := os.Stat(privValStateFile); os.IsNotExist(err) { return nil, fmt.Errorf("state file does not exist at path: %s", privValStateFile) } return signer.NewBLSSigner(privValKeyFile, privValStateFile), nil } return signer.NewLegacySigner(in.PrivKey) } ================================================ FILE: node-core/components/state_processor.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/execution/engine" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/state-transition/core" "github.com/berachain/beacon-kit/storage/deposit" ) // StateProcessorInput is the input for the state processor for the depinject // framework. type StateProcessorInput struct { depinject.In Logger *phuslu.Logger ChainSpec chain.Spec ExecutionEngine *engine.Engine DepositStore deposit.StoreManager Signer crypto.BLSSigner TelemetrySink *metrics.TelemetrySink } // ProvideStateProcessor provides the state processor to the depinject // framework. func ProvideStateProcessor(in StateProcessorInput) *core.StateProcessor { return core.NewStateProcessor( in.Logger.With("service", "state-processor"), in.ChainSpec, in.ExecutionEngine, in.DepositStore, in.Signer, crypto.GetAddressFromPubKey, in.TelemetrySink, ) } ================================================ FILE: node-core/components/storage/storage.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package storage import ( "context" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/consensus-types/types" dastore "github.com/berachain/beacon-kit/da/store" "github.com/berachain/beacon-kit/log" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage/beacondb" "github.com/berachain/beacon-kit/storage/block" "github.com/berachain/beacon-kit/storage/deposit" ) // Backend is a struct that holds the storage backend. It provides a simple // interface to access all types of storage required by the runtime. type Backend struct { chainSpec chain.Spec availabilityStore *dastore.Store kvStore *beacondb.KVStore depositStore deposit.StoreManager blockStore *block.KVStore[*types.BeaconBlock] logger log.Logger telemetrySink statedb.TelemetrySink } func NewBackend( chainSpec chain.Spec, availabilityStore *dastore.Store, kvStore *beacondb.KVStore, depositStore deposit.StoreManager, blockStore *block.KVStore[*types.BeaconBlock], logger log.Logger, telemetrySink statedb.TelemetrySink, ) *Backend { return &Backend{ chainSpec: chainSpec, availabilityStore: availabilityStore, kvStore: kvStore, depositStore: depositStore, blockStore: blockStore, logger: logger, telemetrySink: telemetrySink, } } // AvailabilityStore returns the availability store struct initialized with a // given context. func (k Backend) AvailabilityStore() *dastore.Store { return k.availabilityStore } // StateFromContext returns the beacon state struct initialized with a given // context and the store key. func (k Backend) StateFromContext(ctx context.Context) *statedb.StateDB { return statedb.NewBeaconStateFromDB( k.kvStore.WithContext(ctx), k.chainSpec, k.logger, k.telemetrySink, ) } // BeaconStore returns the beacon store struct. func (k Backend) BeaconStore() *beacondb.KVStore { return k.kvStore } func (k Backend) BlockStore() *block.KVStore[*types.BeaconBlock] { return k.blockStore } // DepositStore returns the deposit store struct initialized with a. func (k Backend) DepositStore() deposit.StoreManager { return k.depositStore } ================================================ FILE: node-core/components/store.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "github.com/berachain/beacon-kit/storage" "github.com/berachain/beacon-kit/storage/beacondb" ) // ProvideKVStore is the depinject provider that returns a beacon KV store. func ProvideKVStore() *beacondb.KVStore { kvStoreService := &storage.KVStoreService{Key: storage.StoreKey} return beacondb.New(kvStoreService) } ================================================ FILE: node-core/components/telemetry_service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "github.com/berachain/beacon-kit/config/config" "github.com/berachain/beacon-kit/observability/telemetry" ) // ProvideTelemetryService is a function that provides a TelemetrySink. func ProvideTelemetryService( cfg *config.Config, ) (*telemetry.Service, error) { return telemetry.NewService(&cfg.Telemetry) } ================================================ FILE: node-core/components/telemetry_sink.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import "github.com/berachain/beacon-kit/node-core/components/metrics" // ProvideTelemetrySink is a function that provides a TelemetrySink. func ProvideTelemetrySink() *metrics.TelemetrySink { return &metrics.TelemetrySink{} } ================================================ FILE: node-core/components/trusted_setup.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "fmt" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/cli/flags" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/primitives/encoding/json" gokzg4844 "github.com/crate-crypto/go-kzg-4844" "github.com/spf13/afero" "github.com/spf13/cast" ) // TrustedSetupInput is the input for the dep inject framework. type TrustedSetupInput struct { depinject.In AppOpts config.AppOptions } // ProvideTrustedSetup provides the module to the application. func ProvideTrustedSetup( in TrustedSetupInput, ) (*gokzg4844.JSONTrustedSetup, error) { return ReadTrustedSetup( cast.ToString(in.AppOpts.Get(flags.KZGTrustedSetupPath)), ) } // ReadTrustedSetup reads the trusted setup from the file system. func ReadTrustedSetup(filePath string) (*gokzg4844.JSONTrustedSetup, error) { config, err := afero.ReadFile(afero.NewOsFs(), filePath) if err != nil { return nil, fmt.Errorf("failed reading path '%s', err: %w", filePath, err) } params := new(gokzg4844.JSONTrustedSetup) if err = json.Unmarshal(config, params); err != nil { return nil, err } if err = gokzg4844.CheckTrustedSetupIsWellFormed(params); err != nil { return nil, err } return params, nil } ================================================ FILE: node-core/components/types.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( appmodule "cosmossdk.io/core/appmodule/v2" "github.com/berachain/beacon-kit/consensus-types/types" consruntimetypes "github.com/berachain/beacon-kit/consensus/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/transition" ) /* -------------------------------------------------------------------------- */ /* Types */ /* -------------------------------------------------------------------------- */ type ( // AttestationData is a type alias for the attestation data. AttestationData = types.AttestationData // Context is a type alias for the transition context. Context = transition.Context // Fork is a type alias for the fork. Fork = types.Fork // SlotData is a type alias for the incoming slot. SlotData = consruntimetypes.SlotData // LegacyKey type alias to LegacyKey used for LegacySinger construction. LegacyKey = signer.LegacyKey // PayloadID is a type alias for the payload ID. PayloadID = engineprimitives.PayloadID // SlashingInfo is a type alias for the slashing info. SlashingInfo = types.SlashingInfo // ValidatorUpdate is a type alias for the validator update. ABCIValidatorUpdate = appmodule.ValidatorUpdate // ValidatorUpdate is a type alias for the validator update. ValidatorUpdate = transition.ValidatorUpdate // ValidatorUpdates is a type alias for the validator updates. ValidatorUpdates = transition.ValidatorUpdates // Withdrawal is a type alias for the engineprimitives withdrawal. // Withdrawal = engineprimitives.Withdrawal. // Withdrawals is a type alias for the engineprimitives withdrawals. // Withdrawals = engineprimitives.Withdrawals. // WithdrawalCredentials is a type alias for the withdrawal credentials. WithdrawalCredentials = types.WithdrawalCredentials ) ================================================ FILE: node-core/components/validator_service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package components import ( "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/beacon/validator" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/node-core/components/storage" "github.com/berachain/beacon-kit/primitives/crypto" ) // ValidatorServiceInput is the input for the validator service provider. type ValidatorServiceInput struct { depinject.In Cfg *config.Config ChainSpec chain.Spec LocalBuilder LocalBuilder Logger *phuslu.Logger StateProcessor StateProcessor StorageBackend *storage.Backend Signer crypto.BLSSigner SidecarFactory SidecarFactory TelemetrySink *metrics.TelemetrySink } // ProvideValidatorService is a depinject provider for the validator service. func ProvideValidatorService(in ValidatorServiceInput) (*validator.Service, error) { // Build the builder service. return validator.NewService( &in.Cfg.Validator, in.Logger.With("service", "validator"), in.ChainSpec, in.StorageBackend, in.StateProcessor, in.Signer, in.SidecarFactory, in.LocalBuilder, in.TelemetrySink, ), nil } ================================================ FILE: node-core/node/node.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package node import ( "context" "fmt" "os" "os/signal" "sync" "syscall" "time" "cosmossdk.io/store" "github.com/berachain/beacon-kit/beacon/blockchain" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/log" service "github.com/berachain/beacon-kit/node-core/services/registry" "github.com/berachain/beacon-kit/node-core/types" ) // Compile-time assertion that node implements the NodeI interface. var _ types.Node = (*node)(nil) // node is the hard-type representation of the beacon-kit node. type node struct { // logger is the node's logger. logger log.Logger // registry is the node's service registry. registry *service.Registry // shutdownTimeout is the maximum time to wait for the node to gracefully shutdown before forcing an exit. shutdownTimeout time.Duration } // New returns a new node. func New[NodeT types.Node](shutdownTimeout time.Duration, registry *service.Registry, logger log.Logger) NodeT { n := &node{ shutdownTimeout: shutdownTimeout, registry: registry, logger: logger, } //nolint:errcheck // should be safe return types.Node(n).(NodeT) } // Start starts the node. func (n *node) Start( ctx context.Context, ) error { cctx, cancelFn := context.WithCancel(ctx) //#nosec:G118 -- cancelFn is called in the shutdownFunc stop := make(chan struct{}) sigc := make(chan os.Signal, 1) signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM) defer signal.Stop(sigc) // make sure we only call shutdownFunc once var once sync.Once shutdownFunc := func(err error) { now := time.Now() n.logger.Error("Shutdown initiated", "timeout", n.shutdownTimeout.String(), "error", err) cancelFn() n.registry.StopAll() close(stop) n.logger.Info("Node shutdown completed", "duration", time.Since(now).String()) } // listen to signals in a separate goroutine go func() { sig := <-sigc timeout := time.AfterFunc(n.shutdownTimeout, func() { n.logger.Error("Shutdown timeout exceeded, forcing exit", "timeout", n.shutdownTimeout.String()) os.Exit(1) }) defer timeout.Stop() once.Do(func() { shutdownFunc(fmt.Errorf("shutdown initiated by signal: %s", sig.String())) }) }() err := n.registry.StartAll(cctx) if err != nil { once.Do(func() { shutdownFunc(fmt.Errorf("failed to start services: %w", err)) }) return err } // we wait here until the signal handler has shutdown the node <-stop return nil } // CommitMultiStore returns the CommitMultiStore from cometbft service. func (n *node) CommitMultiStore() store.CommitMultiStore { var cometService *cometbft.Service err := n.registry.FetchService(&cometService) if err != nil || cometService == nil { // appease nilaway err = fmt.Errorf("failed to fetch cometbft service: %w", err) panic(err) } return cometService.CommitMultiStore() } // StorageBackend returns the storage backend from the blockchain service. func (n *node) StorageBackend() blockchain.StorageBackend { var blockchainService *blockchain.Service err := n.registry.FetchService(&blockchainService) if err != nil || blockchainService == nil { // appease nilaway err = fmt.Errorf("failed to fetch blockchain service: %w", err) panic(err) } return blockchainService.StorageBackend() } ================================================ FILE: node-core/services/registry/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package service import "github.com/berachain/beacon-kit/errors" var ( // errServiceAlreadyExists defines an error for when a service already // exists. errServiceAlreadyExists = errors.Wrapf( errors.New("service already exists"), "%v", ) // errInputIsNotPointer defines an error for when the input must // be of pointer type. errInputIsNotPointer = errors.Wrapf( errors.New( "input must be of pointer type, received value type instead", ), "%T", ) // errUnknownService defines is returned when an unknown service is seen. errUnknownService = errors.Wrapf( errors.New("unknown service"), "%T", ) ) ================================================ FILE: node-core/services/registry/mocks/basic.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( context "context" mock "github.com/stretchr/testify/mock" ) // Basic is an autogenerated mock type for the Basic type type Basic struct { mock.Mock } type Basic_Expecter struct { mock *mock.Mock } func (_m *Basic) EXPECT() *Basic_Expecter { return &Basic_Expecter{mock: &_m.Mock} } // Name provides a mock function with no fields func (_m *Basic) Name() string { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for Name") } var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() } else { r0 = ret.Get(0).(string) } return r0 } // Basic_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' type Basic_Name_Call struct { *mock.Call } // Name is a helper method to define mock.On call func (_e *Basic_Expecter) Name() *Basic_Name_Call { return &Basic_Name_Call{Call: _e.mock.On("Name")} } func (_c *Basic_Name_Call) Run(run func()) *Basic_Name_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *Basic_Name_Call) Return(_a0 string) *Basic_Name_Call { _c.Call.Return(_a0) return _c } func (_c *Basic_Name_Call) RunAndReturn(run func() string) *Basic_Name_Call { _c.Call.Return(run) return _c } // Start provides a mock function with given fields: ctx func (_m *Basic) Start(ctx context.Context) error { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Start") } var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) } else { r0 = ret.Error(0) } return r0 } // Basic_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' type Basic_Start_Call struct { *mock.Call } // Start is a helper method to define mock.On call // - ctx context.Context func (_e *Basic_Expecter) Start(ctx interface{}) *Basic_Start_Call { return &Basic_Start_Call{Call: _e.mock.On("Start", ctx)} } func (_c *Basic_Start_Call) Run(run func(ctx context.Context)) *Basic_Start_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context)) }) return _c } func (_c *Basic_Start_Call) Return(_a0 error) *Basic_Start_Call { _c.Call.Return(_a0) return _c } func (_c *Basic_Start_Call) RunAndReturn(run func(context.Context) error) *Basic_Start_Call { _c.Call.Return(run) return _c } // Stop provides a mock function with no fields func (_m *Basic) Stop() error { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for Stop") } var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() } else { r0 = ret.Error(0) } return r0 } // Basic_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop' type Basic_Stop_Call struct { *mock.Call } // Stop is a helper method to define mock.On call func (_e *Basic_Expecter) Stop() *Basic_Stop_Call { return &Basic_Stop_Call{Call: _e.mock.On("Stop")} } func (_c *Basic_Stop_Call) Run(run func()) *Basic_Stop_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *Basic_Stop_Call) Return(_a0 error) *Basic_Stop_Call { _c.Call.Return(_a0) return _c } func (_c *Basic_Stop_Call) RunAndReturn(run func() error) *Basic_Stop_Call { _c.Call.Return(run) return _c } // NewBasic creates a new instance of Basic. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBasic(t interface { mock.TestingT Cleanup(func()) }) *Basic { mock := &Basic{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-core/services/registry/mocks/commit_multistore_accessor.mock.go ================================================ // Code generated by mockery v2.49.0. DO NOT EDIT. package mocks import ( mock "github.com/stretchr/testify/mock" types "cosmossdk.io/store/types" ) // CommitMultistoreAccessor is an autogenerated mock type for the CommitMultistoreAccessor type type CommitMultistoreAccessor struct { mock.Mock } type CommitMultistoreAccessor_Expecter struct { mock *mock.Mock } func (_m *CommitMultistoreAccessor) EXPECT() *CommitMultistoreAccessor_Expecter { return &CommitMultistoreAccessor_Expecter{mock: &_m.Mock} } // CommitMultiStore provides a mock function with given fields: func (_m *CommitMultistoreAccessor) CommitMultiStore() types.CommitMultiStore { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for CommitMultiStore") } var r0 types.CommitMultiStore if rf, ok := ret.Get(0).(func() types.CommitMultiStore); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(types.CommitMultiStore) } } return r0 } // CommitMultistoreAccessor_CommitMultiStore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CommitMultiStore' type CommitMultistoreAccessor_CommitMultiStore_Call struct { *mock.Call } // CommitMultiStore is a helper method to define mock.On call func (_e *CommitMultistoreAccessor_Expecter) CommitMultiStore() *CommitMultistoreAccessor_CommitMultiStore_Call { return &CommitMultistoreAccessor_CommitMultiStore_Call{Call: _e.mock.On("CommitMultiStore")} } func (_c *CommitMultistoreAccessor_CommitMultiStore_Call) Run(run func()) *CommitMultistoreAccessor_CommitMultiStore_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *CommitMultistoreAccessor_CommitMultiStore_Call) Return(_a0 types.CommitMultiStore) *CommitMultistoreAccessor_CommitMultiStore_Call { _c.Call.Return(_a0) return _c } func (_c *CommitMultistoreAccessor_CommitMultiStore_Call) RunAndReturn(run func() types.CommitMultiStore) *CommitMultistoreAccessor_CommitMultiStore_Call { _c.Call.Return(run) return _c } // NewCommitMultistoreAccessor creates a new instance of CommitMultistoreAccessor. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewCommitMultistoreAccessor(t interface { mock.TestingT Cleanup(func()) }) *CommitMultistoreAccessor { mock := &CommitMultistoreAccessor{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-core/services/registry/mocks/dispatcher.mock.go ================================================ // Code generated by mockery v2.49.0. DO NOT EDIT. package mocks import ( context "context" mock "github.com/stretchr/testify/mock" ) // Dispatcher is an autogenerated mock type for the Dispatcher type type Dispatcher struct { mock.Mock } type Dispatcher_Expecter struct { mock *mock.Mock } func (_m *Dispatcher) EXPECT() *Dispatcher_Expecter { return &Dispatcher_Expecter{mock: &_m.Mock} } // Start provides a mock function with given fields: ctx func (_m *Dispatcher) Start(ctx context.Context) error { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Start") } var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) } else { r0 = ret.Error(0) } return r0 } // Dispatcher_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' type Dispatcher_Start_Call struct { *mock.Call } // Start is a helper method to define mock.On call // - ctx context.Context func (_e *Dispatcher_Expecter) Start(ctx interface{}) *Dispatcher_Start_Call { return &Dispatcher_Start_Call{Call: _e.mock.On("Start", ctx)} } func (_c *Dispatcher_Start_Call) Run(run func(ctx context.Context)) *Dispatcher_Start_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context)) }) return _c } func (_c *Dispatcher_Start_Call) Return(_a0 error) *Dispatcher_Start_Call { _c.Call.Return(_a0) return _c } func (_c *Dispatcher_Start_Call) RunAndReturn(run func(context.Context) error) *Dispatcher_Start_Call { _c.Call.Return(run) return _c } // NewDispatcher creates a new instance of Dispatcher. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewDispatcher(t interface { mock.TestingT Cleanup(func()) }) *Dispatcher { mock := &Dispatcher{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-core/services/registry/mocks/registry_option.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( service "github.com/berachain/beacon-kit/node-core/services/registry" mock "github.com/stretchr/testify/mock" ) // RegistryOption is an autogenerated mock type for the RegistryOption type type RegistryOption struct { mock.Mock } type RegistryOption_Expecter struct { mock *mock.Mock } func (_m *RegistryOption) EXPECT() *RegistryOption_Expecter { return &RegistryOption_Expecter{mock: &_m.Mock} } // Execute provides a mock function with given fields: _a0 func (_m *RegistryOption) Execute(_a0 *service.Registry) error { ret := _m.Called(_a0) if len(ret) == 0 { panic("no return value specified for Execute") } var r0 error if rf, ok := ret.Get(0).(func(*service.Registry) error); ok { r0 = rf(_a0) } else { r0 = ret.Error(0) } return r0 } // RegistryOption_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' type RegistryOption_Execute_Call struct { *mock.Call } // Execute is a helper method to define mock.On call // - _a0 *service.Registry func (_e *RegistryOption_Expecter) Execute(_a0 interface{}) *RegistryOption_Execute_Call { return &RegistryOption_Execute_Call{Call: _e.mock.On("Execute", _a0)} } func (_c *RegistryOption_Execute_Call) Run(run func(_a0 *service.Registry)) *RegistryOption_Execute_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(*service.Registry)) }) return _c } func (_c *RegistryOption_Execute_Call) Return(_a0 error) *RegistryOption_Execute_Call { _c.Call.Return(_a0) return _c } func (_c *RegistryOption_Execute_Call) RunAndReturn(run func(*service.Registry) error) *RegistryOption_Execute_Call { _c.Call.Return(run) return _c } // NewRegistryOption creates a new instance of RegistryOption. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewRegistryOption(t interface { mock.TestingT Cleanup(func()) }) *RegistryOption { mock := &RegistryOption{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-core/services/registry/options.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package service // RegistryOption is a functional option for the Registry. type RegistryOption func(*Registry) error // WithService is an Option that registers a service with the Registry. func WithService(svc Basic) RegistryOption { return func(r *Registry) error { return r.RegisterService(svc) } } ================================================ FILE: node-core/services/registry/registry.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package service import ( "context" "fmt" "reflect" "github.com/berachain/beacon-kit/log" ) // Basic is the minimal interface for a service. type Basic interface { // Start spawns any goroutines required by the service. Start(ctx context.Context) error // Stop stops the service. It should be safe to call // Stop on a service that has not been started Stop() error // Name returns the name of the service. Name() string } // Registry provides a useful pattern for managing services. // It allows for ease of dependency management and ensures services // dependent on others use the same references in memory. type Registry struct { // logger is the logger for the Registry. logger log.Logger // services is a map of service type -> service instance. services map[string]Basic // servicesStarted is a map of services we have called Start() on. servicesStarted map[string]struct{} // serviceTypes is an ordered slice of registered service types. serviceTypes []string } // NewRegistry starts a registry instance for convenience. func NewRegistry(logger log.Logger, opts ...RegistryOption) *Registry { r := &Registry{ logger: logger, services: make(map[string]Basic), servicesStarted: make(map[string]struct{}), } for _, opt := range opts { if err := opt(r); err != nil { panic(err) } } return r } // StartAll initialized each service in order of registration. func (s *Registry) StartAll(ctx context.Context) error { // start all services s.logger.Info("Starting services", "num", len(s.serviceTypes)) for _, typeName := range s.serviceTypes { s.logger.Info("Starting service", "type", typeName) svc := s.services[typeName] if svc == nil { s.logger.Error("service not found", "type", typeName) continue } if err := svc.Start(ctx); err != nil { return fmt.Errorf("error when starting service %s: %w", typeName, err) } s.servicesStarted[typeName] = struct{}{} } s.logger.Info("All services started", "num", len(s.servicesStarted)) return nil } func (s *Registry) StopAll() { // stop all services in reverse order they were started s.logger.Info("Stopping services", "num", len(s.serviceTypes)) for i := len(s.serviceTypes) - 1; i >= 0; i-- { typeName := s.serviceTypes[i] if _, started := s.servicesStarted[typeName]; !started { s.logger.Info("Service not started", "type", typeName) continue } s.logger.Info("Stopping service", "type", typeName) svc := s.services[typeName] if svc == nil { s.logger.Error("service not found", "type", typeName) continue } if err := svc.Stop(); err != nil { s.logger.Error("error when stopping service", "type", typeName, "err", err) } } s.logger.Info("All services stopped", "num", len(s.servicesStarted)) } // RegisterService appends a service constructor function to the service // registry. func (s *Registry) RegisterService(service Basic) error { typeName := service.Name() if _, exists := s.services[typeName]; exists { return errServiceAlreadyExists } s.services[typeName] = service s.serviceTypes = append(s.serviceTypes, typeName) return nil } // FetchService takes in a struct pointer and sets the value of that pointer // to a service currently stored in the service registry. This ensures the // input argument is set to the right pointer that refers to the originally // registered service. func (s *Registry) FetchService(service interface{}) error { serviceType := reflect.TypeOf(service) if serviceType.Kind() != reflect.Ptr || serviceType.Elem().Kind() != reflect.Ptr { return errInputIsNotPointer } element := reflect.ValueOf(service).Elem() typeName := "" for name, svc := range s.services { svcType := reflect.TypeOf(svc) if svcType.AssignableTo(serviceType.Elem()) { typeName = name break } } if typeName == "" { return errUnknownService } if running, ok := s.services[typeName]; ok { element.Set(reflect.ValueOf(running)) return nil } return errUnknownService } ================================================ FILE: node-core/services/registry/registry_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package service_test import ( "reflect" "testing" "time" "github.com/berachain/beacon-kit/log/noop" service "github.com/berachain/beacon-kit/node-core/services/registry" "github.com/berachain/beacon-kit/node-core/services/registry/mocks" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) func TestRegistry_StartAll(t *testing.T) { t.Parallel() logger := noop.NewLogger[any]() registry := service.NewRegistry(logger) service1 := &mocks.Basic{} service1.On("Start", mock.Anything).Return(nil).Once() service1.On("Name").Return("Service1") service2 := &mocks.Basic{} service2.On("Start", mock.Anything).Return(nil).Once() service2.On("Name").Return("Service2") err := registry.RegisterService(service1) if err != nil { t.Fatalf("Failed to register Service1: %v", err) } err = registry.RegisterService(service2) if err != nil { t.Fatalf("Failed to register Service2: %v", err) } require.NoError(t, registry.StartAll(t.Context())) time.Sleep(25 * time.Millisecond) service1.AssertCalled(t, "Start", mock.Anything) service2.AssertCalled(t, "Start", mock.Anything) } func TestRegistry_FetchService(t *testing.T) { t.Parallel() logger := noop.NewLogger[any]() registry := service.NewRegistry(logger) service1 := new(mocks.Basic) service1.On("Name").Return("Service1") if err := registry.RegisterService(service1); err != nil { t.Fatalf("Failed to register Service1: %v", err) } var fetchedService *mocks.Basic if err := registry.FetchService(&fetchedService); err != nil { t.Fatalf("Failed to fetch service: %v", err) } if reflect.TypeOf(fetchedService) != reflect.TypeOf(service1) { t.Errorf("Fetched service type mismatch") } } ================================================ FILE: node-core/services/shutdown/service..go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package shutdown import ( "context" "fmt" "os" "strconv" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log" ) // Service is a service that manages any startup or shutdown tasks that need to be done. type Service struct { // logger is used for logging messages in the service. logger log.Logger // pidFile is the path to the pid file we use to detect unsafe shutdowns. pidFile string } func NewService(logger log.Logger, pidFile string) *Service { return &Service{logger: logger, pidFile: pidFile} } // Name returns the name of the service. func (*Service) Name() string { return "shutdown" } func (s *Service) Start(_ context.Context) error { // if the pid file already exists it means we didn't gracefully shutdown. if _, err := os.Stat(s.pidFile); err == nil { s.printUnsafeShutDownDetected() } // create a new pid file and write our process id to it. If it already existed before // it will be truncated and overwritten with our new pid. The timestamp of the file // will be updated to the current time so we can compute the time it was running f, err := os.Create(s.pidFile) if err != nil { return errors.Wrap(err, "failed to create pidfile") } defer f.Close() _, err = f.WriteString(strconv.Itoa(os.Getpid())) if err != nil { return errors.Wrap(err, "failed to write pid to pidfile") } return nil } func (s *Service) Stop() error { s.logger.Info("Stopping shutdown service") err := os.Remove(s.pidFile) if err != nil { return errors.Wrap(err, "failed to remove pidfile") } return nil } func (s *Service) printUnsafeShutDownDetected() { // collect info about the previous pid instance and when it was started pid := "unknown" if bytes, readErr := os.ReadFile(s.pidFile); readErr == nil { pid = string(bytes) } started := "unknown" if fi, statErr := os.Stat(s.pidFile); statErr == nil { started = fi.ModTime().String() } s.logger.Warn(fmt.Sprintf(` +==========================================================================+ + ⚠️ Detected an unsafe shutdown! + 🧩 Previously running: + PID: %s + Started: %s +==========================================================================+ `, pid, started)) } ================================================ FILE: node-core/services/version/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package version import "github.com/berachain/beacon-kit/chain" // TelemetrySink is an interface for sending telemetry data. type TelemetrySink interface { // IncrementCounter increments a counter metric identified by the provided // keys. IncrementCounter(key string, args ...string) // SetGauge sets a gauge metric to the specified value, identified by the // provided keys. SetGauge(key string, value int64, args ...string) } type ForkSpec interface { chain.ForkSpec } ================================================ FILE: node-core/services/version/version.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package version import ( "context" "fmt" "runtime" "time" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/execution/client/ethclient" "github.com/berachain/beacon-kit/log" ) // defaultReportingInterval is the default interval at which the version is // reported. const defaultReportingInterval = 5 * time.Minute // ReportingService is a service that periodically logs the running chain // version. type ReportingService struct { // logger is used to log information about the running chain version. logger log.Logger // version represents the current version of the running chain. version string // reportingInterval is the interval at which the version is reported. reportingInterval time.Duration // sink is the telemetry sink used to report metrics. sink TelemetrySink // client to query the execution layer client *client.EngineClient forkSpec ForkSpec } // NewReportingService creates a new VersionReporterService. func NewReportingService( logger log.Logger, telemetrySink TelemetrySink, version string, engineClient *client.EngineClient, forkSpec ForkSpec, ) *ReportingService { return &ReportingService{ logger: logger, version: version, reportingInterval: defaultReportingInterval, sink: telemetrySink, client: engineClient, forkSpec: forkSpec, } } // Name returns the name of the service. func (*ReportingService) Name() string { return "reporting" } // Start begins the periodic logging of the chain version. func (rs *ReportingService) Start(ctx context.Context) error { // we print to console always at the beginning rs.printToConsole(engineprimitives.ClientVersionV1{ Version: "unknown", Name: "unknown"}, ) connectedTicker := time.NewTicker(time.Second) go func() { // wait until the client is connected connected := false for !connected { select { case <-connectedTicker.C: connected = rs.client.IsConnected() case <-ctx.Done(): connectedTicker.Stop() return } } connectedTicker.Stop() rs.logger.Info("Connected to execution client") // log telemetry immediately after we are connected ethVersion, err := rs.GetEthVersion(ctx) if err != nil { rs.logger.Warn("Failed to get eth version", "err", err) } rs.logTelemetry(ethVersion) // then we start reporting at the reportingInterval interval ticker := time.NewTicker(rs.reportingInterval) defer ticker.Stop() for { select { case <-ticker.C: // since the eth client can be updated separately for beacon // node // we need to fetch the version every time ethVersion, err = rs.GetEthVersion(ctx) if err != nil { rs.logger.Warn("Failed to get eth version", "err", err) } // print to console and log telemetry rs.printToConsole(ethVersion) rs.logTelemetry(ethVersion) continue case <-ctx.Done(): return } } }() return nil } func (rs *ReportingService) Stop() error { return nil } func (rs *ReportingService) printToConsole( ethClient engineprimitives.ClientVersionV1) { rs.logger.Info(fmt.Sprintf(` +==========================================================================+ + ⭐️ Star BeaconKit on GitHub @ https://github.com/berachain/beacon-kit + + 🧩 Your node is running version: %-40s+ + ♦ Eth client: %-59s+ + 💾 Your system: %-57s+ + 🍴 Deneb1 Fork Time: %-52d+ + 🍴 Electra Fork Time: %-51d+ + 🍴 Electra1 Fork Time: %-50d+ + 🦺 Please report issues @ https://github.com/berachain/beacon-kit/issues + +==========================================================================+ `, rs.version, fmt.Sprintf("%s (version: %s)", ethClient.Name, ethClient.Version), runtime.GOOS+"/"+runtime.GOARCH, rs.forkSpec.Deneb1ForkTime(), rs.forkSpec.ElectraForkTime(), rs.forkSpec.Electra1ForkTime(), )) } func (rs *ReportingService) GetEthVersion( ctx context.Context) (engineprimitives.ClientVersionV1, error) { ethVersion := engineprimitives.ClientVersionV1{ Version: "unknown", Name: "unknown", } if rs.client.HasCapability(ethclient.GetClientVersionV1) { // Get the client version from the execution layer. info, err := rs.client.GetClientVersionV1(ctx) if err != nil { return ethVersion, fmt.Errorf( "failed to get client version: %w", err, ) } // the spec says we should have at least one client version if len(info) == 0 { return ethVersion, errors.New("no client version returned") } ethVersion.Version = info[0].Version ethVersion.Name = info[0].Name } else { rs.logger.Warn("Client does not have capability to get client version") } return ethVersion, nil } func (rs *ReportingService) logTelemetry( ethVersion engineprimitives.ClientVersionV1) { systemInfo := runtime.GOOS + "/" + runtime.GOARCH // TODO: Delete this counter as it should be included in the new // beacon_kit.runtime.version metric. rs.sink.IncrementCounter( "beacon_kit.runtime.version.reported", "version", rs.version, "system", systemInfo, ) rs.logger.Info("Reporting version", "version", rs.version, "system", systemInfo, "eth_version", ethVersion.Version, "eth_name", ethVersion.Name) // Report the version to the telemetry sink and include labels // for beacon node version and eth name and version var args = [8]string{ "version", rs.version, "system", systemInfo, "eth_version", ethVersion.Version, "eth_name", ethVersion.Name, } rs.sink.SetGauge("beacon_kit.runtime.version", 1, args[:]...) } ================================================ FILE: node-core/types/mocks/consensus_service.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( context "context" cometbfttypes "github.com/cometbft/cometbft/types" mock "github.com/stretchr/testify/mock" types "github.com/cosmos/cosmos-sdk/types" ) // ConsensusService is an autogenerated mock type for the ConsensusService type type ConsensusService struct { mock.Mock } type ConsensusService_Expecter struct { mock *mock.Mock } func (_m *ConsensusService) EXPECT() *ConsensusService_Expecter { return &ConsensusService_Expecter{mock: &_m.Mock} } // CreateQueryContext provides a mock function with given fields: height, prove func (_m *ConsensusService) CreateQueryContext(height int64, prove bool) (types.Context, error) { ret := _m.Called(height, prove) if len(ret) == 0 { panic("no return value specified for CreateQueryContext") } var r0 types.Context var r1 error if rf, ok := ret.Get(0).(func(int64, bool) (types.Context, error)); ok { return rf(height, prove) } if rf, ok := ret.Get(0).(func(int64, bool) types.Context); ok { r0 = rf(height, prove) } else { r0 = ret.Get(0).(types.Context) } if rf, ok := ret.Get(1).(func(int64, bool) error); ok { r1 = rf(height, prove) } else { r1 = ret.Error(1) } return r0, r1 } // ConsensusService_CreateQueryContext_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateQueryContext' type ConsensusService_CreateQueryContext_Call struct { *mock.Call } // CreateQueryContext is a helper method to define mock.On call // - height int64 // - prove bool func (_e *ConsensusService_Expecter) CreateQueryContext(height interface{}, prove interface{}) *ConsensusService_CreateQueryContext_Call { return &ConsensusService_CreateQueryContext_Call{Call: _e.mock.On("CreateQueryContext", height, prove)} } func (_c *ConsensusService_CreateQueryContext_Call) Run(run func(height int64, prove bool)) *ConsensusService_CreateQueryContext_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(int64), args[1].(bool)) }) return _c } func (_c *ConsensusService_CreateQueryContext_Call) Return(_a0 types.Context, _a1 error) *ConsensusService_CreateQueryContext_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *ConsensusService_CreateQueryContext_Call) RunAndReturn(run func(int64, bool) (types.Context, error)) *ConsensusService_CreateQueryContext_Call { _c.Call.Return(run) return _c } // GetBlock provides a mock function with given fields: height func (_m *ConsensusService) GetBlock(height int64) *cometbfttypes.Block { ret := _m.Called(height) if len(ret) == 0 { panic("no return value specified for GetBlock") } var r0 *cometbfttypes.Block if rf, ok := ret.Get(0).(func(int64) *cometbfttypes.Block); ok { r0 = rf(height) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*cometbfttypes.Block) } } return r0 } // ConsensusService_GetBlock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetBlock' type ConsensusService_GetBlock_Call struct { *mock.Call } // GetBlock is a helper method to define mock.On call // - height int64 func (_e *ConsensusService_Expecter) GetBlock(height interface{}) *ConsensusService_GetBlock_Call { return &ConsensusService_GetBlock_Call{Call: _e.mock.On("GetBlock", height)} } func (_c *ConsensusService_GetBlock_Call) Run(run func(height int64)) *ConsensusService_GetBlock_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(int64)) }) return _c } func (_c *ConsensusService_GetBlock_Call) Return(_a0 *cometbfttypes.Block) *ConsensusService_GetBlock_Call { _c.Call.Return(_a0) return _c } func (_c *ConsensusService_GetBlock_Call) RunAndReturn(run func(int64) *cometbfttypes.Block) *ConsensusService_GetBlock_Call { _c.Call.Return(run) return _c } // GetSignedHeader provides a mock function with given fields: height func (_m *ConsensusService) GetSignedHeader(height int64) *cometbfttypes.SignedHeader { ret := _m.Called(height) if len(ret) == 0 { panic("no return value specified for GetSignedHeader") } var r0 *cometbfttypes.SignedHeader if rf, ok := ret.Get(0).(func(int64) *cometbfttypes.SignedHeader); ok { r0 = rf(height) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*cometbfttypes.SignedHeader) } } return r0 } // ConsensusService_GetSignedHeader_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSignedHeader' type ConsensusService_GetSignedHeader_Call struct { *mock.Call } // GetSignedHeader is a helper method to define mock.On call // - height int64 func (_e *ConsensusService_Expecter) GetSignedHeader(height interface{}) *ConsensusService_GetSignedHeader_Call { return &ConsensusService_GetSignedHeader_Call{Call: _e.mock.On("GetSignedHeader", height)} } func (_c *ConsensusService_GetSignedHeader_Call) Run(run func(height int64)) *ConsensusService_GetSignedHeader_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(int64)) }) return _c } func (_c *ConsensusService_GetSignedHeader_Call) Return(_a0 *cometbfttypes.SignedHeader) *ConsensusService_GetSignedHeader_Call { _c.Call.Return(_a0) return _c } func (_c *ConsensusService_GetSignedHeader_Call) RunAndReturn(run func(int64) *cometbfttypes.SignedHeader) *ConsensusService_GetSignedHeader_Call { _c.Call.Return(run) return _c } // GetSyncData provides a mock function with no fields func (_m *ConsensusService) GetSyncData() (int64, int64) { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetSyncData") } var r0 int64 var r1 int64 if rf, ok := ret.Get(0).(func() (int64, int64)); ok { return rf() } if rf, ok := ret.Get(0).(func() int64); ok { r0 = rf() } else { r0 = ret.Get(0).(int64) } if rf, ok := ret.Get(1).(func() int64); ok { r1 = rf() } else { r1 = ret.Get(1).(int64) } return r0, r1 } // ConsensusService_GetSyncData_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSyncData' type ConsensusService_GetSyncData_Call struct { *mock.Call } // GetSyncData is a helper method to define mock.On call func (_e *ConsensusService_Expecter) GetSyncData() *ConsensusService_GetSyncData_Call { return &ConsensusService_GetSyncData_Call{Call: _e.mock.On("GetSyncData")} } func (_c *ConsensusService_GetSyncData_Call) Run(run func()) *ConsensusService_GetSyncData_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *ConsensusService_GetSyncData_Call) Return(latestHeight int64, syncToHeight int64) *ConsensusService_GetSyncData_Call { _c.Call.Return(latestHeight, syncToHeight) return _c } func (_c *ConsensusService_GetSyncData_Call) RunAndReturn(run func() (int64, int64)) *ConsensusService_GetSyncData_Call { _c.Call.Return(run) return _c } // IsAppReady provides a mock function with no fields func (_m *ConsensusService) IsAppReady() error { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for IsAppReady") } var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() } else { r0 = ret.Error(0) } return r0 } // ConsensusService_IsAppReady_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsAppReady' type ConsensusService_IsAppReady_Call struct { *mock.Call } // IsAppReady is a helper method to define mock.On call func (_e *ConsensusService_Expecter) IsAppReady() *ConsensusService_IsAppReady_Call { return &ConsensusService_IsAppReady_Call{Call: _e.mock.On("IsAppReady")} } func (_c *ConsensusService_IsAppReady_Call) Run(run func()) *ConsensusService_IsAppReady_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *ConsensusService_IsAppReady_Call) Return(_a0 error) *ConsensusService_IsAppReady_Call { _c.Call.Return(_a0) return _c } func (_c *ConsensusService_IsAppReady_Call) RunAndReturn(run func() error) *ConsensusService_IsAppReady_Call { _c.Call.Return(run) return _c } // Name provides a mock function with no fields func (_m *ConsensusService) Name() string { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for Name") } var r0 string if rf, ok := ret.Get(0).(func() string); ok { r0 = rf() } else { r0 = ret.Get(0).(string) } return r0 } // ConsensusService_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' type ConsensusService_Name_Call struct { *mock.Call } // Name is a helper method to define mock.On call func (_e *ConsensusService_Expecter) Name() *ConsensusService_Name_Call { return &ConsensusService_Name_Call{Call: _e.mock.On("Name")} } func (_c *ConsensusService_Name_Call) Run(run func()) *ConsensusService_Name_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *ConsensusService_Name_Call) Return(_a0 string) *ConsensusService_Name_Call { _c.Call.Return(_a0) return _c } func (_c *ConsensusService_Name_Call) RunAndReturn(run func() string) *ConsensusService_Name_Call { _c.Call.Return(run) return _c } // Start provides a mock function with given fields: ctx func (_m *ConsensusService) Start(ctx context.Context) error { ret := _m.Called(ctx) if len(ret) == 0 { panic("no return value specified for Start") } var r0 error if rf, ok := ret.Get(0).(func(context.Context) error); ok { r0 = rf(ctx) } else { r0 = ret.Error(0) } return r0 } // ConsensusService_Start_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Start' type ConsensusService_Start_Call struct { *mock.Call } // Start is a helper method to define mock.On call // - ctx context.Context func (_e *ConsensusService_Expecter) Start(ctx interface{}) *ConsensusService_Start_Call { return &ConsensusService_Start_Call{Call: _e.mock.On("Start", ctx)} } func (_c *ConsensusService_Start_Call) Run(run func(ctx context.Context)) *ConsensusService_Start_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context)) }) return _c } func (_c *ConsensusService_Start_Call) Return(_a0 error) *ConsensusService_Start_Call { _c.Call.Return(_a0) return _c } func (_c *ConsensusService_Start_Call) RunAndReturn(run func(context.Context) error) *ConsensusService_Start_Call { _c.Call.Return(run) return _c } // Stop provides a mock function with no fields func (_m *ConsensusService) Stop() error { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for Stop") } var r0 error if rf, ok := ret.Get(0).(func() error); ok { r0 = rf() } else { r0 = ret.Error(0) } return r0 } // ConsensusService_Stop_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Stop' type ConsensusService_Stop_Call struct { *mock.Call } // Stop is a helper method to define mock.On call func (_e *ConsensusService_Expecter) Stop() *ConsensusService_Stop_Call { return &ConsensusService_Stop_Call{Call: _e.mock.On("Stop")} } func (_c *ConsensusService_Stop_Call) Run(run func()) *ConsensusService_Stop_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *ConsensusService_Stop_Call) Return(_a0 error) *ConsensusService_Stop_Call { _c.Call.Return(_a0) return _c } func (_c *ConsensusService_Stop_Call) RunAndReturn(run func() error) *ConsensusService_Stop_Call { _c.Call.Return(run) return _c } // NewConsensusService creates a new instance of ConsensusService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewConsensusService(t interface { mock.TestingT Cleanup(func()) }) *ConsensusService { mock := &ConsensusService{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: node-core/types/node.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "context" "cosmossdk.io/store" "github.com/berachain/beacon-kit/beacon/blockchain" service "github.com/berachain/beacon-kit/node-core/services/registry" cmttypes "github.com/cometbft/cometbft/types" sdk "github.com/cosmos/cosmos-sdk/types" ) // Node defines the API for the node application. // It extends the Application interface from the Cosmos SDK. type Node interface { CommitMultistoreAccessor StorageBackendAccessor Start(context.Context) error } // CommitMultistoreAccessor allows access to the commit multistore. // This is required by commands like rollback. type CommitMultistoreAccessor interface { CommitMultiStore() store.CommitMultiStore } // StorageBackendAccessor allows access to the storage backend. // This is required by commands like db-check. type StorageBackendAccessor interface { StorageBackend() blockchain.StorageBackend } // ConsensusService defines everything we utilise externally from CometBFT. type ConsensusService interface { service.Basic IsAppReady() error CreateQueryContext(height int64, prove bool) (sdk.Context, error) GetSyncData() (latestHeight int64, syncToHeight int64) // GetBlock returns the CometBFT block at the given height. GetBlock(height int64) *cmttypes.Block // GetSignedHeader returns the CometBFT signed header (header + commit) at the given height. GetSignedHeader(height int64) *cmttypes.SignedHeader } ================================================ FILE: observability/telemetry/service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package telemetry import ( "context" "github.com/cosmos/cosmos-sdk/telemetry" ) type Config = telemetry.Config // Service is a telemetry service. type Service struct { m *telemetry.Metrics } // NewService creates a new telemetry service. func NewService(cfg *telemetry.Config) (*Service, error) { m, err := telemetry.New(*cfg) if err != nil { return nil, err } return &Service{ m: m, }, nil } // Name returns the service name. func (s *Service) Name() string { return "telemetry" } // Start starts the telemetry service. func (s *Service) Start(context.Context) error { return nil } func (s *Service) Stop() error { return nil } ================================================ FILE: payload/README.md ================================================ # payload module ================================================ FILE: payload/attributes/factory.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package attributes import ( engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" ) // Factory is a factory for creating payload attributes. type Factory struct { // chainSpec is the chain spec for the attributes factory. chainSpec ChainSpec // logger is the logger for the attributes factory. logger log.Logger // suggestedFeeRecipient is the suggested fee recipient sent to // the execution client for the payload build. suggestedFeeRecipient common.ExecutionAddress } // NewAttributesFactory creates a new instance of AttributesFactory. func NewAttributesFactory( chainSpec ChainSpec, logger log.Logger, suggestedFeeRecipient common.ExecutionAddress, ) *Factory { return &Factory{ chainSpec: chainSpec, logger: logger, suggestedFeeRecipient: suggestedFeeRecipient, } } // BuildPayloadAttributes creates a new instance of PayloadAttributes. func (f *Factory) BuildPayloadAttributes( timestamp math.U64, payloadWithdrawals engineprimitives.Withdrawals, prevRandao common.Bytes32, prevHeadRoot common.Root, parentProposerPubkey *crypto.BLSPubkey, ) (*engineprimitives.PayloadAttributes, error) { return engineprimitives.NewPayloadAttributes( f.chainSpec.ActiveForkVersionForTimestamp(timestamp), timestamp, prevRandao, f.suggestedFeeRecipient, payloadWithdrawals, prevHeadRoot, parentProposerPubkey, ) } ================================================ FILE: payload/attributes/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package attributes import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) type ChainSpec interface { ActiveForkVersionForTimestamp(timestamp math.U64) common.Version EpochsPerHistoricalVector() uint64 SlotToEpoch(slot math.Slot) math.Epoch } ================================================ FILE: payload/builder/builder.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "sync" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/math" ) // PayloadBuilder is used to build payloads on the // execution client. type PayloadBuilder struct { // cfg holds the configuration settings for the PayloadBuilder. cfg *Config // chainSpec holds the chain specifications for the PayloadBuilder. chainSpec ChainSpec // logger is used for logging within the PayloadBuilder. logger log.Logger // ee is the execution engine. ee ExecutionEngine // pc is the payload ID cache, it is used to store // "in-flight" payloads that are being built on // the execution client. pc PayloadCache // attributesFactory is used to create attributes for the attributesFactory AttributesFactory // latestEnvelope caches the latest verified payload, so that // it can be re-issued if the verified payload is not finalized // and node is requested to build a block. This helps respecting // FCU invariants (can't ask to build Nth block if N+1th has already // being requested ) muEnv sync.RWMutex latestEnvelopeSlot math.Slot latestEnvelope ctypes.BuiltExecutionPayloadEnv } // New creates a new service. func New( cfg *Config, chainSpec ChainSpec, logger log.Logger, ee ExecutionEngine, pc PayloadCache, af AttributesFactory, ) *PayloadBuilder { return &PayloadBuilder{ cfg: cfg, chainSpec: chainSpec, logger: logger, ee: ee, pc: pc, attributesFactory: af, } } // Enabled returns true if the payload builder is enabled. func (pb *PayloadBuilder) Enabled() bool { return pb.cfg.Enabled } ================================================ FILE: payload/builder/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "time" "github.com/berachain/beacon-kit/primitives/common" ) const ( // defaultPayloadTimeout is the default value for local build // payload timeout. defaultPayloadTimeout = 850 * time.Millisecond ) // Config is the configuration for the payload builder. type Config struct { // Enabled determines if the local builder is enabled. Enabled bool `mapstructure:"enabled"` // SuggestedFeeRecipient is the address that will receive the transaction // fees produced by any blocks from this node. SuggestedFeeRecipient common.ExecutionAddress `mapstructure:"suggested-fee-recipient"` // PayloadTimeout is the timeout parameter for local build // payload. This should match, or be slightly less than the configured // timeout on your execution client. It also must be less than // timeout_proposal in the CometBFT configuration. PayloadTimeout time.Duration `mapstructure:"payload-timeout"` } // DefaultConfig returns the default fork configuration. func DefaultConfig() Config { return Config{ Enabled: true, SuggestedFeeRecipient: common.ExecutionAddress{}, PayloadTimeout: defaultPayloadTimeout, } } ================================================ FILE: payload/builder/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import "github.com/berachain/beacon-kit/errors" var ( // ErrPayloadBuilderDisabled is returned when the payload builder is // disabled. ErrPayloadBuilderDisabled = errors.New("payload builder is disabled") // ErrNilPayloadID is returned when a nil payload ID is received. ErrNilPayloadID = errors.New("received nil payload ID") // ErrPayloadIDNotFound is returned when a payload ID is not found in the // cache. ErrPayloadIDNotFound = errors.New("unable to find payload ID in cache") // ErrNilWithdrawals is returned when nil withdrawals list is received. ErrNilWithdrawals = errors.New("nil withdrawals received from execution client") ) ================================================ FILE: payload/builder/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "context" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/payload/cache" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" ) type PayloadCache interface { Get(slot math.Slot, stateRoot common.Root) (cache.PayloadIDCacheResult, bool) Set(slot math.Slot, stateRoot common.Root, pid engineprimitives.PayloadID, version common.Version) Delete(slot math.Slot, stateRoot common.Root) } // AttributesFactory is the interface for the attributes factory. type AttributesFactory interface { BuildPayloadAttributes( timestamp math.U64, payloadWithdrawals engineprimitives.Withdrawals, prevRandao common.Bytes32, prevHeadRoot common.Root, parentProposerPubkey *crypto.BLSPubkey, ) (*engineprimitives.PayloadAttributes, error) } // ExecutionEngine is the interface for the execution engine. type ExecutionEngine interface { // GetPayload returns the payload and blobs bundle for the given slot. GetPayload( ctx context.Context, req *ctypes.GetPayloadRequest, ) (ctypes.BuiltExecutionPayloadEnv, error) // NotifyForkchoiceUpdate notifies the execution client of a forkchoice // update. NotifyForkchoiceUpdate( ctx context.Context, req *ctypes.ForkchoiceUpdateRequest, ) (*engineprimitives.PayloadID, error) } type ChainSpec interface { ActiveForkVersionForTimestamp(timestamp math.U64) common.Version SlotToEpoch(slot math.Slot) math.Epoch EpochsPerHistoricalVector() uint64 } ================================================ FILE: payload/builder/payload.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder import ( "context" "fmt" "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" engineerrors "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" ) type RequestPayloadData struct { Slot math.Slot Timestamp math.U64 PayloadWithdrawals engineprimitives.Withdrawals PrevRandao common.Bytes32 ParentBlockRoot common.Root FCState engineprimitives.ForkchoiceStateV1 ParentProposerPubkey *crypto.BLSPubkey // nil for fork versions before Electra1 } // RequestPayloadAsync builds a payload for the given slot and // returns the payload ID. func (pb *PayloadBuilder) RequestPayloadAsync( ctx context.Context, r *RequestPayloadData, ) (*engineprimitives.PayloadID, common.Version, error) { if !pb.Enabled() { return nil, common.Version{}, ErrPayloadBuilderDisabled } if payloadID, found := pb.pc.Get(r.Slot, r.ParentBlockRoot); found { pb.logger.Info( "aborting payload build; payload already exists in cache", "for_slot", r.Slot.Base10(), "parent_block_root", r.ParentBlockRoot, ) return &payloadID.PayloadID, payloadID.ForkVersion, nil } // Assemble the payload attributes. attrs, err := pb.attributesFactory.BuildPayloadAttributes( r.Timestamp, r.PayloadWithdrawals, r.PrevRandao, r.ParentBlockRoot, r.ParentProposerPubkey, ) if err != nil { return nil, common.Version{}, err } forkVersion := pb.chainSpec.ActiveForkVersionForTimestamp(r.Timestamp) // Submit the forkchoice update to the execution client. req := ctypes.BuildForkchoiceUpdateRequest( &r.FCState, attrs, forkVersion, ) payloadID, err := pb.ee.NotifyForkchoiceUpdate(ctx, req) if err != nil { return nil, common.Version{}, fmt.Errorf("RequestPayloadAsync failed sending forkchoice update: %w", err) } // Only add to cache if we received back a payload ID. if payloadID != nil { pb.pc.Set(r.Slot, r.ParentBlockRoot, *payloadID, forkVersion) } return payloadID, forkVersion, nil } // RequestPayloadSync request a payload for the given slot and // blocks until the payload is delivered. func (pb *PayloadBuilder) RequestPayloadSync( ctx context.Context, r *RequestPayloadData, ) (ctypes.BuiltExecutionPayloadEnv, error) { if !pb.Enabled() { return nil, ErrPayloadBuilderDisabled } // Build the payload and wait for the execution client to // return the payload ID. payloadID, forkVersion, err := pb.RequestPayloadAsync(ctx, r) if err != nil { return nil, err } if payloadID == nil { return nil, ErrNilPayloadID } // Wait for the payload to be delivered to the execution client. pb.logger.Info( "Waiting for local payload to be delivered to execution client", "for_slot", r.Slot.Base10(), "timeout", pb.cfg.PayloadTimeout.String(), ) select { case <-time.After(pb.cfg.PayloadTimeout): // We want to trigger delivery of the payload to the execution client // before the timestamp expires. break case <-ctx.Done(): return nil, ctx.Err() } payload, err := pb.getPayload(ctx, *payloadID, forkVersion) if err != nil { if errors.Is(err, engineerrors.ErrUnknownPayload) { // We may have cached the payloadID, but the payload have become stale // in the EVM, or there could have been other issues forcing the EVM // to provide no payload. In both cases we can purge the payloadID as it // is not usable anymore. pb.pc.Delete(r.Slot, r.ParentBlockRoot) } return nil, fmt.Errorf("failed retrieving payload for ID %x: %w", *payloadID, err) } return payload, nil } // RetrievePayload attempts to pull a previously built payload // by reading a payloadID from the builder's cache. If it fails to // retrieve a payload, it will build a new payload and wait for the // execution client to return the payload. func (pb *PayloadBuilder) RetrievePayload( ctx context.Context, slot math.Slot, parentBlockRoot common.Root, expectedForkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) { if !pb.Enabled() { return nil, ErrPayloadBuilderDisabled } // With optimistic block building enabled, multiple payloads can be available // when it's the proposer turn to build. We select them as follows: // - First we check if node has already built a payload for the requested slot. If so we use that // payload; note that such a payload may not be available (no payloadID associated or payload is stale). // - Secondly we try and reuse the latest payload we verified, even if produced by other validators. // The reason we have to do this has to do with an ENGINE API invariant: the node // could be asked to build a block at slot H even if it already verified a block at that slot H. // This happens if the block passes verification but is not finalized (e.g. due to network issue). // In such a case, the EVM may not be able to serve a new payload (e.g. if it has received a // FCU call with FINALIZED == H). To avoiding a failure in building the block // we reuse a validated payload if it's available // - Finally if neither of these payloads is available, we signal the block builder to build // the payload just in time with ErrPayloadIDNotFound error flag payloadRes, found := pb.pc.Get(slot, parentBlockRoot) if !found { // No block built optimistically, try reusing the latest verified payload if verifiedEnvelope := pb.getLatestVerifiedPayload(slot, expectedForkVersion); verifiedEnvelope != nil { return verifiedEnvelope, nil } // ErrPayloadIDNotFound tells to the block builder to build payload just in time return nil, ErrPayloadIDNotFound } if !version.Equals(payloadRes.ForkVersion, expectedForkVersion) { pb.pc.Delete(slot, parentBlockRoot) return nil, ErrPayloadIDNotFound // force payload rebuild with the right fork } // Get the payload from the execution client. envelope, err := pb.getPayload(ctx, payloadRes.PayloadID, payloadRes.ForkVersion) if err != nil { if errors.Is(err, engineerrors.ErrUnknownPayload) { // We may have cached the payloadID, but the payload have become stale // in the EVM, or there could have been other issues. In any case the payloadID // can't be reused, so we can drop it. pb.pc.Delete(slot, parentBlockRoot) // Again here we should try reusing the latest verified block. if verifiedEnvelope := pb.getLatestVerifiedPayload(slot, expectedForkVersion); verifiedEnvelope != nil { return verifiedEnvelope, nil } } return nil, err } // Minor validations and logging below payload := envelope.GetExecutionPayload() if payload.GetFeeRecipient() != pb.cfg.SuggestedFeeRecipient { pb.logger.Warn( "Payload fee recipient does not match suggested fee recipient - "+ "please check both your CL and EL configuration", "payload_fee_recipient", payload.GetFeeRecipient(), "suggested_fee_recipient", pb.cfg.SuggestedFeeRecipient, ) } // log some data args := []any{ "for_slot", slot.Base10(), "override_builder", envelope.ShouldOverrideBuilder(), "payload_block_hash", payload.GetBlockHash(), "parent_hash", payload.GetParentHash(), } if blobsBundle := envelope.GetBlobsBundle(); blobsBundle != nil { args = append(args, "num_blobs", len(blobsBundle.GetBlobs())) } pb.logger.Info("Payload retrieved from local builder", args...) return envelope, err } func (pb *PayloadBuilder) CacheLatestVerifiedPayload( latestEnvelopeSlot math.Slot, latestEnvelope ctypes.BuiltExecutionPayloadEnv, ) { pb.muEnv.Lock() defer pb.muEnv.Unlock() pb.latestEnvelopeSlot = latestEnvelopeSlot pb.latestEnvelope = latestEnvelope } // getLatestVerifiedPayload returns the latest verified payload if it is for the given slot and fork version. func (pb *PayloadBuilder) getLatestVerifiedPayload( slot math.Slot, expectedForkVersion common.Version, ) ctypes.BuiltExecutionPayloadEnv { pb.muEnv.RLock() defer pb.muEnv.RUnlock() if pb.latestEnvelope == nil || slot != pb.latestEnvelopeSlot { return nil } payload := pb.latestEnvelope.GetExecutionPayload() if payload == nil { return nil } if version.Equals( pb.chainSpec.ActiveForkVersionForTimestamp(payload.GetTimestamp()), expectedForkVersion, ) { return pb.latestEnvelope } return nil } func (pb *PayloadBuilder) getPayload( ctx context.Context, payloadID engineprimitives.PayloadID, forkVersion common.Version, ) (ctypes.BuiltExecutionPayloadEnv, error) { envelope, err := pb.ee.GetPayload( ctx, &ctypes.GetPayloadRequest{ PayloadID: payloadID, ForkVersion: forkVersion, }, ) if err != nil { return nil, err } // envelope is guaranteed to be non-nil here if envelope.GetExecutionPayload().Withdrawals == nil { return nil, ErrNilWithdrawals } return envelope, nil } ================================================ FILE: payload/builder/payload_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package builder_test import ( "context" "testing" "github.com/berachain/beacon-kit/config/spec" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/payload/builder" "github.com/berachain/beacon-kit/payload/cache" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) func TestRetrievePayload(t *testing.T) { t.Parallel() chainSpec, err := spec.MainnetChainSpec() require.NoError(t, err) var ( slot = math.Slot(10) parentBlockRoot = common.Root{0x01} denebTimestamp = math.U64(1_737_381_600) // before mainnet Deneb1ForkTime dummyPayloadID = engineprimitives.PayloadID{0xab} ) validEnvelope := &mockExecutionPayloadEnvelope[*engineprimitives.BlobsBundleV1]{ ExecutionPayload: &ctypes.ExecutionPayload{ Timestamp: denebTimestamp, Withdrawals: engineprimitives.Withdrawals{}, }, BlobsBundle: &engineprimitives.BlobsBundleV1{}, } nilWithdrawalsEnvelope := &mockExecutionPayloadEnvelope[*engineprimitives.BlobsBundleV1]{ ExecutionPayload: &ctypes.ExecutionPayload{ Timestamp: denebTimestamp, Withdrawals: nil, }, BlobsBundle: &engineprimitives.BlobsBundleV1{}, } nilPayloadEnvelope := &mockExecutionPayloadEnvelope[*engineprimitives.BlobsBundleV1]{ ExecutionPayload: nil, } tests := []struct { name string // If non-nil, seed the PayloadIDCache before calling RetrievePayload. cachePayloadID *engineprimitives.PayloadID cacheForkVersion common.Version // Stub response from the execution engine's GetPayload. eeEnvelope ctypes.BuiltExecutionPayloadEnv // If non-nil, cache as the latest verified payload for the same slot. verifiedEnvelope ctypes.BuiltExecutionPayloadEnv expectedForkVersion common.Version wantEnvelope ctypes.BuiltExecutionPayloadEnv wantErr error }{ { name: "sunny path via PayloadIDCache", cachePayloadID: &dummyPayloadID, cacheForkVersion: version.Deneb(), eeEnvelope: validEnvelope, expectedForkVersion: version.Deneb(), wantEnvelope: validEnvelope, }, { name: "nil withdrawals list rejected", cachePayloadID: &dummyPayloadID, cacheForkVersion: version.Deneb(), eeEnvelope: nilWithdrawalsEnvelope, expectedForkVersion: version.Deneb(), wantErr: builder.ErrNilWithdrawals, }, { name: "fallback reuses verified payload on fork version match", verifiedEnvelope: validEnvelope, expectedForkVersion: version.Deneb(), wantEnvelope: validEnvelope, }, { name: "fallback rejects verified payload on fork version mismatch", verifiedEnvelope: validEnvelope, expectedForkVersion: version.Electra(), wantErr: builder.ErrPayloadIDNotFound, }, { name: "fallback skips verified payload with nil execution payload", verifiedEnvelope: nilPayloadEnvelope, expectedForkVersion: version.Deneb(), wantErr: builder.ErrPayloadIDNotFound, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() ee := &stubExecutionEngine{payloadEnvToReturn: tt.eeEnvelope} pc := cache.NewPayloadIDCache() pb := builder.New( &builder.Config{Enabled: true}, chainSpec, noop.NewLogger[any](), ee, pc, &stubAttributesFactory{}, ) if tt.cachePayloadID != nil { pc.Set(slot, parentBlockRoot, *tt.cachePayloadID, tt.cacheForkVersion) } if tt.verifiedEnvelope != nil { pb.CacheLatestVerifiedPayload(slot, tt.verifiedEnvelope) } //nolint:govet // shadow err so that parallel tests do not overwrite err. envelope, err := pb.RetrievePayload(t.Context(), slot, parentBlockRoot, tt.expectedForkVersion) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) return } require.NoError(t, err) require.Equal(t, tt.wantEnvelope, envelope) }) } } // HELPERS section type mockExecutionPayloadEnvelope[BlobsBundleT engineprimitives.BlobsBundle] struct { ExecutionPayload *ctypes.ExecutionPayload `json:"executionPayload"` BlockValue *math.U256 `json:"blockValue"` BlobsBundle BlobsBundleT `json:"blobsBundle"` ExecutionRequests []ctypes.EncodedExecutionRequest `json:"executionRequests"` Override bool `json:"shouldOverrideBuilder"` } func (m mockExecutionPayloadEnvelope[BlobsBundleT]) GetExecutionPayload() *ctypes.ExecutionPayload { return m.ExecutionPayload } func (m mockExecutionPayloadEnvelope[BlobsBundleT]) GetBlockValue() *math.U256 { return m.BlockValue } func (m mockExecutionPayloadEnvelope[BlobsBundleT]) GetBlobsBundle() engineprimitives.BlobsBundle { return m.BlobsBundle } func (m mockExecutionPayloadEnvelope[BlobsBundleT]) GetEncodedExecutionRequests() []ctypes.EncodedExecutionRequest { return m.ExecutionRequests } func (m mockExecutionPayloadEnvelope[BlobsBundleT]) ShouldOverrideBuilder() bool { return m.Override } var errStubNotImplemented = errors.New("stub not implemented") type stubExecutionEngine struct { payloadEnvToReturn ctypes.BuiltExecutionPayloadEnv errToReturn error } func (ee *stubExecutionEngine) GetPayload( context.Context, *ctypes.GetPayloadRequest, ) (ctypes.BuiltExecutionPayloadEnv, error) { return ee.payloadEnvToReturn, ee.errToReturn } func (ee *stubExecutionEngine) NotifyForkchoiceUpdate( context.Context, *ctypes.ForkchoiceUpdateRequest, ) (*engineprimitives.PayloadID, error) { return nil, errStubNotImplemented } type stubAttributesFactory struct{} func (ee *stubAttributesFactory) BuildPayloadAttributes( math.U64, engineprimitives.Withdrawals, common.Bytes32, common.Root, *crypto.BLSPubkey, ) (*engineprimitives.PayloadAttributes, error) { return nil, errStubNotImplemented } ================================================ FILE: payload/cache/payload_id.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cache import ( "sync" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) // historicalPayloadIDCacheSize defines the maximum number of slots to retain // in the cache. Beyond this number, older slots will be pruned to manage // memory usage. const historicalPayloadIDCacheSize = 2 // PayloadIDCache provides a mechanism to store and retrieve payload IDs based // on slot and parent block hash. It is designed to improve the efficiency of // payload ID retrieval by caching recent entries. type PayloadIDCache struct { // mu protects access to the slotToBlockRootToPayloadID map. mu sync.RWMutex // slotToBlockRootToPayloadID is used for storing payload ID mappings slotToBlockRootToPayloadID map[payloadIDCacheKey]PayloadIDCacheResult } // payloadIDCacheKey is the (slot, root) tuple that is used to access a // payloadID from the cache. type payloadIDCacheKey struct { slot math.Slot root common.Root } type PayloadIDCacheResult struct { PayloadID engineprimitives.PayloadID ForkVersion common.Version } // NewPayloadIDCache initializes and returns a new instance of PayloadIDCache. // It prepares the internal data structures for storing payload ID mappings. func NewPayloadIDCache() *PayloadIDCache { return &PayloadIDCache{ mu: sync.RWMutex{}, slotToBlockRootToPayloadID: make( map[payloadIDCacheKey]PayloadIDCacheResult, ), } } // Has retrieves the payload ID associated with a given slot and eth1 hash. // Has checks if a payload ID exists for a given slot and eth1 hash. func (p *PayloadIDCache) Has( slot math.Slot, blockRoot common.Root, ) bool { p.mu.RLock() defer p.mu.RUnlock() _, ok := p.slotToBlockRootToPayloadID[payloadIDCacheKey{slot, blockRoot}] return ok } // Get retrieves the payloadID from the cache. It does *not* evict // payloadID from the cache upon successful retrieval. Clearing the cache is // done via Delete and via pruning in Set. func (p *PayloadIDCache) Get( slot math.Slot, blockRoot common.Root, ) (PayloadIDCacheResult, bool) { p.mu.RLock() defer p.mu.RUnlock() key := payloadIDCacheKey{slot, blockRoot} pid, ok := p.slotToBlockRootToPayloadID[key] if !ok { return PayloadIDCacheResult{}, false } return pid, true } // Set updates or inserts a payload ID for a given slot and eth1 hash. // It also prunes entries in the cache that are older than the // historicalPayloadIDCacheSize limit. func (p *PayloadIDCache) Set( slot math.Slot, blockRoot common.Root, pid engineprimitives.PayloadID, version common.Version, ) { p.mu.Lock() defer p.mu.Unlock() // Prune older slots to maintain the cache size limit. if slot >= historicalPayloadIDCacheSize { p.prunePrior(slot - historicalPayloadIDCacheSize) } // Update the cache with the new payload ID. p.slotToBlockRootToPayloadID[payloadIDCacheKey{slot, blockRoot}] = PayloadIDCacheResult{ PayloadID: pid, ForkVersion: version, } } // Delete deletes a payload ID from the cache if it exists. func (p *PayloadIDCache) Delete( slot math.Slot, blockRoot common.Root, ) { p.mu.Lock() defer p.mu.Unlock() delete(p.slotToBlockRootToPayloadID, payloadIDCacheKey{slot, blockRoot}) } // prunePrior removes payload IDs from the cache for slots less than // the specified slot. This method helps in managing the memory usage // of the cache by discarding outdated entries. func (p *PayloadIDCache) prunePrior(slot math.Slot) { for s := range p.slotToBlockRootToPayloadID { if s.slot < slot { delete(p.slotToBlockRootToPayloadID, s) } } } ================================================ FILE: payload/cache/payload_id_fuzz_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cache_test import ( "sync" "testing" "time" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/payload/cache" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) func FuzzPayloadIDCacheBasic(f *testing.F) { f.Add(uint64(1), []byte{1, 2, 3}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) f.Add(uint64(2), []byte{4, 5, 6}, []byte{9, 10, 11, 12, 13, 14, 15, 16}) f.Add(uint64(3), []byte{7, 8, 9}, []byte{17, 18, 19, 20, 21, 22, 23, 24}) f.Fuzz(func(t *testing.T, s uint64, _r, _p []byte) { var r [32]byte copy(r[:], _r) slot := math.Slot(s) pid := engineprimitives.PayloadID(_p[:8]) cacheUnderTest := cache.NewPayloadIDCache() cacheUnderTest.Set(slot, r, pid, version.Deneb()) p, ok := cacheUnderTest.Get(slot, r) require.True(t, ok) require.Equal(t, pid, p.PayloadID) // Test overwriting the same slot and root with a different PayloadID newPid := engineprimitives.PayloadID{} for i := range pid { newPid[i] = pid[i] + 1 // Simple mutation for a new PayloadID } cacheUnderTest.Set(slot, r, newPid, version.Deneb()) p, ok = cacheUnderTest.Get(slot, r) require.True(t, ok) require.Equal( t, newPid, p.PayloadID, "PayloadID should be overwritten with the new value") // Verify deletion cacheUnderTest.Delete(slot, r) ok = cacheUnderTest.Has(slot, r) require.False(t, ok, "Entry should be pruned and not found") }) } func FuzzPayloadIDInvalidInput(f *testing.F) { // Intentionally invalid inputs f.Add(uint64(1), []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}, []byte{1, 2, 3}) f.Fuzz(func(t *testing.T, s uint64, _r, _p []byte) { var r [32]byte slot := math.Slot(s) if len(_r) > 32 { // Expecting an error or specific handling of oversized input t.Skip( "Skipping test due to intentionally invalid input size for root.", ) } copy(r[:], _r) var paddedPayload [8]byte copy(paddedPayload[:], _p[:min(len(_p), 8)]) pid := [8]byte(paddedPayload[:]) cacheUnderTest := cache.NewPayloadIDCache() cacheUnderTest.Set(slot, r, pid, version.Deneb()) _, ok := cacheUnderTest.Get(slot, r) require.True(t, ok) }) } func FuzzPayloadIDCacheConcurrency(f *testing.F) { f.Add(uint64(1), []byte{1, 2, 3}, []byte{1, 2, 3, 4}) f.Fuzz(func(t *testing.T, s uint64, _r, _p []byte) { cacheUnderTest := cache.NewPayloadIDCache() slot := math.Slot(s) var wg sync.WaitGroup wg.Add(2) // Set operation in one goroutine go func() { defer wg.Done() var r [32]byte copy(r[:], _r) var paddedPayload [8]byte copy(paddedPayload[:], _p[:min(len(_p), 8)]) pid := [8]byte(paddedPayload[:]) cacheUnderTest.Set(slot, r, pid, version.Deneb()) }() // Get operation in another goroutine var ok bool go func() { defer wg.Done() time.Sleep( 10 * time.Millisecond, ) // Small delay to let the Set operation proceed var r [32]byte copy(r[:], _r) _, ok = cacheUnderTest.Get(slot, r) }() wg.Wait() require.True(t, ok) }) } ================================================ FILE: payload/cache/payload_id_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package cache_test import ( "testing" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/payload/cache" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) func TestPayloadIDCache(t *testing.T) { t.Parallel() cacheUnderTest := cache.NewPayloadIDCache() t.Run("Get from empty cache", func(t *testing.T) { var r [32]byte p, ok := cacheUnderTest.Get(0, r) require.False(t, ok) require.Equal(t, engineprimitives.PayloadID{}, p.PayloadID) }) t.Run("Set and Get", func(t *testing.T) { slot := math.Slot(1234) r := [32]byte{1, 2, 3} pid := engineprimitives.PayloadID{1, 2, 3, 3, 7, 8, 7, 8} cacheUnderTest.Set(slot, r, pid, version.Deneb()) p, ok := cacheUnderTest.Get(slot, r) require.True(t, ok) require.Equal(t, pid, p.PayloadID) }) t.Run("Overwrite existing", func(t *testing.T) { slot := math.Slot(1234) r := [32]byte{1, 2, 3} newPid := engineprimitives.PayloadID{9, 9, 9, 9, 9, 9, 9, 9} cacheUnderTest.Set(slot, r, newPid, version.Deneb()) p, ok := cacheUnderTest.Get(slot, r) require.True(t, ok) require.Equal(t, newPid, p.PayloadID) }) t.Run("Prune and verify deletion", func(t *testing.T) { slot := math.Slot(9456456) r := [32]byte{4, 5, 6} pid := engineprimitives.PayloadID{4, 5, 6, 6, 9, 0, 9, 0} // Set pid for slot. cacheUnderTest.Set(slot, r, pid, version.Deneb()) // Set historicalPayloadIDCacheSize+1 number of pids. This should // prune the first slot from the cache. cacheUnderTest.Set(slot+1, r, pid, version.Deneb()) cacheUnderTest.Set(slot+2, r, pid, version.Deneb()) cacheUnderTest.Set(slot+3, r, pid, version.Deneb()) // Attempt to retrieve pruned slot. ok := cacheUnderTest.Has(slot, r) require.False(t, ok) }) t.Run("Multiple entries and prune", func(t *testing.T) { numEntries := 10 historicalPayloadIDCacheSize := 2 // Set multiple entries for i := range uint8(numEntries) { slot := math.Slot(i) r := [32]byte{i, i + 1, i + 2} pid := [8]byte{ i, i, i, i, i, i, i, i, } cacheUnderTest.Set(slot, r, pid, version.Deneb()) } // Only the last historicalPayloadIDCacheSize+1 number of entries // should still exist. for i := range uint8(numEntries - (historicalPayloadIDCacheSize + 1)) { slot := math.Slot(i) r := [32]byte{i, i + 1, i + 2} ok := cacheUnderTest.Has(slot, r) require.False(t, ok, "Expected entry to be pruned for slot", slot) } for i := uint8(numEntries - (historicalPayloadIDCacheSize + 1)); i < uint8(numEntries); i++ { slot := math.Slot(i) r := [32]byte{i, i + 1, i + 2} ok := cacheUnderTest.Has(slot, r) require.True(t, ok, "Expected entry to exist for slot", slot) } }) } ================================================ FILE: primitives/bytes/b.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package bytes import ( "github.com/berachain/beacon-kit/primitives/encoding/hex" ) // Bytes marshals/unmarshals as a JSON string with 0x prefix. // The empty slice marshals as "0x". type Bytes []byte // MarshalText implements encoding.TextMarshaler. func (b Bytes) MarshalText() ([]byte, error) { return []byte(hex.EncodeBytes(b)), nil } // UnmarshalJSON implements json.Unmarshaler. func (b *Bytes) UnmarshalJSON(input []byte) error { strippedInput, err := hex.ValidateQuotedString(input) if err != nil { return err } return b.UnmarshalText(strippedInput) } // UnmarshalText implements encoding.TextUnmarshaler. func (b *Bytes) UnmarshalText(input []byte) error { dec, err := hex.UnmarshalByteText(input) if err != nil { return err } *b = Bytes(dec) return nil } // String returns the hex encoding of b. func (b Bytes) String() string { return hex.EncodeBytes(b) } ================================================ FILE: primitives/bytes/b20.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package bytes import ( "fmt" "github.com/berachain/beacon-kit/primitives/encoding/hex" ) const ( // B20Size represents a 20-byte size. B20Size = 20 ) // B20 represents a 20-byte fixed-size byte array. // For SSZ purposes it is serialized a `Vector[Byte, 20]`. type B20 [20]byte // ToBytes20 is a utility function that transforms a byte slice into a fixed // 20-byte array. It errs if input has not the required size. func ToBytes20(input []byte) (B20, error) { if len(input) != B20Size { return B20{}, fmt.Errorf( "%w, got %d, expected %d", ErrIncorrectLength, len(input), B20Size, ) } return B20(input), nil } /* -------------------------------------------------------------------------- */ /* TextMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalText implements the encoding.TextMarshaler interface for B20. func (h B20) MarshalText() ([]byte, error) { return []byte(h.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface for B20. func (h *B20) UnmarshalText(text []byte) error { return UnmarshalTextHelper(h[:], text) } // String returns the hex string representation of B20. func (h *B20) String() string { return hex.EncodeBytes(h[:]) } /* -------------------------------------------------------------------------- */ /* JSONMarshaler */ /* -------------------------------------------------------------------------- */ // UnmarshalJSON implements the json.Unmarshaler interface for B20. func (h *B20) UnmarshalJSON(input []byte) error { return UnmarshalJSONHelper(h[:], input) } /* -------------------------------------------------------------------------- */ /* SSZMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalSSZ implements the SSZ marshaling for B20. func (h B20) MarshalSSZ() ([]byte, error) { return h[:], nil } // HashTreeRoot returns the hash tree root of the B20. func (h B20) HashTreeRoot() (B32, error) { return ToBytes32(ExtendToSize(h[:], B32Size)) } ================================================ FILE: primitives/bytes/b20_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package bytes_test import ( "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/stretchr/testify/require" ) func TestBytes20MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B20 want string }{ { name: "valid bytes", input: bytes.B20{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14}, want: "0x0102030405060708090a0b0c0d0e0f1011121314", }, { name: "all zeros", input: bytes.B20{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, want: "0x0000000000000000000000000000000000000000", }, { name: "all ones", input: bytes.B20{ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, want: "0xffffffffffffffffffffffffffffffffffffffff", }, { name: "mixed bytes", input: bytes.B20{ 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE}, want: "0xaabbccddeeff112233445566778899aabbccddee", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalText() require.NoError(t, err) require.Equal(t, tt.want, string(got)) }) } } func TestBytes20MarshalSSZ(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B20 want []byte }{ { name: "marshal B20", input: bytes.B20{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, }, want: []byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalSSZ() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } func TestBytes20HashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B20 want bytes.B32 }{ { name: "hash tree root", input: bytes.B20{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, }, want: [32]byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.HashTreeRoot() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } func TestBytes20UnmarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B20 wantErr bool }{ { name: "valid hex", input: "0x0102030405060708090a0b0c0d0e0f1011121314", want: bytes.B20{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14}, wantErr: false, }, { name: "invalid hex", input: "0xZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ", want: bytes.B20{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B20 err := got.UnmarshalText([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestBytes20UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B20 wantErr bool }{ { name: "valid JSON", input: "\"0x0102030405060708090a0b0c0d0e0f1011121314\"", want: bytes.B20{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14}, wantErr: false, }, { name: "invalid JSON", input: "\"0xZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\"", want: bytes.B20{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B20 err := got.UnmarshalJSON([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestToBytes20(t *testing.T) { t.Parallel() tests := []struct { name string input []byte wantRes bytes.B20 wantErr error }{ { name: "exact 20 bytes", input: []byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, }, wantRes: bytes.B20{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, }, wantErr: nil, }, { name: "less than 20 bytes", input: []byte{0x01, 0x02, 0x03, 0x04, 0x05}, wantRes: bytes.B20{}, wantErr: bytes.ErrIncorrectLength, }, { name: "more than 20 bytes", input: []byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, }, wantRes: bytes.B20{}, wantErr: bytes.ErrIncorrectLength, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := bytes.ToBytes20(tt.input) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.wantRes, result) } }) } } ================================================ FILE: primitives/bytes/b256.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package bytes import ( "fmt" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/prysmaticlabs/gohashtree" ) const ( // B256Size represents a 256-byte size. B256Size = 256 ) // B256 represents a 256-byte fixed-size byte array. // For SSZ purposes it is serialized a `Vector[Byte, 256]`. type B256 [256]byte // ToBytes256 is a utility function that transforms a byte slice into a fixed // 256-byte array. It errs if input has not the required size. func ToBytes256(input []byte) (B256, error) { if len(input) != B256Size { return B256{}, fmt.Errorf( "%w, got %d, expected %d", ErrIncorrectLength, len(input), B256Size, ) } return B256(input), nil } /* -------------------------------------------------------------------------- */ /* TextMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalText implements the encoding.TextMarshaler interface for B256. func (h B256) MarshalText() ([]byte, error) { return []byte(h.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface for B256. func (h *B256) UnmarshalText(text []byte) error { return UnmarshalTextHelper(h[:], text) } // String returns the hex string representation of B256. func (h *B256) String() string { return hex.EncodeBytes(h[:]) } /* -------------------------------------------------------------------------- */ /* JSONMarshaler */ /* -------------------------------------------------------------------------- */ // UnmarshalJSON implements the json.Unmarshaler interface for B256. func (h *B256) UnmarshalJSON(input []byte) error { return UnmarshalJSONHelper(h[:], input) } /* -------------------------------------------------------------------------- */ /* SSZMarshaler */ /* -------------------------------------------------------------------------- */ // SizeSSZ returns the size of its SSZ encoding in bytes. func (h B256) SizeSSZ() uint32 { return B256Size } // MarshalSSZ implements the SSZ marshaling for B256. func (h B256) MarshalSSZ() ([]byte, error) { return h[:], nil } // HashTreeRoot returns the hash tree root of the B256. func (h B256) HashTreeRoot() (B32, error) { //nolint:mnd // for a tree height of 3 we need 8 working chunks. result := make([][32]byte, 8) copy(result[0][:], h[:32]) copy(result[1][:], h[32:64]) copy(result[2][:], h[64:96]) copy(result[3][:], h[96:128]) copy(result[4][:], h[128:160]) copy(result[5][:], h[160:192]) copy(result[6][:], h[192:224]) copy(result[7][:], h[224:256]) gohashtree.HashChunks(result, result) gohashtree.HashChunks(result, result) gohashtree.HashChunks(result, result) return result[0], nil } ================================================ FILE: primitives/bytes/b32.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package bytes import ( "fmt" "github.com/berachain/beacon-kit/primitives/encoding/hex" ) const ( // B32Size represents a 32-byte size. B32Size = 32 ) // B32 represents a 32-byte fixed-size byte array. // For SSZ purposes it is serialized a `Vector[Byte, 32]`. type B32 [B32Size]byte // ToBytes32 is a utility function that transforms a byte slice into a fixed // 32-byte array It errs if input has not the required size. func ToBytes32(input []byte) (B32, error) { if len(input) != B32Size { return B32{}, fmt.Errorf( "%w, got %d, expected %d", ErrIncorrectLength, len(input), B32Size, ) } return B32(input), nil } /* -------------------------------------------------------------------------- */ /* TextMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalText implements the encoding.TextMarshaler interface for B32. func (h B32) MarshalText() ([]byte, error) { return []byte(h.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface for B32. func (h *B32) UnmarshalText(text []byte) error { return UnmarshalTextHelper(h[:], text) } // String returns the hex string representation of B32. func (h B32) String() string { return hex.EncodeBytes(h[:]) } /* -------------------------------------------------------------------------- */ /* JSONMarshaler */ /* -------------------------------------------------------------------------- */ // UnmarshalJSON implements the json.Unmarshaler interface for B32. func (h *B32) UnmarshalJSON(input []byte) error { return UnmarshalJSONHelper(h[:], input) } /* -------------------------------------------------------------------------- */ /* SSZMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalSSZ implements the SSZ marshaling for B32. func (h B32) MarshalSSZ() ([]byte, error) { return h[:], nil } // HashTreeRoot returns the hash tree root of the B32. func (h B32) HashTreeRoot() B32 { return h } ================================================ FILE: primitives/bytes/b32_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package bytes_test import ( "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/stretchr/testify/require" ) func TestBytes32UnmarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B32 wantErr bool }{ { name: "valid input", input: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", want: bytes.B32{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, }, wantErr: false, }, { name: "invalid input - not hex", input: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", wantErr: true, }, { name: "invalid input - wrong length", input: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B32 err := got.UnmarshalText([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestBytes32UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B32 wantErr bool }{ { name: "valid input", input: `"0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"`, want: bytes.B32{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, }, wantErr: false, }, { name: "invalid input - not hex", input: `"0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20"`, wantErr: true, }, { name: "invalid input - wrong length", input: `"0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"`, wantErr: true, }, { name: "invalid input - extra characters", input: `"0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122"`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B32 err := got.UnmarshalJSON([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestBytes32MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B32 want string }{ { name: "valid input", input: bytes.B32{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}, want: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", }, { name: "empty input", input: bytes.B32{}, want: "0x0000000000000000000000000000000000000000000000000000000000000000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalText() require.NoError(t, err) require.Equal(t, tt.want, string(got)) }) } } func TestBytes32String(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B32 want string }{ { name: "valid input", input: bytes.B32{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20}, want: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20", }, { name: "empty input", input: bytes.B32{}, want: "0x0000000000000000000000000000000000000000000000000000000000000000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.input.String() require.Equal(t, tt.want, got) }) } } func TestToBytes32(t *testing.T) { t.Parallel() tests := []struct { name string input []byte wantRes bytes.B32 wantErr error }{ { name: "Input less than 32 bytes", input: []byte{1, 2, 3}, wantRes: bytes.B32{}, wantErr: bytes.ErrIncorrectLength, }, { name: "Input exactly 32 bytes", input: make([]byte, 32), wantRes: bytes.B32{}, wantErr: nil, }, { name: "Input more than 32 bytes", input: make([]byte, 40), wantRes: bytes.B32{}, wantErr: bytes.ErrIncorrectLength, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := bytes.ToBytes32(tt.input) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.wantRes, result) } }) } } func TestB32MarshalSSZ(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B32 want []byte }{ { name: "valid bytes", input: bytes.B32{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20}, want: []byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalSSZ() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } ================================================ FILE: primitives/bytes/b4.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package bytes import ( "encoding/binary" "fmt" "github.com/berachain/beacon-kit/primitives/encoding/hex" ) const ( // B4Size represents a 4-byte size. B4Size = 4 ) // B4 represents a 4-byte fixed-size byte array. // For SSZ purposes it is serialized a `Vector[Byte, 4]`. type B4 [4]byte // ToBytes4 is a utility function that transforms a byte slice into a fixed // 4-byte array. It errs if input has not the required size. func ToBytes4(input []byte) (B4, error) { if len(input) != B4Size { return B4{}, fmt.Errorf( "%w, got %d, expected %d", ErrIncorrectLength, len(input), B4Size, ) } return B4(input), nil } /* -------------------------------------------------------------------------- */ /* TextMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalText implements the encoding.TextMarshaler interface for B4. func (h B4) MarshalText() ([]byte, error) { return []byte(h.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface for B4. func (h *B4) UnmarshalText(text []byte) error { return UnmarshalTextHelper(h[:], text) } // String returns the hex string representation of B4. func (h B4) String() string { return hex.EncodeBytes(h[:]) } /* -------------------------------------------------------------------------- */ /* JSONMarshaler */ /* -------------------------------------------------------------------------- */ // UnmarshalJSON implements the json.Unmarshaler interface for B4. func (h *B4) UnmarshalJSON(input []byte) error { return UnmarshalJSONHelper(h[:], input) } /* -------------------------------------------------------------------------- */ /* SSZMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalSSZ implements the SSZ marshaling for B8. func (h B4) MarshalSSZ() ([]byte, error) { return h[:], nil } // HashTreeRoot returns the hash tree root of the B8. func (h B4) HashTreeRoot() (B32, error) { return ToBytes32(ExtendToSize(h[:], B32Size)) } /* -------------------------------------------------------------------------- */ /* uint32 conversion */ /* -------------------------------------------------------------------------- */ // FromUint32 returns a new B4 from a uint32. func FromUint32(v uint32) B4 { h := B4{} binary.LittleEndian.PutUint32(h[:], v) return h } // ToUint32 returns a new uint32 from a B4. func (h B4) ToUint32() uint32 { return binary.LittleEndian.Uint32(h[:]) } ================================================ FILE: primitives/bytes/b48.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package bytes import ( "fmt" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/prysmaticlabs/gohashtree" ) const ( // B48Size represents a 48-byte size. B48Size = 48 ) // B48 represents a 48-byte fixed-size byte array. // For SSZ purposes it is serialized a `Vector[Byte, 48]`. type B48 [48]byte // ToBytes48 is a utility function that transforms a byte slice into a fixed // 48-byte array. It errs if input has not the required size. func ToBytes48(input []byte) (B48, error) { if len(input) != B48Size { return B48{}, fmt.Errorf( "%w, got %d, expected %d", ErrIncorrectLength, len(input), B48Size, ) } return B48(input), nil } /* -------------------------------------------------------------------------- */ /* TextMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalText implements the encoding.TextMarshaler interface for B48. func (h B48) MarshalText() ([]byte, error) { return []byte(h.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface for B48. func (h *B48) UnmarshalText(text []byte) error { return UnmarshalTextHelper(h[:], text) } // String returns the hex string representation of B48. func (h B48) String() string { return hex.EncodeBytes(h[:]) } /* -------------------------------------------------------------------------- */ /* JSONMarshaler */ /* -------------------------------------------------------------------------- */ // UnmarshalJSON implements the json.Unmarshaler interface for B48. func (h *B48) UnmarshalJSON(input []byte) error { return UnmarshalJSONHelper(h[:], input) } /* -------------------------------------------------------------------------- */ /* SSZMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalSSZ implements the SSZ marshaling for B48. func (h B48) MarshalSSZ() ([]byte, error) { return h[:], nil } func (h B48) HashTreeRoot() B32 { //nolint:mnd // for a tree height of 1 we need 2 working chunks. result := make([][32]byte, 2) copy(result[0][:], h[:32]) copy(result[1][:], h[32:48]) gohashtree.HashChunks(result, result) return result[0] } ================================================ FILE: primitives/bytes/b48_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package bytes_test import ( "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/merkle/zero" "github.com/stretchr/testify/require" ) func TestBytes48String(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B48 want string }{ { name: "valid input", input: bytes.B48{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, }, want: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30", }, { name: "empty input", input: bytes.B48{}, want: "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.input.String() require.Equal(t, tt.want, got) }) } } func TestBytes48MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B48 want string }{ { name: "valid input", input: bytes.B48{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, }, want: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30", }, { name: "empty input", input: bytes.B48{}, want: "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalText() require.NoError(t, err) require.Equal(t, tt.want, string(got)) }) } } func TestBytes48UnmarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B48 wantErr bool }{ { name: "valid input", input: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30", want: bytes.B48{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, }, }, { name: "invalid input - not hex", input: "0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30", wantErr: true, }, { name: "invalid input - wrong length", input: "0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B48 err := got.UnmarshalText([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestToBytes48(t *testing.T) { t.Parallel() tests := []struct { name string input []byte wantRes bytes.B48 wantErr error }{ { name: "Input less than 48 bytes", input: []byte{1, 2, 3}, wantRes: bytes.B48{}, wantErr: bytes.ErrIncorrectLength, }, { name: "Input exactly 48 bytes", input: make([]byte, 48), wantRes: bytes.B48{}, }, { name: "Input more than 48 bytes", input: make([]byte, 60), wantRes: bytes.B48{}, wantErr: bytes.ErrIncorrectLength, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := bytes.ToBytes48(tt.input) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.wantRes, result) } }) } } func TestB48UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input string expected bytes.B48 wantErr bool }{ { name: "Valid input", input: `"0x010203000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"`, expected: bytes.B48{1, 2, 3}, wantErr: false, }, { name: "Empty input", input: `"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"`, expected: bytes.B48{}, wantErr: false, }, { name: "Invalid input - not hex", input: `"invalid"`, expected: bytes.B48{}, wantErr: true, }, { name: "Invalid input - odd length", input: `"0x010203"`, expected: bytes.B48{}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B48 err := got.UnmarshalJSON([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.expected, got) } }) } } func TestB48_HashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B48 want bytes.B32 }{ { name: "Zero bytes", input: bytes.B48{}, want: zero.Hashes[1], }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.input.HashTreeRoot() require.Equal(t, tt.want, result) }) } } func TestB48MarshalSSZ(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B48 want []byte }{ { name: "valid bytes", input: bytes.B48{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30}, want: []byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalSSZ() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } ================================================ FILE: primitives/bytes/b4_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package bytes_test import ( "encoding/binary" "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/stretchr/testify/require" ) func TestFromUint32_CustomType(t *testing.T) { t.Parallel() input := uint32(123456789) expected := bytes.B4{} binary.LittleEndian.PutUint32(expected[:], input) result := bytes.FromUint32(input) require.Equal(t, expected, result) } func TestToUint32_CustomType(t *testing.T) { t.Parallel() input := bytes.B4{0x15, 0xCD, 0x5B, 0x07} expected := uint32(123456789) result := input.ToUint32() require.Equal(t, expected, result) } func TestBytes4UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B4 wantErr bool }{ { name: "valid input", input: `"0x01020304"`, want: bytes.B4{0x01, 0x02, 0x03, 0x04}, wantErr: false, }, { name: "invalid input - not hex", input: `"01020304"`, wantErr: true, }, { name: "invalid input - wrong length", input: `"0x010203"`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B4 err := got.UnmarshalJSON([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestBytes4String(t *testing.T) { t.Parallel() tests := []struct { name string h bytes.B4 want string }{ { name: "non-empty bytes", h: bytes.B4{0x01, 0x02, 0x03, 0x04}, want: "0x01020304", }, { name: "empty bytes", h: bytes.B4{}, want: "0x00000000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.h.String() require.Equal(t, tt.want, got) }) } } func TestBytes4MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string h bytes.B4 want string }{ { name: "valid bytes", h: bytes.B4{0x01, 0x02, 0x03, 0x04}, want: "0x01020304", }, { name: "all zeros", h: bytes.B4{0x00, 0x00, 0x00, 0x00}, want: "0x00000000", }, { name: "all ones", h: bytes.B4{0xFF, 0xFF, 0xFF, 0xFF}, want: "0xffffffff", }, { name: "mixed bytes", h: bytes.B4{0xAA, 0xBB, 0xCC, 0xDD}, want: "0xaabbccdd", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.h.MarshalText() require.NoError(t, err) require.Equal(t, tt.want, string(got)) }) } } func TestBytes4UnmarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B4 wantErr bool }{ { name: "valid input", input: "0x01020304", want: bytes.B4{0x01, 0x02, 0x03, 0x04}, wantErr: false, }, { name: "invalid input - not hex", input: "01020304", wantErr: true, }, { name: "invalid input - wrong length", input: "0x010203", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B4 err := got.UnmarshalText([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestToBytes4(t *testing.T) { t.Parallel() tests := []struct { name string input []byte wantRes bytes.B4 wantErr error }{ { name: "Input less than 4 bytes", input: []byte{0x01, 0x02}, wantRes: bytes.B4{}, wantErr: bytes.ErrIncorrectLength, }, { name: "Input exactly 4 bytes", input: []byte{0x01, 0x02, 0x03, 0x04}, wantRes: bytes.B4{0x01, 0x02, 0x03, 0x04}, }, { name: "Input more than 4 bytes", input: []byte{0x01, 0x02, 0x03, 0x04, 0x05}, wantRes: bytes.B4{}, wantErr: bytes.ErrIncorrectLength, }, { name: "Empty input", input: []byte{}, wantRes: bytes.B4{}, wantErr: bytes.ErrIncorrectLength, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := bytes.ToBytes4(tt.input) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.wantRes, result) } }) } } func TestBytes4MarshalSSZ(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B4 want []byte }{ { name: "marshal B4", input: bytes.B4{0x01, 0x02, 0x03, 0x04}, want: []byte{0x01, 0x02, 0x03, 0x04}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalSSZ() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } func TestBytes4HashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B4 want bytes.B32 }{ { name: "hash tree root", input: bytes.B4{0x01, 0x02, 0x03, 0x04}, want: bytes.B32{0x01, 0x02, 0x03, 0x04}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.HashTreeRoot() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } ================================================ FILE: primitives/bytes/b8.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package bytes import ( "fmt" "github.com/berachain/beacon-kit/primitives/encoding/hex" ) const ( // B8Size represents an 8-byte size. B8Size = 8 ) // B8 represents an 8-byte fixed-size byte array. // For SSZ purposes it is serialized a `Vector[Byte, 8]`. type B8 [8]byte // ToBytes8 is a utility function that transforms a byte slice into a fixed // 8-byte array. It errs if input has not the required size. func ToBytes8(input []byte) (B8, error) { if len(input) != B8Size { return B8{}, fmt.Errorf( "%w, got %d, expected %d", ErrIncorrectLength, len(input), B8Size, ) } return B8(input), nil } /* -------------------------------------------------------------------------- */ /* TextMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalText implements the encoding.TextMarshaler interface for B8. func (h B8) MarshalText() ([]byte, error) { return []byte(h.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface for B8. func (h *B8) UnmarshalText(text []byte) error { return UnmarshalTextHelper(h[:], text) } // String returns the hex string representation of B8. func (h B8) String() string { return hex.EncodeBytes(h[:]) } /* -------------------------------------------------------------------------- */ /* JSONMarshaler */ /* -------------------------------------------------------------------------- */ // UnmarshalJSON implements the json.Unmarshaler interface for B8. func (h *B8) UnmarshalJSON(input []byte) error { return UnmarshalJSONHelper(h[:], input) } /* -------------------------------------------------------------------------- */ /* SSZMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalSSZ implements the SSZ marshaling for B8. func (h B8) MarshalSSZ() ([]byte, error) { return h[:], nil } // HashTreeRoot returns the hash tree root of the B8. func (h B8) HashTreeRoot() (B32, error) { return ToBytes32(ExtendToSize(h[:], B32Size)) } ================================================ FILE: primitives/bytes/b8_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package bytes_test import ( "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/stretchr/testify/require" ) func TestBytes8UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B8 wantErr bool }{ { name: "valid input", input: `"0x0102030405060708"`, want: bytes.B8{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, wantErr: false, }, { name: "invalid input - not hex", input: `"0102030405060708"`, wantErr: true, }, { name: "invalid input - wrong length", input: `"0x01020304"`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B8 err := got.UnmarshalJSON([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) } }) } } func TestBytes8String(t *testing.T) { t.Parallel() tests := []struct { name string h bytes.B8 want string }{ { name: "non-empty bytes", h: bytes.B8{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, want: "0x0102030405060708", }, { name: "empty bytes", h: bytes.B8{}, want: "0x0000000000000000", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.h.String() require.Equal(t, tt.want, got) }) } } func TestBytes8MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string h bytes.B8 want string }{ { name: "valid bytes", h: bytes.B8{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, want: "0x0102030405060708", }, { name: "empty bytes", h: bytes.B8{}, want: "0x0000000000000000", }, { name: "all zeros", h: bytes.B8{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, want: "0x0000000000000000", }, { name: "all ones", h: bytes.B8{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, want: "0xffffffffffffffff", }, { name: "mixed bytes", h: bytes.B8{0xaa, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22}, want: "0xaabbccddeeff1122", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.h.MarshalText() require.NoError(t, err) require.Equal(t, tt.want, string(got)) }) } } func TestBytes8UnmarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B8 wantErr bool }{ { name: "valid input", input: "0x0102030405060708", want: bytes.B8{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, wantErr: false, }, { name: "invalid input - not hex", input: "0102030405060708", wantErr: true, }, { name: "invalid input - wrong length", input: "0x01020304", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B8 err := got.UnmarshalText([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) } }) } } func TestToBytes8(t *testing.T) { t.Parallel() tests := []struct { name string input []byte wantRes bytes.B8 wantErr error }{ { name: "Exact 8 bytes", input: []byte{1, 2, 3, 4, 5, 6, 7, 8}, wantRes: bytes.B8{1, 2, 3, 4, 5, 6, 7, 8}, wantErr: nil, }, { name: "Less than 8 bytes", input: []byte{1, 2, 3, 4}, wantErr: bytes.ErrIncorrectLength, }, { name: "Two bytes", input: []byte{1, 2}, wantErr: bytes.ErrIncorrectLength, }, { name: "Empty input", input: []byte{}, wantErr: bytes.ErrIncorrectLength, }, { name: "More than 8 bytes", input: []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, wantErr: bytes.ErrIncorrectLength, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := bytes.ToBytes8(tt.input) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.wantRes, result) } }) } } func TestBytes8MarshalSSZ(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B8 want []byte }{ { name: "marshal B8", input: bytes.B8{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, want: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalSSZ() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } func TestBytes8HashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B8 want bytes.B32 }{ { name: "hash tree root", input: bytes.B8{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, want: [32]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.HashTreeRoot() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } ================================================ FILE: primitives/bytes/b96.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // package bytes import ( "fmt" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/prysmaticlabs/gohashtree" ) const ( // B96Size represents a 96-byte size. B96Size = 96 ) // B96 represents a 96-byte fixed-size byte array. // For SSZ purposes it is serialized a `Vector[Byte, 96]`. type B96 [96]byte // ToBytes96 is a utility function that transforms a byte slice into a fixed // 96-byte array. It errs if input has not the required size. func ToBytes96(input []byte) (B96, error) { if len(input) != B96Size { return B96{}, fmt.Errorf( "%w, got %d, expected %d", ErrIncorrectLength, len(input), B96Size, ) } return B96(input), nil } /* -------------------------------------------------------------------------- */ /* TextMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalText implements the encoding.TextMarshaler interface for B96. func (h B96) MarshalText() ([]byte, error) { return []byte(h.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface for B96. func (h *B96) UnmarshalText(text []byte) error { return UnmarshalTextHelper(h[:], text) } // String returns the hex string representation of B96. func (h *B96) String() string { return hex.EncodeBytes(h[:]) } /* -------------------------------------------------------------------------- */ /* JSONMarshaler */ /* -------------------------------------------------------------------------- */ // UnmarshalJSON implements the json.Unmarshaler interface for B96. func (h *B96) UnmarshalJSON(input []byte) error { return UnmarshalJSONHelper(h[:], input) } /* -------------------------------------------------------------------------- */ /* SSZMarshaler */ /* -------------------------------------------------------------------------- */ // MarshalSSZ implements the SSZ marshaling for B96. func (h B96) MarshalSSZ() ([]byte, error) { return h[:], nil } // HashTreeRoot returns the hash tree root of the B96. func (h B96) HashTreeRoot() B32 { //nolint:mnd // for a tree height of 2 we need 4 working chunks. result := make([][32]byte, 4) copy(result[0][:], h[:32]) copy(result[1][:], h[32:64]) copy(result[2][:], h[64:96]) gohashtree.HashChunks(result, result) gohashtree.HashChunks(result, result) return result[0] } ================================================ FILE: primitives/bytes/b96_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:lll // long strings. package bytes_test import ( "fmt" "strings" "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/berachain/beacon-kit/primitives/merkle/zero" "github.com/stretchr/testify/require" ) func TestBytes96UnmarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B96 wantErr bool }{ { name: "valid input", input: "0x" + strings.Repeat("01", 96), want: func() bytes.B96 { var b bytes.B96 for i := range b { b[i] = 0x01 } return b }(), }, { name: "invalid input - not hex", input: strings.Repeat("01", 96), wantErr: true, }, { name: "invalid input - wrong length", input: "0x" + strings.Repeat("01", 95), wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B96 err := got.UnmarshalText([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestBytes96UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input string want bytes.B96 wantErr bool }{ { name: "valid input", input: `"0x` + strings.Repeat("01", 96) + `"`, want: func() bytes.B96 { var b bytes.B96 for i := range b { b[i] = 0x01 } return b }(), }, { name: "invalid input - not hex", input: `"` + strings.Repeat("01", 96) + `"`, wantErr: true, }, { name: "invalid input - wrong length", input: `"0x` + strings.Repeat("01", 95) + `"`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var got bytes.B96 err := got.UnmarshalJSON([]byte(tt.input)) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func TestBytes96MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string h bytes.B96 want string }{ { name: "valid bytes", h: func() bytes.B96 { var b bytes.B96 for i := range b { b[i] = 0x01 } return b }(), want: "0x" + strings.Repeat("01", 96), }, { name: "empty bytes", h: bytes.B96{}, want: "0x" + strings.Repeat("00", 96), }, { name: "mixed bytes", h: func() bytes.B96 { var b bytes.B96 for i := 0; i < len(b); i++ { b[i] = byte(i % 256) } return b }(), want: "0x" + func() string { var s string for i := range 96 { s += fmt.Sprintf("%02x", i%256) } return s }(), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.h.MarshalText() require.NoError(t, err) require.Equal(t, tt.want, string(got)) }) } } func TestBytes96String(t *testing.T) { t.Parallel() tests := []struct { name string h bytes.B96 want string }{ { name: "non-empty bytes", h: func() bytes.B96 { var b bytes.B96 for i := range b { b[i] = 0x01 } return b }(), want: "0x" + strings.Repeat("01", 96), }, { name: "empty bytes", h: bytes.B96{}, want: "0x" + strings.Repeat("00", 96), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got := tt.h.String() require.Equal(t, tt.want, got) }) } } func TestToBytes96(t *testing.T) { t.Parallel() tests := []struct { name string input []byte wantRes bytes.B96 wantErr error }{ { name: "Input less than 96 bytes", input: []byte{1, 2, 3}, wantRes: bytes.B96{}, wantErr: bytes.ErrIncorrectLength, }, { name: "Input exactly 96 bytes", input: make([]byte, 96), wantRes: bytes.B96{}, }, { name: "Input more than 96 bytes", input: make([]byte, 100), wantRes: bytes.B96{}, wantErr: bytes.ErrIncorrectLength, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := bytes.ToBytes96(tt.input) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.wantRes, result) } }) } } func TestB96_HashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B96 want bytes.B32 }{ { name: "Zero bytes", input: bytes.B96{}, want: zero.Hashes[2], }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.input.HashTreeRoot() require.Equal(t, tt.want, result) }) } } func BenchmarkB96_MarshalJSON(b *testing.B) { data := bytes.B96{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} b.ResetTimer() for range b.N { _, err := json.Marshal(data) require.NoError(b, err) } } func BenchmarkB96_UnmarshalJSON(b *testing.B) { //nolint:lll // its a test. jsonData := []byte( `"0x0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5fdd"`, ) var data bytes.B96 b.ResetTimer() for range b.N { err := data.UnmarshalJSON(jsonData) require.NoError(b, err) } } func TestB96MarshalSSZ(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B96 want []byte }{ { name: "valid bytes", input: bytes.B96{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60}, want: []byte{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalSSZ() require.NoError(t, err) require.Equal(t, tt.want, got) }) } } ================================================ FILE: primitives/bytes/b_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package bytes_test import ( stdhex "encoding/hex" "reflect" "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/stretchr/testify/require" ) func TestFromHex(t *testing.T) { t.Parallel() tests := []struct { name string input string wantOutput bytes.Bytes wantErr error }{ { name: "Valid hex string", input: "0x48656c6c6f", wantOutput: bytes.Bytes{0x48, 0x65, 0x6c, 0x6c, 0x6f}, wantErr: nil, }, { name: "Empty hex string", input: "0x", wantOutput: bytes.Bytes{}, wantErr: nil, }, { name: "Invalid hex string - odd length", input: "0x12345", wantOutput: nil, wantErr: stdhex.ErrLength, }, { name: "Invalid hex string - no 0x prefix", input: "12345", wantOutput: nil, wantErr: hex.ErrMissingPrefix, }, { name: "Empty input string", input: "", wantOutput: nil, wantErr: hex.ErrEmptyString, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := hex.ToBytes(tt.input) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.wantOutput, bytes.Bytes(got)) } }) } } func TestMustFromHex(t *testing.T) { t.Parallel() tests := []struct { name string input string expected []byte shouldPanic bool }{ { name: "Valid hex string", input: "0x68656c6c6f", expected: bytes.Bytes("hello"), shouldPanic: false, }, { name: "Another valid hex string", input: "0x776f726c64", expected: bytes.Bytes("world"), shouldPanic: false, }, { name: "Empty hex string", input: "0x", expected: bytes.Bytes{}, shouldPanic: false, }, { name: "Invalid hex string", input: "0x12345", expected: nil, shouldPanic: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var ( res []byte f = func() { res = hex.MustToBytes(tt.input) } ) if tt.shouldPanic { require.Panics(t, f) } else { require.NotPanics(t, f) require.Equal(t, tt.expected, res) } }) } } func TestBytesUnmarshalJSONText(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expectErr bool }{ { name: "Valid JSON text", input: []byte(`"0x48656c6c6f"`), expectErr: false, }, { name: "Invalid JSON text", input: []byte(`"invalid"`), expectErr: true, }, { name: "Invalid quoted JSON text", input: []byte(`"0x`), expectErr: true, }, { name: "Empty JSON text", input: []byte(`""`), expectErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() b := &bytes.Bytes{} err := b.UnmarshalJSON(tt.input) if tt.expectErr { require.Error(t, err) } else { require.NoError(t, err) } }) } } func TestReverseEndianness(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expected []byte }{ {name: "Even length", input: []byte{1, 2, 3, 4}, expected: []byte{4, 3, 2, 1}}, {name: "Odd length", input: []byte{1, 2, 3, 4, 5}, expected: []byte{5, 4, 3, 2, 1}}, {name: "Empty slice", input: []byte{}, expected: []byte{}}, {name: "Single element", input: []byte{1}, expected: []byte{1}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := bytes.CopyAndReverseEndianess(tt.input) require.Equal(t, tt.expected, result) }) } } func TestHashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.B32 want bytes.B32 }{ { name: "Non-empty input", input: bytes.B32{1, 2, 3}, want: [32]byte{1, 2, 3}, }, { name: "Empty input", input: bytes.B32{}, want: [32]byte{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.input.HashTreeRoot() require.Equal(t, tt.want, result) }) } } func TestUnmarshalFixedJSON(t *testing.T) { t.Parallel() tests := []struct { name string typ reflect.Type input []byte out []byte expected []byte wantErr bool }{ { name: "Valid input", typ: reflect.TypeOf([4]byte{}), input: []byte(`"0x01020304"`), out: make([]byte, 4), expected: []byte{0x01, 0x02, 0x03, 0x04}, wantErr: false, }, { name: "Invalid input - not hex", typ: reflect.TypeOf([4]byte{}), input: []byte(`"01020304"`), out: make([]byte, 4), expected: nil, wantErr: true, }, { name: "Invalid input - wrong length", typ: reflect.TypeOf([4]byte{}), input: []byte(`"0x010203"`), out: make([]byte, 4), expected: nil, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := bytes.UnmarshalFixedJSON(tt.input, tt.out) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.expected, tt.out) } }) } } func TestUnmarshalFixedText(t *testing.T) { t.Parallel() tests := []struct { name string typename string input []byte out []byte expected []byte wantErr bool }{ { name: "Valid input", typename: "B4", input: []byte("0x01020304"), out: make([]byte, 4), expected: []byte{0x01, 0x02, 0x03, 0x04}, wantErr: false, }, { name: "Invalid input - not hex", typename: "B4", input: []byte("01020304"), out: make([]byte, 4), expected: nil, wantErr: true, }, { name: "Invalid input - wrong length", typename: "B4", input: []byte("0x010203"), out: make([]byte, 4), expected: nil, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := bytes.UnmarshalFixedText(tt.input, tt.out) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.expected, tt.out) } }) } } func TestBytes_String(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.Bytes expected string }{ { name: "Empty bytes", input: bytes.Bytes{}, expected: "0x", }, { name: "Single byte", input: bytes.Bytes{0x01}, expected: "0x01", }, { name: "Multiple bytes", input: bytes.Bytes{0x01, 0x02, 0x03, 0x04}, expected: "0x01020304", }, { name: "Bytes with leading zeros", input: bytes.Bytes{0x00, 0x00, 0x01, 0x02}, expected: "0x00000102", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.input.String() require.Equal(t, tt.expected, result) }) } } func TestBytes_MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input bytes.Bytes want string wantErr bool }{ { name: "Empty slice", input: bytes.Bytes{}, want: "0x", wantErr: false, }, { name: "Single byte", input: bytes.Bytes{0x01}, want: "0x01", wantErr: false, }, { name: "Multiple bytes", input: bytes.Bytes{0x01, 0x02, 0x03}, want: "0x010203", wantErr: false, }, { name: "Nil slice", input: nil, want: "0x", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := tt.input.MarshalText() if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.want, string(got)) } }) } } ================================================ FILE: primitives/bytes/buffer/buffer.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package buffer // initialBufferSize is the initial size of the internal buffer. const initialBufferSize = 64 // ReusableBuffer is a re-usable buffer for merkle tree hashing. Prevents // unnecessary allocations and garbage collection of byte slices. // // NOTE: this buffer is currently only safe for use in a single thread. type ReusableBuffer[RootT ~[32]byte] struct { internal []RootT } // NewReusableBuffer creates a new re-usable buffer for merkle tree hashing. func NewReusableBuffer[RootT ~[32]byte]() *ReusableBuffer[RootT] { return &ReusableBuffer[RootT]{ internal: make([]RootT, initialBufferSize), } } // Get returns a slice of the internal buffer of roots of the given size. func (b *ReusableBuffer[RootT]) Get(size int) []RootT { if delta := size - len(b.internal); delta > 0 { b.grow(delta) } return b.internal[:size] } // grow resizes the internal buffer by the requested delta. func (b *ReusableBuffer[RootT]) grow(delta int) { b.internal = append(b.internal, make([]RootT, delta)...) } // singleuseBuffer is a buffer for a single use case. Allocates new // memory for each use (call to `Get`). // // NOTE: this buffer is only used for testing. type SingleUseBuffer[RootT ~[32]byte] struct{} // NewSingleuseBuffer creates a new single-use buffer. func NewSingleuseBuffer[RootT ~[32]byte]() *SingleUseBuffer[RootT] { return &SingleUseBuffer[RootT]{} } // Get returns a new slice of roots the given size. func (b *SingleUseBuffer[RootT]) Get(size int) []RootT { return make([]RootT, size) } ================================================ FILE: primitives/bytes/buffer/buffer_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package buffer_test import ( "math/rand" "testing" "time" "github.com/berachain/beacon-kit/primitives/bytes/buffer" ) type bufferI interface { Get(size int) [][32]byte } // getBuffer returns a buffer of the given type. func getBuffer(usageType string) bufferI { switch usageType { case "reusable": return buffer.NewReusableBuffer[[32]byte]() case "singleuse": return buffer.NewSingleuseBuffer[[32]byte]() default: panic("unknown usage type: " + usageType) } } // Test getting a slice of the internal re-usable buffer and modifying. func TestReusableGet(t *testing.T) { t.Parallel() buffer := getBuffer("reusable") testCases := []struct { size int expected int }{ {size: 0, expected: 0}, {size: 1, expected: 1}, {size: 5, expected: 5}, {size: 16, expected: 16}, {size: 33, expected: 33}, {size: 17, expected: 17}, {size: 100, expected: 100}, } for i, tc := range testCases { result := buffer.Get(tc.size) if len(result) != tc.expected { t.Errorf( "Expected result size to be %d, got %d", tc.expected, len(result), ) } // Ensure modifications to the underlying buffer persist. if i >= 1 { if result[0][i-1] != byte(i-1) { t.Errorf( "Expected result[0][%d] to be %b, got %d", i-1, byte(i-1), result[0][i-1], ) } result[0] = [32]byte{} result[0][i] = byte(i) } } } // Test getting a slice of the internal single-use buffer and modifying. func TestSingleuseGet(t *testing.T) { t.Parallel() buffer := getBuffer("singleuse") testCases := []struct { size int expected int }{ {size: 0, expected: 0}, {size: 1, expected: 1}, {size: 5, expected: 5}, {size: 16, expected: 16}, {size: 33, expected: 33}, {size: 17, expected: 17}, {size: 100, expected: 100}, } for i, tc := range testCases { result := buffer.Get(tc.size) if len(result) != tc.expected { t.Errorf( "Expected result size to be %d, got %d", tc.expected, len(result), ) } // Ensure modifications to the underlying buffer do not persist. if i >= 1 { if result[0][i-1] != byte(0) { t.Errorf( "Expected result[0][%d] to be %b, got %d", i-1, byte(0), result[0][i-1], ) } result[0] = [32]byte{} result[0][i] = byte(i) } } } // Benchmark for the Get method on the re-usable buffer // // goos: darwin // goarch: arm64 // pkg: github.com/berachain/beacon-kit/primitives/merkle // BenchmarkReusableGet-12 158002471 7.439 ns/op 0 B/op 0 allocs/op. func BenchmarkReusableGet(b *testing.B) { buffer := getBuffer("reusable") r := rand.New(rand.NewSource(time.Now().UnixNano())) b.ResetTimer() for range b.N { size := r.Intn(100) + 1 result := buffer.Get(size) // Perform some operation on the result to avoid compiler optimizations. result[0] = [32]byte{} index := r.Intn(32) result[0][index] = byte(index) } } // Benchmark for the Get method on the single-use buffer // // goos: darwin // goarch: arm64 // pkg: github.com/berachain/beacon-kit/primitives/merkle // BenchmarkSingleuseGet-12 5388972 215.0 ns/op 1700 B/op 1 allocs/op. func BenchmarkSingleuseGet(b *testing.B) { buffer := getBuffer("singleuse") r := rand.New(rand.NewSource(time.Now().UnixNano())) b.ResetTimer() for range b.N { size := r.Intn(100) + 1 result := buffer.Get(size) // Perform some operation on the result to avoid compiler optimizations. result[0] = [32]byte{} index := r.Intn(32) result[0][index] = byte(index) } } ================================================ FILE: primitives/bytes/utils.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package bytes import ( "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/encoding/hex" ) var ErrIncorrectLength = errors.New("incorrect length") // ------------------------------ Helpers ------------------------------ // Helper function to unmarshal JSON for various byte types. func UnmarshalJSONHelper(target []byte, input []byte) error { bz := Bytes{} if err := bz.UnmarshalJSON(input); err != nil { return err } if len(bz) != len(target) { return ErrIncorrectLength } copy(target, bz) return nil } // UnmarshalTextHelper function to unmarshal text for various byte types. func UnmarshalTextHelper(target []byte, text []byte) error { bz := Bytes{} if err := bz.UnmarshalText(text); err != nil { return err } if len(bz) != len(target) { return ErrIncorrectLength } copy(target, bz) return nil } // CopyAndReverseEndianess will copy the input byte slice and return the // flipped version of it. func CopyAndReverseEndianess(input []byte) []byte { copied := make([]byte, len(input)) copy(copied, input) for i, j := 0, len(copied)-1; i < j; i, j = i+1, j-1 { copied[i], copied[j] = copied[j], copied[i] } return copied } // ExtendToSize extends a byte slice to a specified length. It returns the // original slice if it's already larger. func ExtendToSize(slice []byte, length int) []byte { if len(slice) >= length { return slice } return append(slice, make([]byte, length-len(slice))...) } // UnmarshalFixedJSON decodes the input as a string with 0x prefix. The length // of out determines the required input length. This function is commonly used // to implement the UnmarshalJSON method for fixed-size types. func UnmarshalFixedJSON(input, out []byte) error { return hex.DecodeFixedJSON(input, out) } // UnmarshalFixedText decodes the input as a string with 0x prefix. The length // of out determines the required input length. This function is commonly used // to implement the UnmarshalText method for fixed-size types. func UnmarshalFixedText(input, out []byte) error { return hex.DecodeFixedText(input, out) } ================================================ FILE: primitives/common/consensus.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package common import ( stdbytes "bytes" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/encoding/json" ) /* -------------------------------------------------------------------------- */ /* Root */ /* -------------------------------------------------------------------------- */ type ( // Bytes32 defines the commonly used 32-byte array. Bytes32 = bytes.B32 // Domain as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types Domain = bytes.B32 // DomainType as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types DomainType = bytes.B4 // Hash32 as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types Hash32 = bytes.B32 // Version as per the Ethereum 2.0 specification. // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types Version = bytes.B4 // ForkDigest as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types ForkDigest = bytes.B4 ) // Root represents a 32-byte Merkle root. // We use this type to represent roots that come from the consensus layer. type Root [RootSize]byte const RootSize = 32 // NewRootFromHex creates a new root from a hex string. // // Errors if: // - input is not prefixed with "0x". // - input is not valid hex of 32 bytes. func NewRootFromHex(input string) (Root, error) { val, err := hex.ToBytes(input) if err != nil { return Root{}, err } if len(val) != RootSize { return Root{}, bytes.ErrIncorrectLength } return Root(val), nil } // NewRootFromBytes creates a new root from a byte slice. func NewRootFromBytes(input []byte) Root { var root Root copy(root[:], input) return root } // Equals returns true if the two roots are equal. func (r Root) Equals(other Root) bool { return stdbytes.Equal(r[:], other[:]) } // Hex converts a root to a hex string. func (r Root) Hex() string { return hex.EncodeBytes(r[:]) } // String implements the stringer interface and is used also by the logger when // doing full logging into a file. func (r Root) String() string { return r.Hex() } // MarshalText returns the hex representation of r. func (r Root) MarshalText() ([]byte, error) { return []byte(r.Hex()), nil } // UnmarshalText parses a root in hex syntax. func (r *Root) UnmarshalText(input []byte) error { var err error *r, err = NewRootFromHex(string(input)) return err } // MarshalJSON returns the JSON representation of r. func (r Root) MarshalJSON() ([]byte, error) { return json.Marshal(r.Hex()) } // UnmarshalJSON parses a root in hex syntax. // // NOTE: Enforces the input to include any extra character in the first and last position. // Technically this is used to remove the quote `"`. For example, the input may look like: // []byte(`"0x6969696969696969696969696969696969696969696969696969696969696969"`) func (r *Root) UnmarshalJSON(input []byte) error { if len(input) <= 1 { return errors.Wrapf( bytes.ErrIncorrectLength, "input length (%d) is too small", len(input), ) } return r.UnmarshalText(input[1 : len(input)-1]) } ================================================ FILE: primitives/common/consensus_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package common_test import ( "strings" "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/stretchr/testify/require" ) func TestNewRootFromHex(t *testing.T) { t.Parallel() tests := []struct { name string input func() string expectedErr error }{ { name: "EmptyString", input: func() string { return "" }, expectedErr: hex.ErrEmptyString, }, { name: "ShortSize", input: func() string { return hex.Prefix + strings.Repeat("f", 2*common.RootSize-2) }, expectedErr: bytes.ErrIncorrectLength, }, { name: "RightSize", input: func() string { return hex.Prefix + strings.Repeat("f", 2*common.RootSize) }, expectedErr: nil, }, { name: "LongSize", input: func() string { return hex.Prefix + strings.Repeat("f", 2*common.RootSize+2) }, expectedErr: bytes.ErrIncorrectLength, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var err error f := func() { input := tt.input() _, err = common.NewRootFromHex(input) } require.NotPanics(t, f) if tt.expectedErr != nil { require.ErrorIs(t, err, tt.expectedErr) } else { require.NoError(t, err) } }) } } func TestRoot_UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expectedErr error }{ { name: "nil input", input: nil, expectedErr: bytes.ErrIncorrectLength, }, { name: "empty input", input: []byte(``), expectedErr: bytes.ErrIncorrectLength, }, { name: "short input of 1 byte", input: []byte{0x01}, expectedErr: bytes.ErrIncorrectLength, }, { name: "short input of just quotes", input: []byte(`""`), expectedErr: hex.ErrEmptyString, }, { name: "valid input", input: []byte(`"0x6969696969696969696969696969696969696969696969696969696969696969"`), expectedErr: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var ( r common.Root err error input = tt.input ) f := func() { err = r.UnmarshalJSON(input) } require.NotPanics(t, f) if tt.expectedErr != nil { require.ErrorContains(t, err, tt.expectedErr.Error()) } else { require.NoError(t, err) } }) } } ================================================ FILE: primitives/common/execution.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package common import ( stdbytes "bytes" "encoding" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/encoding/json" "golang.org/x/crypto/sha3" ) var ( _ encoding.TextMarshaler = (*ExecutionHash)(nil) _ encoding.TextUnmarshaler = (*ExecutionHash)(nil) _ json.Marshaler = (*ExecutionHash)(nil) _ json.Unmarshaler = (*ExecutionHash)(nil) _ encoding.TextMarshaler = (*ExecutionAddress)(nil) _ encoding.TextUnmarshaler = (*ExecutionAddress)(nil) _ json.Marshaler = (*ExecutionAddress)(nil) _ json.Unmarshaler = (*ExecutionAddress)(nil) ) /* -------------------------------------------------------------------------- */ /* ExecutionHash */ /* -------------------------------------------------------------------------- */ // ExecutionHash represents the 32 byte Keccak256 hash of arbitrary data. // We use this type to represent hashes of things that come from the execution // layer. type ExecutionHash [32]byte // NewExecutionHashFromHex creates a new hash from a hex string. func NewExecutionHashFromHex(input string) ExecutionHash { return ExecutionHash(hex.MustToBytes(input)) } // Hex converts a hash to a hex string. func (h ExecutionHash) Hex() string { return hex.EncodeBytes(h[:]) } // String implements the stringer interface and is used also by the logger when // doing full logging into a file. func (h ExecutionHash) String() string { return h.Hex() } // MarshalText returns the hex representation of h. func (h ExecutionHash) MarshalText() ([]byte, error) { return []byte(hex.EncodeBytes(h[:])), nil } // UnmarshalText parses a hash in hex syntax. // // Errors if: // - input is not "0x" prefixed. // - input length is not 66. func (h *ExecutionHash) UnmarshalText(input []byte) error { return hex.DecodeFixedText(input, h[:]) } // MarshalJSON returns the JSON representation of h. func (h ExecutionHash) MarshalJSON() ([]byte, error) { return json.Marshal(h.Hex()) } // UnmarshalJSON parses a hash in hex syntax. // // NOTE: Enforces the input to include the `"` characters in first and last position. // For example, the input may look like: // []byte(`"0x6969696969696969696969696969696969696969696969696969696969696969"`) func (h *ExecutionHash) UnmarshalJSON(input []byte) error { return hex.DecodeFixedJSON(input, h[:]) } /* -------------------------------------------------------------------------- */ /* ExecutionAddress */ /* -------------------------------------------------------------------------- */ // ExecutionAddress represents a 20-byte Ethereum address. // We use this type to represent addresses that come from the execution layer. // It is EIP-55 checksummed and compliant. type ExecutionAddress [20]byte // NewExecutionAddressFromHex creates a new address from a hex string. func NewExecutionAddressFromHex(input string) (ExecutionAddress, error) { bz, err := hex.ToBytes(input) if err != nil { return ExecutionAddress{}, err } return ExecutionAddress(bz), nil } // MustNewExecutionAddressFromHex creates a new address from a hex string, // panicking if the input is not a valid hex string. func MustNewExecutionAddressFromHex(input string) ExecutionAddress { return ExecutionAddress(hex.MustToBytes(input)) } // Equals returns true if the two addresses are the same. func (a ExecutionAddress) Equals(other ExecutionAddress) bool { return stdbytes.Equal(a[:], other[:]) } // Hex converts an address to a hex string. func (a ExecutionAddress) Hex() string { return string(a.checksumHex()) } // String implements the stringer interface and is used also by the logger when // doing full logging into a file. func (a ExecutionAddress) String() string { return a.Hex() } // MarshalText returns the hex representation of a. func (a ExecutionAddress) MarshalText() ([]byte, error) { return []byte(a.Hex()), nil } // UnmarshalText parses an address in hex syntax. // // Errors if: // - input is not "0x" prefixed. // - input length is not 42. func (a *ExecutionAddress) UnmarshalText(input []byte) error { return hex.DecodeFixedText(input, a[:]) } // MarshalJSON returns the JSON representation of a. func (a ExecutionAddress) MarshalJSON() ([]byte, error) { return json.Marshal(a.Hex()) } // UnmarshalJSON parses an address in hex syntax. // // NOTE: Enforces the input to include any extra character in the first and last position. // Technically this is used to remove the quote `"`. For example, the input may look like: // []byte(`"0x6969696969696969696969696969696969696969"`) func (a *ExecutionAddress) UnmarshalJSON(input []byte) error { if len(input) <= 1 { return errors.Wrapf( bytes.ErrIncorrectLength, "input length (%d) is too small", len(input), ) } return a.UnmarshalText(input[1 : len(input)-1]) } // checksumHex returns the checksummed hex representation of a. func (a *ExecutionAddress) checksumHex() []byte { buf := []byte(hex.EncodeBytes(a[:])) // compute checksum sha := sha3.NewLegacyKeccak256() sha.Write(buf[2:]) hash := sha.Sum(nil) for i := 2; i < len(buf); i++ { //nolint:mnd // todo fix. hashByte := hash[(i-2)/2] if i%2 == 0 { hashByte >>= 4 } else { hashByte &= 0xf } if buf[i] > '9' && hashByte > 7 { buf[i] -= 32 } } return buf } ================================================ FILE: primitives/common/execution_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package common_test import ( "encoding/json" "testing" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/stretchr/testify/require" ) func TestExecutionAddressMarshalling(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expectedErr error }{ { name: "address too short", input: []byte("\"0xab\""), expectedErr: hex.ErrInvalidHexStringLength, }, { name: "address missing hex prefix", input: []byte("\"abc\""), expectedErr: hex.ErrMissingPrefix, }, { name: "address too long", input: []byte( "\"0x000102030405060708090a0b0c0d0e0f101112131415161718\"", ), expectedErr: hex.ErrInvalidHexStringLength, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var ( v common.ExecutionAddress err error ) require.NotPanics(t, func() { err = json.Unmarshal(tt.input, &v) }) require.ErrorIs(t, err, tt.expectedErr) }) } } func TestExecutionAddressUnmarshalJSON_Short(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expectedErr error }{ { name: "empty input", input: []byte(``), expectedErr: bytes.ErrIncorrectLength, }, { name: "nil input", input: nil, expectedErr: bytes.ErrIncorrectLength, }, { name: "short input of 1 byte", input: []byte{0x01}, expectedErr: bytes.ErrIncorrectLength, }, { name: "short input of just quotes", input: []byte(`""`), expectedErr: hex.ErrInvalidHexStringLength, }, { name: "valid input", input: []byte(`"0x6969696969696969696969696969696969696969"`), expectedErr: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var ( addr common.ExecutionAddress err error input = tt.input ) f := func() { err = addr.UnmarshalJSON(input) } require.NotPanics(t, f) if tt.expectedErr != nil { require.ErrorContains(t, err, tt.expectedErr.Error()) } else { require.NoError(t, err) } }) } } ================================================ FILE: primitives/common/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package common import ( "github.com/karalabe/ssz" ) // sszMarshaler is an interface for objects that can be marshaled to SSZ format. type sszMarshaler interface { // MarshalSSZ marshals the object into SSZ format. MarshalSSZ() ([]byte, error) } // SSZUnmarshaler is an interface for objects that can be unmarshaled from SSZ format. type SSZUnmarshaler interface { ssz.Object ValidateAfterDecodingSSZ() error // once unmarshalled we will check whether type syntax is correct } // SSZMarshallable is an interface that combines SSZMarshaler and SSZUnmarshaler. type SSZMarshallable interface { sszMarshaler SSZUnmarshaler } // SSZRootable is an interface for objects that can compute their hash tree root. type SSZRootable interface { // HashTreeRoot computes the hash tree root of the object. HashTreeRoot() Root } // SSZMarshallableRootable is an interface that combines // sszMarshaler, sszUnmarshaler, and SSZRootable. type SSZMarshallableRootable interface { SSZMarshallable SSZRootable } ================================================ FILE: primitives/common/unused_type.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package common import ( "github.com/berachain/beacon-kit/errors" "github.com/karalabe/ssz" ) // UnusedEnforcer is an interface that asserts that a type is unused. type UnusedEnforcer interface { EnforceUnused() error } // Compile-time assertions to ensure UnusedType implements necessary interfaces. var ( _ ssz.StaticObject = (*UnusedType)(nil) _ SSZMarshallableRootable = (*UnusedType)(nil) _ UnusedEnforcer = (*UnusedType)(nil) ) type UnusedType uint8 // SizeSSZ returns the SSZ encoded size in bytes for the UnusedType. func (ut *UnusedType) SizeSSZ(_ *ssz.Sizer) uint32 { return 1 } // DefineSSZ defines the SSZ encoding for the UnusedType object. func (ut *UnusedType) DefineSSZ(c *ssz.Codec) { ssz.DefineUint8(c, ut) } // MarshalSSZ marshals the UnusedType object to SSZ format. func (ut *UnusedType) MarshalSSZ() ([]byte, error) { buf := make([]byte, ssz.Size(ut)) return buf, ssz.EncodeToBytes(buf, ut) } func (ut *UnusedType) ValidateAfterDecodingSSZ() error { return ut.EnforceUnused() } // HashTreeRoot returns the hash tree root of the Deposits. func (ut *UnusedType) HashTreeRoot() Root { return ssz.HashSequential(ut) } // EnforceUnused return true if the UnusedType contains all zero values. // As long as this type remains unused and unvalidated by consensus, // we must enforce that it contains no data. func (ut *UnusedType) EnforceUnused() error { if *ut != UnusedType(0) { return errors.New("UnusedType must be unused") } return nil } func EnforceAllUnused(enforcers ...UnusedEnforcer) error { for _, enforcer := range enforcers { if err := enforcer.EnforceUnused(); err != nil { return err } } return nil } ================================================ FILE: primitives/common/unused_type_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package common_test import ( "testing" "github.com/berachain/beacon-kit/primitives/common" "github.com/karalabe/ssz" "github.com/stretchr/testify/require" ) // Verify that DecodeFromBytes produces the same UnusedType obj as the previous implementation // defined by *v = UnusedType(buf[0]) func TestDecodeUnusedTypeEquality(t *testing.T) { t.Parallel() tests := []struct { name string buf []byte wantErr bool }{ {name: "decode-unused-type-empty", buf: []byte{0x00}, wantErr: false}, {name: "decode-unused-type-one", buf: []byte{0x01}, wantErr: false}, {name: "decode-unused-type-max", buf: []byte{0xff}, wantErr: false}, {name: "decode-unused-type-too-long", buf: []byte{0xff, 0xff}, wantErr: true}, {name: "decode-unused-type-too-short", buf: []byte{}, wantErr: true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := new(common.UnusedType) if err := ssz.DecodeFromBytes(tt.buf, got); err != nil { if tt.wantErr { return } t.Errorf("DecodeFromBytes() error = %v", err) } want := common.UnusedType(tt.buf[0]) require.Equal(t, &want, got) }) } } // Verify that MarshalSSZ produces the same bytes as the previous implementation // defined by: // []byte{uint8(*ut)} func TestEncodeUnusedTypeEquality(t *testing.T) { t.Parallel() tests := []struct { name string ut common.UnusedType }{ {name: "encode-unused-type-empty", ut: common.UnusedType(0)}, {name: "encode-unused-type-one", ut: common.UnusedType(1)}, {name: "encode-unused-type-max", ut: ^common.UnusedType(0)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := tt.ut.MarshalSSZ() if err != nil { t.Errorf("MarshalSSZ() error = %v", err) return } want := []byte{uint8(tt.ut)} require.Equal(t, want, got) }) } } ================================================ FILE: primitives/constants/bls12_381.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package constants const ( // BLSSignatureLength defines the byte length of a BLS12-381 Signature. // It is 96 bytes as defined in the Ethereum 2.0 Specification. BLSSignatureLength = 96 // BLSPubkeyLength defines the byte length of a BLS12-381 public key. // As per the standard, it is set to 48 bytes. BLSPubkeyLength = 48 // BLSSecretKeyLength defines the byte length of a BLS12-381 secret key. // It is defined to be 32 bytes in length. BLSSecretKeyLength = 32 ) ================================================ FILE: primitives/constants/constants.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package constants const ( // RootLength the length of a HashTreeRoot in bytes. RootLength = 32 // SSZOffsetSize is the number of bytes that an SSZ Offset contains. SSZOffsetSize uint32 = 4 ) ================================================ FILE: primitives/constants/eip4844.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package constants const ( // BlobCommitmentVersion is the version of the blob commitment. // It is the Version byte for the point evaluation precompile as // defined in EIP-4844. // // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md BlobCommitmentVersion uint8 = 0x01 // MaxBlobCommitmentsPerBlock is the hardfork-independent fixed // theoretical limit same as TARGET_BLOB_GAS_PER_BLOCK (see EIP 4844). // // https://ethereum.github.io/consensus-specs/specs/deneb/beacon-chain/#execution MaxBlobCommitmentsPerBlock = 4096 // MaxBlobSidecarsPerBlock is the maximum number of blob sidecars that can // be included in a block. MaxBlobSidecarsPerBlock = 6 ) ================================================ FILE: primitives/constants/misc.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package constants import ( stdmath "math" "github.com/berachain/beacon-kit/primitives/math" ) // Genesis constants taken from: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#misc const ( // GenesisSlot represents the initial slot in the system. GenesisSlot math.Slot = 0 // GenesisEpoch represents the initial epoch in the system. GenesisEpoch math.Epoch = 0 // FarFutureEpoch represents a far future epoch value. FarFutureEpoch math.Epoch = stdmath.MaxUint64 ) // Electra constants taken from : // https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#misc const ( // FullExitRequestAmount is the request amount for a full exit request, i.e. when a validator // wants to withdraw its entire balance. FullExitRequestAmount math.Gwei = 0 ) // Berachain constants. const ( // FirstDepositIndex represents the index of the first deposit in the system, set at genesis. FirstDepositIndex uint64 = 0 ) // State list lengths. const ( // ValidatorsRegistryLimit is the maximum number of validators that can be registered. // https://github.com/ethereum/consensus-specs/blob/dev/presets/mainnet/phase0.yaml#L55 // 2**40 (= 1,099,511,627,776) validator spots. ValidatorsRegistryLimit = 1_099_511_627_776 // PendingPartialWithdrawalsLimit is the maximum number of pending partial withdrawals. // https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#state-list-lengths // 2**27 (= 134,217,728) pending partial withdrawals // If the limit is hit, any new partial withdrawal requests will be dropped. This is not likely to happen but // theoretically possible. PendingPartialWithdrawalsLimit = 134_217_728 ) ================================================ FILE: primitives/constants/operations_per_block.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package constants const ( MaxProposerSlashings = 16 MaxAttesterSlashings = 2 MaxAttestations = 128 MaxVoluntaryExits = 16 MaxBlsToExecutionChanges = 16 // MaxTxsPerPayload is the maximum number of transactions in a execution payload. MaxTxsPerPayload uint64 = 1048576 // MaxWithdrawalsPerPayload is the maximum number of withdrawals in a execution payload. MaxWithdrawalsPerPayload uint64 = 16 // MaxWithdrawalRequestsPerPayload is the maximum number of withdrawal requests in a execution // payload. MaxWithdrawalRequestsPerPayload = 16 // MaxConsolidationRequestsPerPayload is the maximum number of consolidation requests in a // execution payload. MaxConsolidationRequestsPerPayload = 2 // MaxDepositRequestsPerPayload is the maximum number of deposit requests in a execution payload. MaxDepositRequestsPerPayload = 8192 ) ================================================ FILE: primitives/constants/payload.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package constants const ( // LogsBloomLength the length of a LogsBloom in bytes. LogsBloomLength = 256 // ExtraDataLength is the length of the extra data in bytes. ExtraDataLength = 32 // DepositContractDepth is the depth of the deposit contract merkle tree. DepositContractDepth uint64 = 32 // MaxDeposits is the maximum number of deposits supported by the // deposit tree (2**32). This is different from the enforced // MaxDepositsPerBlock. MaxDeposits uint64 = 1 << DepositContractDepth // MaxBytesPerTx is the maximum number of bytes per transaction. MaxBytesPerTx uint64 = 1073741824 ) // Execution Layer Triggered Requests: // https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#execution-layer-triggered-requests const ( DepositRequestType = byte(0x00) WithdrawalRequestType = byte(0x01) ConsolidationRequestType = byte(0x02) ) // Withdrawals processing: // https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#withdrawals-processing const ( // MaxPendingPartialsPerWithdrawalsSweep is the maximum number of pending partial withdrawals // per sweep. MaxPendingPartialsPerWithdrawalsSweep = 8 ) ================================================ FILE: primitives/constants/validator.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package constants // Validator status strings. const ( ValidatorStatusPendingInitialized = "pending_initialized" ValidatorStatusPendingQueued = "pending_queued" ValidatorStatusActiveOngoing = "active_ongoing" ValidatorStatusActiveExiting = "active_exiting" ValidatorStatusActiveSlashed = "active_slashed" ValidatorStatusExitedUnslashed = "exited_unslashed" ValidatorStatusExitedSlashed = "exited_slashed" ValidatorStatusWithdrawalPossible = "withdrawal_possible" ValidatorStatusWithdrawalDone = "withdrawal_done" ) ================================================ FILE: primitives/constraints/ssz.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package constraints import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/karalabe/ssz" ) // SSZMarshaler is an interface for objects that can be // marshaled to SSZ format. type SSZMarshaler interface { // MarshalSSZ marshals the object into SSZ format. MarshalSSZ() ([]byte, error) } // SSZUnmarshaler is an interface for objects that can be unmarshaled from SSZ format. type SSZUnmarshaler interface { ssz.Object ValidateAfterDecodingSSZ() error // once unmarshalled we will check whether type syntax is correct } // SSZMarshallable is an interface that combines SSZMarshaler and SSZUnmarshaler. type SSZMarshallable interface { SSZMarshaler SSZUnmarshaler } // Versionable is a constraint that requires a type to have a GetForkVersion method. type Versionable interface { GetForkVersion() common.Version } // SSZVersionable is an interface that combines SSZMarshallable and Versionable. type SSZVersionedMarshallable interface { Versionable SSZMarshallable } // SSZRootable is an interface for objects that can compute their hash tree root. type SSZRootable interface { // HashTreeRoot computes the hash tree root of the object. HashTreeRoot() common.Root } // SSZMarshallableRootable is an interface that combines // sszMarshaler, sszUnmarshaler, and SSZRootable. type SSZMarshallableRootable interface { SSZMarshallable SSZRootable } // SSZVersionedMarshallableRootable is an interface that combines // SSZVersionedMarshallable and SSZRootable. type SSZVersionedMarshallableRootable interface { SSZVersionedMarshallable SSZRootable } ================================================ FILE: primitives/crypto/bls.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package crypto import ( "fmt" "github.com/berachain/beacon-kit/primitives/bytes" cometencoding "github.com/cometbft/cometbft/crypto/encoding" ) // CometBLSType is the BLS curve type used in the Comet BFT consensus // algorithm. const CometBLSType = "bls12_381" type ( // BLSPubkey as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types BLSPubkey = bytes.B48 // BLSSignature as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types BLSSignature = bytes.B96 ) func GetAddressFromPubKey(pubKey BLSPubkey) ([]byte, error) { pk, err := cometencoding.PubKeyFromTypeAndBytes(CometBLSType, pubKey[:]) if err != nil { return nil, fmt.Errorf("failed retrieving pubKey from bytes: %w", err) } return pk.Address(), nil } // BLSSigner defines an interface for cryptographic signing operations. // It uses generic type parameters Signature and Pubkey, both of which are // slices of bytes. type BLSSigner interface { // PublicKey returns the public key of the signer. PublicKey() BLSPubkey // Sign takes a message as a slice of bytes and returns a signature as a // slice of bytes and an error. Sign([]byte) (BLSSignature, error) // VerifySignature verifies a signature against a message and a public key. VerifySignature(pubKey BLSPubkey, msg []byte, signature BLSSignature) error } ================================================ FILE: primitives/crypto/mocks/bls_signer.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( crypto "github.com/berachain/beacon-kit/primitives/crypto" mock "github.com/stretchr/testify/mock" ) // Blssigner is an autogenerated mock type for the BLSSigner type type Blssigner struct { mock.Mock } type Blssigner_Expecter struct { mock *mock.Mock } func (_m *Blssigner) EXPECT() *Blssigner_Expecter { return &Blssigner_Expecter{mock: &_m.Mock} } // PublicKey provides a mock function with no fields func (_m *Blssigner) PublicKey() crypto.BLSPubkey { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for PublicKey") } var r0 crypto.BLSPubkey if rf, ok := ret.Get(0).(func() crypto.BLSPubkey); ok { r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(crypto.BLSPubkey) } } return r0 } // Blssigner_PublicKey_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'PublicKey' type Blssigner_PublicKey_Call struct { *mock.Call } // PublicKey is a helper method to define mock.On call func (_e *Blssigner_Expecter) PublicKey() *Blssigner_PublicKey_Call { return &Blssigner_PublicKey_Call{Call: _e.mock.On("PublicKey")} } func (_c *Blssigner_PublicKey_Call) Run(run func()) *Blssigner_PublicKey_Call { _c.Call.Run(func(args mock.Arguments) { run() }) return _c } func (_c *Blssigner_PublicKey_Call) Return(_a0 crypto.BLSPubkey) *Blssigner_PublicKey_Call { _c.Call.Return(_a0) return _c } func (_c *Blssigner_PublicKey_Call) RunAndReturn(run func() crypto.BLSPubkey) *Blssigner_PublicKey_Call { _c.Call.Return(run) return _c } // Sign provides a mock function with given fields: _a0 func (_m *Blssigner) Sign(_a0 []byte) (crypto.BLSSignature, error) { ret := _m.Called(_a0) if len(ret) == 0 { panic("no return value specified for Sign") } var r0 crypto.BLSSignature var r1 error if rf, ok := ret.Get(0).(func([]byte) (crypto.BLSSignature, error)); ok { return rf(_a0) } if rf, ok := ret.Get(0).(func([]byte) crypto.BLSSignature); ok { r0 = rf(_a0) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(crypto.BLSSignature) } } if rf, ok := ret.Get(1).(func([]byte) error); ok { r1 = rf(_a0) } else { r1 = ret.Error(1) } return r0, r1 } // Blssigner_Sign_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Sign' type Blssigner_Sign_Call struct { *mock.Call } // Sign is a helper method to define mock.On call // - _a0 []byte func (_e *Blssigner_Expecter) Sign(_a0 interface{}) *Blssigner_Sign_Call { return &Blssigner_Sign_Call{Call: _e.mock.On("Sign", _a0)} } func (_c *Blssigner_Sign_Call) Run(run func(_a0 []byte)) *Blssigner_Sign_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].([]byte)) }) return _c } func (_c *Blssigner_Sign_Call) Return(_a0 crypto.BLSSignature, _a1 error) *Blssigner_Sign_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *Blssigner_Sign_Call) RunAndReturn(run func([]byte) (crypto.BLSSignature, error)) *Blssigner_Sign_Call { _c.Call.Return(run) return _c } // VerifySignature provides a mock function with given fields: pubKey, msg, signature func (_m *Blssigner) VerifySignature(pubKey crypto.BLSPubkey, msg []byte, signature crypto.BLSSignature) error { ret := _m.Called(pubKey, msg, signature) if len(ret) == 0 { panic("no return value specified for VerifySignature") } var r0 error if rf, ok := ret.Get(0).(func(crypto.BLSPubkey, []byte, crypto.BLSSignature) error); ok { r0 = rf(pubKey, msg, signature) } else { r0 = ret.Error(0) } return r0 } // Blssigner_VerifySignature_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VerifySignature' type Blssigner_VerifySignature_Call struct { *mock.Call } // VerifySignature is a helper method to define mock.On call // - pubKey crypto.BLSPubkey // - msg []byte // - signature crypto.BLSSignature func (_e *Blssigner_Expecter) VerifySignature(pubKey interface{}, msg interface{}, signature interface{}) *Blssigner_VerifySignature_Call { return &Blssigner_VerifySignature_Call{Call: _e.mock.On("VerifySignature", pubKey, msg, signature)} } func (_c *Blssigner_VerifySignature_Call) Run(run func(pubKey crypto.BLSPubkey, msg []byte, signature crypto.BLSSignature)) *Blssigner_VerifySignature_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(crypto.BLSPubkey), args[1].([]byte), args[2].(crypto.BLSSignature)) }) return _c } func (_c *Blssigner_VerifySignature_Call) Return(_a0 error) *Blssigner_VerifySignature_Call { _c.Call.Return(_a0) return _c } func (_c *Blssigner_VerifySignature_Call) RunAndReturn(run func(crypto.BLSPubkey, []byte, crypto.BLSSignature) error) *Blssigner_VerifySignature_Call { _c.Call.Return(run) return _c } // NewBlssigner creates a new instance of Blssigner. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewBlssigner(t interface { mock.TestingT Cleanup(func()) }) *Blssigner { mock := &Blssigner{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: primitives/crypto/sha256/sha256.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package sha256 import ( "hash" "sync" "github.com/minio/sha256-simd" ) // sha256Pool is a pool of sha256 hash functions. // //nolint:gochecknoglobals // needed for pool. var sha256Pool = sync.Pool{New: func() interface{} { return sha256.New() }} // Sha256 defines a function that returns the sha256 checksum of the data passed // in. Adheres to the crypto.HashFn signature. // https://github.com/ethereum/consensus-specs/blob/v0.9.3/specs/core/0_beacon-chain.md#hash func Hash(data []byte) [32]byte { h, ok := sha256Pool.Get().(hash.Hash) if !ok { h = sha256.New() } defer sha256Pool.Put(h) h.Reset() var b [32]byte //#nosec:G104 bet h.Write(data) h.Sum(b[:0]) return b } // CustomHashFn provides a hash function utilizing // an internal hasher. It is not thread-safe as the same // hasher instance is reused. // // Note: This method is more efficient only if the callback // is invoked more than 5 times. func CustomHashFn() func([]byte) [32]byte { hasher, ok := sha256Pool.Get().(hash.Hash) if !ok { hasher = sha256.New() } else { hasher.Reset() } var h [32]byte return func(data []byte) [32]byte { //#nosec:G104 // bet hasher.Write(data) hasher.Sum(h[:0]) hasher.Reset() return h } } ================================================ FILE: primitives/eip4844/blob.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip4844 import ( "github.com/berachain/beacon-kit/primitives/bytes" ) // Blob represents an EIP-4844 data blob. type Blob [131072]byte // UnmarshalJSON parses a blob in hex syntax. func (b *Blob) UnmarshalJSON(input []byte) error { return bytes.UnmarshalFixedJSON(input, b[:]) } // MarshalText returns the hex representation of b. func (b Blob) MarshalText() ([]byte, error) { return bytes.Bytes(b[:]).MarshalText() } ================================================ FILE: primitives/eip4844/blob_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip4844_test import ( "encoding/hex" "testing" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/stretchr/testify/require" ) func TestBlob_UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expected []byte wantErr bool }{ { name: "valid hex input", input: []byte( `"0x` + hex.EncodeToString(make([]byte, 131072)) + `"`, ), expected: []byte{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, }, wantErr: false, }, { name: "invalid hex input", input: []byte(`"invalidhex"`), wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var b eip4844.Blob err := b.UnmarshalJSON(tt.input) if tt.wantErr { require.Error(t, err, "Test case: %s", tt.name) } else { require.NoError(t, err, "Test case: %s", tt.name) require.Equal(t, tt.expected, b[:len(tt.expected)], "Test case: %s", tt.name) } }) } } func TestBlob_MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input eip4844.Blob expected string }{ { name: "valid blob", input: func() eip4844.Blob { var b eip4844.Blob copy( b[:], []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, ) return b }(), expected: func() string { var b eip4844.Blob copy( b[:], []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}, ) return "0x" + hex.EncodeToString(b[:]) }(), }, { name: "all zero bytes", input: func() eip4844.Blob { var b eip4844.Blob copy(b[:], make([]byte, len(b))) return b }(), expected: func() string { var b eip4844.Blob copy(b[:], make([]byte, len(b))) return "0x" + hex.EncodeToString(b[:]) }(), }, { name: "all max bytes", input: func() eip4844.Blob { var b eip4844.Blob for i := range b { b[i] = 0xFF } return b }(), expected: func() string { var b eip4844.Blob for i := range b { b[i] = 0xFF } return "0x" + hex.EncodeToString(b[:]) }(), }, { name: "mixed values", input: func() eip4844.Blob { var b eip4844.Blob copy( b[:], []byte{0x00, 0xFF, 0xAA, 0x55, 0x11, 0x22, 0x33, 0x44, 0x88, 0x99, 0x77, 0x66, 0xEE, 0xDD, 0xCC, 0xBB}, ) return b }(), expected: func() string { var b eip4844.Blob copy( b[:], []byte{0x00, 0xFF, 0xAA, 0x55, 0x11, 0x22, 0x33, 0x44, 0x88, 0x99, 0x77, 0x66, 0xEE, 0xDD, 0xCC, 0xBB}, ) return "0x" + hex.EncodeToString(b[:]) }(), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() output, err := tt.input.MarshalText() require.NoError(t, err, "Test case: %s", tt.name) require.Equal( t, tt.expected, string(output), "Test case: %s", tt.name, ) }) } } ================================================ FILE: primitives/eip4844/kzg_commitment.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip4844 import ( "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto/sha256" "github.com/prysmaticlabs/gohashtree" ) // KZGCommitment is a KZG commitment. type KZGCommitment [48]byte // ToVersionedHash converts this KZG commitment into a versioned hash // as per the Ethereum 2.0 specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/beacon-chain.md#kzg_commitment_to_versioned_hash func (c KZGCommitment) ToVersionedHash() [32]byte { sum := sha256.Hash(c[:]) // Prefix the hash with the BlobCommitmentVersion // to create a versioned hash. sum[0] = constants.BlobCommitmentVersion return sum } // ToHashChunks converts this KZG commitment into a set of hash chunks. func (c KZGCommitment) ToHashChunks() [][32]byte { chunks := make([][32]byte, 2) //nolint:mnd // 2 chunks. copy(chunks[0][:], c[:constants.RootLength]) copy(chunks[1][:], c[constants.RootLength:]) gohashtree.HashChunks(chunks, chunks) return chunks } // HashTreeRoot returns the hash tree root of the commitment. func (c KZGCommitment) HashTreeRoot() common.Root { chunks := c.ToHashChunks() return chunks[0] } // UnmarshalJSON parses a commitment in hex syntax. func (c *KZGCommitment) UnmarshalJSON(input []byte) error { return bytes.UnmarshalFixedJSON( input, c[:], ) } // MarshalText returns the hex representation of c. func (c KZGCommitment) MarshalText() ([]byte, error) { return bytes.Bytes(c[:]).MarshalText() } // KZGCommitments represents a slice of KZG commitments. type KZGCommitments[HashT ~[32]byte] []KZGCommitment // ToVersionedHashes converts the commitments to a set of // versioned hashes. It is simplify a convenience method // for converting a slice of commitments to a slice of // versioned hashes. func (c KZGCommitments[HashT]) ToVersionedHashes() []HashT { hashes := make([]HashT, len(c)) for i, bz := range c { hashes[i] = bz.ToVersionedHash() } return hashes } // Leafify converts the commitments to a slice of leaves. Each leaf is the // hash tree root of each commitment. func (c KZGCommitments[HashT]) Leafify() []common.Root { leaves := make([]common.Root, len(c)) for i, commitment := range c { leaves[i] = commitment.HashTreeRoot() } return leaves } ================================================ FILE: primitives/eip4844/kzg_commitment_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip4844_test import ( "encoding/hex" "testing" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/stretchr/testify/require" ) func TestKzgCommitmentToVersionedHash(t *testing.T) { t.Parallel() commitment := newTestCommitment("test commitment") expectedPrefix := constants.BlobCommitmentVersion hash := commitment.ToVersionedHash() require.Equal(t, expectedPrefix, hash[0], "First byte of hash should match BlobCommitmentVersion") require.Len(t, hash, 32, "Hash length should be 32 bytes") } func TestKzgCommitmentsToVersionedHashHashes(t *testing.T) { t.Parallel() commitments := []eip4844.KZGCommitment{ newTestCommitment("commitment 1"), newTestCommitment("commitment 2"), } hashes := eip4844.KZGCommitments[[32]byte](commitments).ToVersionedHashes() require.Len(t, hashes, len(commitments), "Number of hashes should match number of commitments") for i, hash := range hashes { require.Equal(t, constants.BlobCommitmentVersion, hash[0], "First byte of hash %d should match BlobCommitmentVersion", i) } } func TestKZGCommitmentToHashChunks(t *testing.T) { t.Parallel() tests := []struct { name string input eip4844.KZGCommitment expected int }{ {"Valid input", newTestCommitment("example commitment data that " + "exceeds root length to test chunking"), 2}, {"Short input", newTestCommitment("short"), 2}, {"Empty input", eip4844.KZGCommitment{}, 2}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() chunks := tt.input.ToHashChunks() require.Len(t, chunks, tt.expected, "Incorrect number of chunks for test: "+tt.name) }) } } func TestKZGCommitmentHashTreeRoot(t *testing.T) { t.Parallel() tests := []struct { name string input eip4844.KZGCommitment expected common.Root }{ {"Simple input", newTestCommitment("example commitment"), [32]byte{138, 20, 122, 217, 77, 116, 246, 111, 195, 118, 240, 67, 111, 145, 176, 117, 67, 82, 153, 245, 152, 25, 235, 239, 171, 54, 148, 169, 30, 169, 167, 229}}, {"Empty input", eip4844.KZGCommitment{}, [32]byte{245, 165, 253, 66, 209, 106, 32, 48, 39, 152, 239, 110, 211, 9, 151, 155, 67, 0, 61, 35, 32, 217, 240, 232, 234, 152, 49, 169, 39, 89, 251, 75}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() hashTreeRoot := tt.input.HashTreeRoot() require.Equal( t, tt.expected, hashTreeRoot, "Hash tree root does not "+ "match expected for test: "+tt.name, ) }) } } func TestKZGCommitmentUnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string input string expected eip4844.KZGCommitment shouldError bool }{ { name: "Valid hex input", input: `"0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789` + `abcdef0123456789abcdef0123456789abcdef"`, expected: func() eip4844.KZGCommitment { var c eip4844.KZGCommitment data, _ := hex.DecodeString( "0123456789abcdef0123456789abcdef0" + "123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", ) copy(c[:], data) return c }(), shouldError: false, }, { name: "Invalid hex input", input: `"0xG123456789abcdef"`, expected: eip4844.KZGCommitment{}, shouldError: true, }, { name: "Empty input", input: `""`, expected: eip4844.KZGCommitment{}, shouldError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var commitment eip4844.KZGCommitment err := commitment.UnmarshalJSON([]byte(tt.input)) if tt.shouldError { require.Error(t, err, "Expected an error for test: "+tt.name) } else { require.NoError(t, err) require.Equal(t, tt.expected, commitment, "Unmarshaled commitment does "+ "not match expected for test: "+tt.name) } }) } } func TestKZGCommitment_MarshalText(t *testing.T) { t.Parallel() testCases := []struct { name string input eip4844.KZGCommitment expected string }{ { name: "Empty Commitment", input: eip4844.KZGCommitment{}, expected: "3078303030303030303030303030303030303030303030303030303030" + "3030303030303030303030303030303030303030303030303030303030303030" + "3030303030303030303030303030303030303030303030303030303030303030" + "3030303030", }, { name: "Non-Empty Commitment", input: func() eip4844.KZGCommitment { var c eip4844.KZGCommitment for i := range c { c[i] = byte(i % 256) } return c }(), expected: "30783030303130323033303430353036303730383039306130623063306" + "43065306631303131313231333134313531363137313831393161316231633164" + "31653166323032313232323332343235323632373238323932613262326332643" + "2653266", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() output, err := tc.input.MarshalText() require.NoError(t, err) require.Equal(t, tc.expected, hex.EncodeToString(output), "Test case: %s", tc.name) }) } } func TestKZGCommitments_Leafify(t *testing.T) { t.Parallel() tests := []struct { name string input []eip4844.KZGCommitment }{ { name: "Single Commitment", input: []eip4844.KZGCommitment{ newTestCommitment("single commitment"), }, }, { name: "Multiple Commitments", input: []eip4844.KZGCommitment{ newTestCommitment("commitment one"), newTestCommitment("commitment two"), }, }, { name: "Empty Commitments", input: []eip4844.KZGCommitment{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() // Dynamically compute expected values based on input expected := make([]common.Root, len(tt.input)) for i, commitment := range tt.input { expected[i] = commitment.ToHashChunks()[0] } leaves := eip4844.KZGCommitments[common.Root](tt.input).Leafify() require.Equal(t, expected, leaves, "Leaves do not match expected for test: "+tt.name) }) } } func newTestCommitment(data string) eip4844.KZGCommitment { var c eip4844.KZGCommitment copy(c[:], data) return c } ================================================ FILE: primitives/eip4844/kzg_proof.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package eip4844 import ( "github.com/berachain/beacon-kit/primitives/bytes" ) // KZGProof represents a KZG proof, which is a 48-byte slice. type KZGProof = bytes.B48 ================================================ FILE: primitives/encoding/hex/bytes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex import ( "encoding/hex" "github.com/berachain/beacon-kit/errors" ) var ErrInvalidHexStringLength = errors.New("invalid hex string length") // EncodeBytes creates a hex string with 0x prefix. // Inverse operation is ToBytes or MustToBytes. func EncodeBytes(b []byte) string { hexStr := make([]byte, len(b)*2+prefixLen) copy(hexStr, Prefix) hex.Encode(hexStr[prefixLen:], b) return string(hexStr) } // MustToBytes returns the bytes represented by the given hex string. // It panics if the input is not a valid hex string. func MustToBytes(input string) []byte { bz, err := ToBytes(input) if err != nil { panic(err) } return bz } // ToBytes returns the bytes represented by the given hex string. // An error is returned if the input is not a valid hex string. func ToBytes(input string) ([]byte, error) { strippedInput, err := IsValidHex(input) if err != nil { return nil, err } return hex.DecodeString(strippedInput) } func UnmarshalByteText(input []byte) ([]byte, error) { raw, err := formatAndValidateText(input) if err != nil { return []byte{}, err } dec := make([]byte, len(raw)/encDecRatio) if _, err = hex.Decode(dec, raw); err != nil { return []byte{}, err } return dec, nil } // DecodeFixedJSON decodes the input as a string with 0x prefix. The length // of out determines the required input length. This function is commonly used // to implement the UnmarshalJSON method for fixed-size types. func DecodeFixedJSON(input, out []byte) error { strippedInput, err := ValidateQuotedString(input) if err != nil { return err } return DecodeFixedText(strippedInput, out) } // DecodeFixedText decodes the input as a string with 0x prefix. The length // of out determines the required input length. func DecodeFixedText(input, out []byte) error { raw, err := formatAndValidateText(input) if err != nil { return err } if len(raw)/encDecRatio != len(out) { return errors.Wrapf( ErrInvalidHexStringLength, "hex string has length %d, want %d", len(raw), len(out)*encDecRatio, ) } // Pre-verify syntax and decode in a single pass for i := 0; i < len(raw); i += 2 { highNibble := decodeNibble(raw[i]) lowNibble := decodeNibble(raw[i+1]) if highNibble == badNibble || lowNibble == badNibble { return ErrInvalidString } out[i/2] = byte((highNibble << nibbleShift) | lowNibble) // #nosec G115 -- nibbles are validated 0-15, combined result is 0-255. } return nil } ================================================ FILE: primitives/encoding/hex/bytes_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex_test import ( "strconv" "testing" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/stretchr/testify/require" ) func TestEncodeAndDecodeBytes(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expected string }{ { name: "typical byte slice", input: []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f}, expected: "0x48656c6c6f", }, { name: "empty byte slice", input: []byte{}, expected: "0x", }, { name: "single byte", input: []byte{0x01}, expected: "0x01", }, { name: "long byte slice", input: []byte{ 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0xba, 0xbe}, expected: "0xdeadbeefcafebabe" + "deadbeefcafebabe" + "deadbeefcafebabe" + "deadbeefcafebabe", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := hex.EncodeBytes(tt.input) require.Equal(t, tt.expected, result) _, err := hex.IsValidHex(result) require.NoError(t, err) decoded, err := hex.ToBytes(result) require.NoError(t, err) require.Equal(t, tt.input, decoded) require.NotPanics(t, func() { decoded = hex.MustToBytes(result) }) require.Equal(t, tt.input, decoded) }) } } func TestUnmarshalByteText(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expected []byte expectErr bool }{ { name: "valid hex string", input: []byte("0x48656c6c6f"), expected: []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f}, expectErr: false, }, { name: "empty hex string", input: []byte("0x"), expected: []byte{}, expectErr: false, }, { name: "invalid hex string", input: []byte("0xZZZZ"), expected: nil, expectErr: true, }, { name: "invalid format", input: []byte("invalid hex string"), expected: nil, expectErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := hex.UnmarshalByteText(tt.input) if tt.expectErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.expected, result) } }) } } func TestDecodeFixedText(t *testing.T) { t.Parallel() tests := []struct { name string typename string input []byte expected []byte expectErr bool }{ { name: "valid hex string", typename: "testType", input: []byte("0x48656c6c6f"), expected: []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f}, expectErr: false, }, { name: "invalid hex string length", typename: "testType", input: []byte("0x48656c6c"), expected: make([]byte, 5), expectErr: true, }, { name: "invalid hex characters", typename: "testType", input: []byte("0xZZZZZZZZZZ"), expected: make([]byte, 5), expectErr: true, }, { name: "hex.Decode error", typename: "testType", input: []byte("0x123"), // Invalid length for hex.Decode expected: make([]byte, 2), expectErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() out := make([]byte, len(tt.expected)) err := hex.DecodeFixedText(tt.input, out) if tt.expectErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, tt.expected, out) } }) } } func TestDecodeFixedJSON(t *testing.T) { t.Parallel() tests := []struct { name string typename string input []byte out []byte expectErr bool }{ { name: "valid hex string", typename: "testType", input: []byte(`"0x48656c6c6f"`), out: make([]byte, 5), expectErr: false, }, { name: "invalid hex string length", typename: "testType", input: []byte(`"0x48656c6c"`), out: make([]byte, 5), expectErr: true, }, { name: "invalid hex characters", typename: "testType", input: []byte(`"0xZZZZZZZZZZ"`), out: make([]byte, 5), expectErr: true, }, { name: "non-quoted string", typename: "testType", input: []byte(`0x48656c6c6f`), out: make([]byte, 5), expectErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := hex.DecodeFixedJSON( tt.input, tt.out, ) if tt.expectErr { require.Error(t, err) } else { require.NoError(t, err) require.Equal(t, []byte{0x48, 0x65, 0x6c, 0x6c, 0x6f}, tt.out) } }) } } func BenchmarkDecodeFixedText(b *testing.B) { sizes := []int{100, 1000, 10000} // Different input sizes for _, size := range sizes { benchName := "Size" + strconv.Itoa(size) b.Run(benchName, func(b *testing.B) { input := make( []byte, size*2+2, ) // Each byte is represented by 2 hex characters + "0x" prefix input[0] = '0' input[1] = 'x' for i := 2; i < len(input); i += 2 { input[i] = 'a' input[i+1] = 'f' } out := make( []byte, size, ) // Adjust the size based on the expected output length b.ResetTimer() for range b.N { err := hex.DecodeFixedText(input, out) if err != nil { b.Fatalf("DecodeFixedText failed: %v", err) } } }) } } ================================================ FILE: primitives/encoding/hex/const.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex const ( Prefix = "0x" prefixLen = len(Prefix) badNibble = ^uint64(0) hexBase = 16 initialCapacity = 10 encDecRatio = 2 nibblesPer64Bits = 16 // 64/4 nibblesPer256Bits = 64 // 256/4 nibbleShift = 4 // hexadecimal conversion constants. hexBaseOffset = '0' hexAlphaOffsetUpper = 'A' - 10 hexAlphaOffsetLower = 'a' - 10 ) ================================================ FILE: primitives/encoding/hex/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex import ( "errors" ) var ( ErrEmptyString = errors.New("empty hex string") ErrMissingPrefix = errors.New("hex string without 0x prefix") ErrOddLength = errors.New("hex string of odd length") ErrNonQuotedString = errors.New("non-quoted hex string") ErrInvalidString = errors.New("invalid hex string") ErrLeadingZero = errors.New("hex number with leading zero digits") ErrEmptyNumber = errors.New("hex string \"0x\"") ErrUint64Range = errors.New("hex number > 64 bits") ErrBig256Range = errors.New("hex number > 256 bits") ErrInvalidBigWordSize = errors.New("weird big.Word size") ) ================================================ FILE: primitives/encoding/hex/format.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex import ( "errors" "strings" ) // IsValidHex performs basic validations that every hex string // must pass (there may be extra ones depending on the type encoded) // It returns the suffix (dropping 0x prefix) in the hope to appease nilaway. func IsValidHex[T ~[]byte | ~string](s T) (T, error) { if len(s) == 0 { return *new(T), ErrEmptyString } if len(s) < prefixLen { return *new(T), ErrMissingPrefix } if strings.ToLower(string(s[:prefixLen])) != Prefix { return *new(T), ErrMissingPrefix } return s[prefixLen:], nil } // ValidateQuotedString errs if input has no quotes. // For convenience it returns the unstrip content if it does not err. func ValidateQuotedString(input []byte) ([]byte, error) { if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { return input[1 : len(input)-1], nil } return nil, ErrNonQuotedString } // formatAndValidateText validates the input text for a hex string. func formatAndValidateText(input []byte) ([]byte, error) { input, err := IsValidHex(input) if errors.Is(err, ErrEmptyString) { return nil, nil // empty strings are allowed } else if err != nil { return nil, err } if len(input)%2 != 0 { return nil, ErrOddLength } return input, nil } // formatAndValidateNumber checks the input text for a hex number. func formatAndValidateNumber[T []byte | string](input T) (T, error) { input, err := IsValidHex(input) if err != nil { return *new(T), err } if len(input) == 0 { return *new(T), ErrEmptyNumber } if len(input) > 1 && input[0] == '0' { return *new(T), ErrLeadingZero } return input, nil } ================================================ FILE: primitives/encoding/hex/format_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex_test import ( "testing" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/stretchr/testify/require" ) func TestIsValidHex(t *testing.T) { t.Parallel() tests := []struct { name string input string wantErr error }{ { name: "Valid hex string", input: "0x48656c6c6f", wantErr: nil, }, { name: "Empty string", input: "", wantErr: hex.ErrEmptyString, }, { name: "No 0x prefix", input: "48656c6c6f", wantErr: hex.ErrMissingPrefix, }, { name: "Valid single hex character", input: "0x0", wantErr: nil, }, { name: "Empty hex string", input: "0x", wantErr: nil, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() _, err := hex.IsValidHex(test.input) if test.wantErr != nil { require.ErrorIs(t, test.wantErr, err) } else { require.NoError(t, err) } }) } } ================================================ FILE: primitives/encoding/hex/nibble.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex // decodeNibble decodes a single hexadecimal nibble (half-byte) into uint64. func decodeNibble(in byte) uint64 { // uint64 conversion here is safe switch { case in >= '0' && in <= '9': //#nosec G701 // The resulting value will be in the range 0-9. return uint64(in - hexBaseOffset) case in >= 'A' && in <= 'F': //#nosec G701 // The resulting value will be in the range 10-15. return uint64(in - hexAlphaOffsetUpper) case in >= 'a' && in <= 'f': //#nosec G701 // The resulting value will be in the range 10-15. return uint64(in - hexAlphaOffsetLower) default: return badNibble } } ================================================ FILE: primitives/encoding/hex/u64.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex import ( "strconv" ) // This file contains functions for encoding and decoding uint64 values to and // from hexadecimal strings, and marshaling and unmarshaling uint64 values to // and from byte slices representing hexadecimal strings. // MarshalText returns a byte slice containing the hexadecimal representation // of uint64 input. func MarshalText(b uint64) ([]byte, error) { buf := make([]byte, prefixLen, initialCapacity) copy(buf, Prefix) buf = strconv.AppendUint(buf, b, hexBase) return buf, nil } // UnmarshalUint64Text parses a byte slice containing a hexadecimal string and // returns the uint64 value it represents. func UnmarshalUint64Text(input []byte) (uint64, error) { raw, err := formatAndValidateNumber(input) if err != nil { return 0, err } if len(raw) > nibblesPer64Bits { return 0, ErrUint64Range } var dec uint64 for _, byte := range raw { nib := decodeNibble(byte) if nib == badNibble { return dec, ErrInvalidString } dec *= hexBase // hex shift left :D dec += nib } return dec, nil } ================================================ FILE: primitives/encoding/hex/u64_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package hex_test import ( "testing" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/stretchr/testify/require" ) func TestMarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input uint64 expected []byte }{ {"Zero", 0, []byte("0x0")}, {"MaxByte", 255, []byte("0xff")}, {"Positive value", 12345, []byte("0x3039")}, {"MaxWord", 65535, []byte("0xffff")}, {"MaxDWord", 4294967295, []byte("0xffffffff")}, {"MaxQWord", 18446744073709551615, []byte("0xffffffffffffffff")}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result, err := hex.MarshalText(tt.input) require.NoError(t, err) require.Equal(t, tt.expected, result) decoded, err := hex.UnmarshalUint64Text(result) require.NoError(t, err) require.Equal(t, tt.input, decoded) }) } } func TestValidateQuotedString(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expected error }{ {"ValidQuotedString", []byte(`"0x0"`), nil}, {"ValidQuotedStringFF", []byte(`"0xff"`), nil}, {"NonQuotedString", []byte(`0xff`), hex.ErrNonQuotedString}, {"InvalidQuotedString", []byte(`"z`), hex.ErrNonQuotedString}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() _, err := hex.ValidateQuotedString(test.input) if test.expected != nil { require.ErrorIs(t, test.expected, err) } else { require.NoError(t, err) } }) } } func TestUnmarshalUint64Text(t *testing.T) { t.Parallel() tests := []struct { name string input []byte expected uint64 err error }{ {"Zero", []byte("0x0"), 0, nil}, {"MaxByte", []byte("0xff"), 255, nil}, {"MaxWord", []byte("0xffff"), 65535, nil}, {"MaxDWord", []byte("0xffffffff"), 4294967295, nil}, {"MaxQWord", []byte("0xffffffffffffffff"), 18446744073709551615, nil}, {"OutOfRange", []byte("0x10000000000000000"), 0, hex.ErrUint64Range}, {"InvalidString", []byte("0xzz"), 0, hex.ErrInvalidString}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { t.Parallel() result, err := hex.UnmarshalUint64Text(test.input) if test.err != nil { require.ErrorIs(t, test.err, err) } else { require.NoError(t, err) require.Equal(t, test.expected, result) } }) } } ================================================ FILE: primitives/encoding/json/json.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. // //nolint:gochecknoglobals // intentional aliases. package json import ( "encoding/json" ) // Marshaler is the interface implemented by types that // can marshal themselves into valid JSON. type Marshaler = json.Marshaler // Unmarshaler is the interface implemented by types // that can unmarshal a JSON description of themselves. type Unmarshaler = json.Unmarshaler var Marshal = json.Marshal var MarshalIndent = json.MarshalIndent var Unmarshal = json.Unmarshal // RawMessage is an alias for json.RawMessage, represensting a raw encoded JSON // value. It implements Marshaler and Unmarshaler and can be used to delay JSON // decoding or precompute a JSON encoding. type RawMessage = json.RawMessage ================================================ FILE: primitives/encoding/ssz/schema/common.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package schema const ( BoolSize = 1 U8Size = 1 U16Size = 2 U32Size = 4 U64Size = 8 U128Size = 16 U256Size = 32 B4Size = 4 B8Size = 8 B16Size = 16 B20Size = 20 B32Size = 32 B48Size = 48 B64Size = 64 B96Size = 96 B256Size = 256 ) // Basic SSZ types. // Bool returns an SSZType representing a boolean. func Bool() SSZType { return basic(BoolSize) } // U8 returns an SSZType representing an 8-bit unsigned integer. func U8() SSZType { return basic(U8Size) } // U16 returns an SSZType representing a 16-bit unsigned integer. func U16() SSZType { return basic(U16Size) } // U32 returns an SSZType representing a 32-bit unsigned integer. func U32() SSZType { return basic(U32Size) } // U64 returns an SSZType representing a 64-bit unsigned integer. func U64() SSZType { return basic(U64Size) } // U128 returns an SSZType representing a 128-bit unsigned integer. func U128() SSZType { return basic(U128Size) } // U256 returns an SSZType representing a 256-bit unsigned integer. func U256() SSZType { return basic(U256Size) } // B4 creates a DefineByteVector of 4 bytes (32 bits). func B4() SSZType { return DefineByteVector(B4Size) } // B8 creates a DefineByteVector of 8 bytes (64 bits). func B8() SSZType { return DefineByteVector(B8Size) } // B16 creates a DefineByteVector of 16 bytes (128 bits). func B16() SSZType { return DefineByteVector(B16Size) } // B20 creates a DefineByteVector of 20 bytes (160 bits). func B20() SSZType { return DefineByteVector(B20Size) } // B32 creates a DefineByteVector of 32 bytes (256 bits). func B32() SSZType { return DefineByteVector(B32Size) } // B48 creates a DefineByteVector of 48 bytes (384 bits). func B48() SSZType { return DefineByteVector(B48Size) } // B64 creates a DefineByteVector of 64 bytes (512 bits). func B64() SSZType { return DefineByteVector(B64Size) } // B96 creates a DefineByteVector of 96 bytes (768 bits). func B96() SSZType { return DefineByteVector(B96Size) } // B256 creates a Vector of 256 bytes (2048 bits). func B256() SSZType { return DefineByteVector(B256Size) } ================================================ FILE: primitives/encoding/ssz/schema/definitions.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package schema import ( "errors" "fmt" "github.com/berachain/beacon-kit/primitives/math" ) // BytesPerChunk is the number of bytes per chunk. const BytesPerChunk = 32 /* -------------------------------------------------------------------------- */ /* Basic */ /* -------------------------------------------------------------------------- */ // basic represents a basic SSZ type. type basic uint64 // ID returns the type ID of the basic type. func (b basic) ID() ID { return Basic } // ItemLength returns the size of the basic type in bytes. func (b basic) ItemLength() uint64 { return uint64(b) } // ItemPosition always returns an error for basic types, // as they have no children. func (b basic) ItemPosition(_ string) (uint64, uint8, uint8, error) { return 0, 0, 0, errors.New("basic type has no children") } // ElementType returns the basic type itself, as it has no children. func (b basic) ElementType(_ string) SSZType { return b } // HashChunkCount returns the number of 32-byte chunks // required to represent the basic type. func (b basic) HashChunkCount() uint64 { return 1 } /* -------------------------------------------------------------------------- */ /* Vector */ /* -------------------------------------------------------------------------- */ type vector struct { elementType SSZType length uint64 } func DefineVector(elementType SSZType, length uint64) SSZType { return vector{elementType: elementType, length: length} } func DefineByteVector(length uint64) SSZType { return DefineVector(U8(), length) } func (v vector) ID() ID { return Vector } func (v vector) ItemLength() uint64 { return BytesPerChunk } func (v vector) ItemPosition(p string) (uint64, uint8, uint8, error) { i, err := math.U64FromString(p) if err != nil { return 0, 0, 0, fmt.Errorf("expected index, got name %s", p) } start := i.Unwrap() * v.elementType.ItemLength() return start / BytesPerChunk, uint8(start % BytesPerChunk), // #nosec G115 -- can't overflow. uint8(start%BytesPerChunk + v.ItemLength()), // #nosec G115 -- can't overflow. nil } func (v vector) HashChunkCount() uint64 { totalBytes := v.Length() * v.elementType.ItemLength() chunks := (totalBytes + BytesPerChunk - 1) / BytesPerChunk return chunks } // Length describes the length for vector. func (v vector) Length() uint64 { return v.length } func (v vector) ElementType(_ string) SSZType { return v.elementType } /* -------------------------------------------------------------------------- */ /* List */ /* -------------------------------------------------------------------------- */ // List Type. type list struct { elementType SSZType limit uint64 } func DefineList(elementType SSZType, limit uint64) SSZType { return list{elementType: elementType, limit: limit} } func DefineByteList(limit uint64) SSZType { return DefineList(U8(), limit) } func (l list) ID() ID { return List } func (l list) ItemLength() uint64 { return l.elementType.ItemLength() } func (l list) HashChunkCount() uint64 { totalBytes := l.Length() * l.elementType.ItemLength() chunks := (totalBytes + BytesPerChunk - 1) / BytesPerChunk return chunks } func (l list) ElementType(_ string) SSZType { return l.elementType } // Length describes the limit for list. func (l list) Length() uint64 { return l.limit } // ItemPosition returns the chunk index and offset for a given list index. func (l list) ItemPosition(p string) (uint64, uint8, uint8, error) { i, err := math.U64FromString(p) if err != nil { return 0, 0, 0, fmt.Errorf("expected index, got name %s", p) } start := i.Unwrap() * l.elementType.ItemLength() return start / BytesPerChunk, uint8(start % BytesPerChunk), // #nosec G115 -- can't overflow. uint8(start%BytesPerChunk + l.ItemLength()), // #nosec G115 -- can't overflow. nil } /* -------------------------------------------------------------------------- */ /* Container */ /* -------------------------------------------------------------------------- */ type container struct { Fields []SSZType FieldIndex map[string]uint64 } func DefineContainer(fields ...*Field) SSZType { fieldIndex := make(map[string]uint64) types := make([]SSZType, len(fields)) for i, f := range fields { fieldIndex[f.GetName()] = uint64(i) // #nosec G115 -- todo fix. types[i] = f.GetValue() } return container{Fields: types, FieldIndex: fieldIndex} } func (c container) ID() ID { return Container } func (c container) ItemLength() uint64 { return BytesPerChunk } func (c container) ItemPosition(p string) (uint64, uint8, uint8, error) { pos, ok := c.FieldIndex[p] if !ok { return 0, 0, 0, fmt.Errorf("field %s not found", p) } // #nosec G115 -- can't overflow. return pos, 0, uint8(c.Fields[pos].ItemLength()), nil } func (c container) ElementType(p string) SSZType { return c.Fields[c.FieldIndex[p]] } func (c container) Length() uint64 { return uint64(len(c.Fields)) } func (c container) HashChunkCount() uint64 { return uint64(len(c.Fields)) } ================================================ FILE: primitives/encoding/ssz/schema/field.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package schema // Field represents a named value of a generic type. type Field struct { // name is the name of the field name string // value is the value of the field value SSZType } // NewField creates a new field. func NewField(name string, typ SSZType) *Field { return &Field{name: name, value: typ} } // GetName returns the name of the field. func (f Field) GetName() string { return f.name } // GetValue returns the value of the field. func (f Field) GetValue() SSZType { return f.value } ================================================ FILE: primitives/encoding/ssz/schema/id.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package schema type ID uint8 const ( Basic ID = iota Vector List Container ) // IsBasic returns true if the type is a basic type. func (t ID) IsBasic() bool { return t == Basic } // IsElements returns true if the type is an enumerable type. func (t ID) IsElements() bool { return t == Vector || t == List } // IsComposite returns true if the type is a composite type. func (t ID) IsComposite() bool { return t == Vector || t == List || t == Container } // IsEnumerable returns true if the type is an enumerable type. func (t ID) IsEnumerable() bool { return t == Vector || t == List } // IsList returns true if the type is a list type. func (t ID) IsList() bool { return t == List } // IsContainer returns true if the type is a container type. func (t ID) IsContainer() bool { return t == Container } /* -------------------------------------------------------------------------- */ /* Type Definitions */ /* -------------------------------------------------------------------------- */ // SSZType defines the interface that type definitions must adhere to. // An SSZType *REPRESENTS* an underlying type, but it is NOT an instance // of this type. type SSZType interface { // ID returns the type identifier for the SSZ type. ID() ID // ItemLength returns the length of an item in bytes for the SSZ type. ItemLength() uint64 // ItemPosition calculates the position of an item within the SSZ type. // It returns the generalized index, start offset, end offset, and any error // encountered. ItemPosition(p string) (uint64, uint8, uint8, error) // ElementType returns the SSZ type of the element at the given path. ElementType(p string) SSZType // HashChunkCount returns the number of 32-byte chunks required to represent // the SSZ type in a Merkle tree. HashChunkCount() uint64 } ================================================ FILE: primitives/encoding/ssz/utils.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package ssz import ( "fmt" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/karalabe/ssz" ) // Unmarshal is the way we build objects from byte formatted in SSZ encoding. // This function highlights the common template for SSZ decoding different objects. func Unmarshal[T constraints.SSZUnmarshaler](buf []byte, v T) error { if err := ssz.DecodeFromBytes(buf, v); err != nil { return fmt.Errorf("failed decoding %T: %w", v, err) } // Note: ValidateAfterDecodingSSZ may change v even if it returns error // (depending on the specific implementations) return v.ValidateAfterDecodingSSZ() } // MarshalItemsEIP7685 marshals a slice of items that satisfy SSZMarshaler according // to the EIP-7685 standard. It encodes each item individually and appends its bytes // to the output buffer. func MarshalItemsEIP7685[T constraints.SSZMarshaler](items []T) ([]byte, error) { var buf []byte for i, item := range items { itemBytes, err := item.MarshalSSZ() if err != nil { return nil, fmt.Errorf("failed to marshal item at index %d: %w", i, err) } buf = append(buf, itemBytes...) } return buf, nil } // UnmarshalItemsEIP7685 decodes a slice of items from the provided data according // to the EIP-7685 standard. It assumes that each item is encoded into a fixed number // of bytes (itemSize) and that newItem returns a new instance of the item. func UnmarshalItemsEIP7685[T constraints.SSZUnmarshaler]( data []byte, itemSize int, newItem func() T, ) ([]T, error) { if len(data)%itemSize != 0 { return nil, fmt.Errorf( "invalid data length: %d is not a multiple of item size %d", len(data), itemSize, ) } numItems := len(data) / itemSize items := make([]T, 0, numItems) for i := 0; i < len(data); i += itemSize { chunk := data[i : i+itemSize] item := newItem() if err := Unmarshal(chunk, item); err != nil { return nil, fmt.Errorf( "failed to unmarshal item at index %d: %w", i/itemSize, err, ) } items = append(items, item) } return items, nil } ================================================ FILE: primitives/math/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package math import ( "github.com/berachain/beacon-kit/errors" ) var ( // ErrUnexpectedInputLengthBase is the base error for unexpected input // length errors. ErrUnexpectedInputLengthBase = errors.New("unexpected input length") ) // ErrUnexpectedInputLength returns an error indicating that the input length. func ErrUnexpectedInputLength(expected uint32, actual int) error { return errors.Wrapf( ErrUnexpectedInputLengthBase, "expected %d, got %d", expected, actual, ) } ================================================ FILE: primitives/math/log/log.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package log import "math/bits" // ILog2Ceil returns the ceiling of the base 2 logarithm of the input. func ILog2Ceil[U64T ~uint64](u U64T) uint8 { // Log2(0) is undefined, should we panic? if u == 0 { return 0 } // #nosec G115 -- we handle the case of u == 0 above, so this is safe. return uint8(bits.Len64(uint64(u - 1))) } // ILog2Floor returns the floor of the base 2 logarithm of the input. func ILog2Floor[U64T ~uint64](u U64T) uint8 { // Log2(0) is undefined, should we panic? if u == 0 { return 0 } // #nosec G115 -- we handle the case of u == 0 above, so this is safe. return uint8(bits.Len64(uint64(u))) - 1 } ================================================ FILE: primitives/math/log/log_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package log_test import ( "testing" "github.com/berachain/beacon-kit/primitives/math/log" ) func TestILog2Ceil(t *testing.T) { t.Parallel() tests := []struct { input uint64 expected uint8 }{ {0, 0}, {1, 0}, {2, 1}, {3, 2}, {4, 2}, {5, 3}, {8, 3}, {9, 4}, {16, 4}, {17, 5}, } for _, test := range tests { result := log.ILog2Ceil(test.input) if result != test.expected { t.Errorf( "ILog2Ceil(%d) = %d; want %d", test.input, result, test.expected, ) } } } func TestILog2Floor(t *testing.T) { t.Parallel() tests := []struct { input uint64 expected uint8 }{ {0, 0}, {1, 0}, {2, 1}, {3, 1}, {4, 2}, {5, 2}, {8, 3}, {9, 3}, {16, 4}, {17, 4}, } for _, test := range tests { result := log.ILog2Floor(test.input) if result != test.expected { t.Errorf( "ILog2Floor(%d) = %d; want %d", test.input, result, test.expected, ) } } } ================================================ FILE: primitives/math/pow/pow.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package pow // PrevPowerOfTwo returns the previous power of 2 for the given input. // //nolint:mnd // todo fix. func PrevPowerOfTwo[U64T ~uint64](u U64T) U64T { if u <= 1 { return 1 } u |= u >> 1 u |= u >> 2 u |= u >> 4 u |= u >> 8 u |= u >> 16 u |= u >> 32 return u - (u >> 1) } // NextPowerOfTwo returns the next power of 2 for the given input. // //nolint:mnd // todo fix. func NextPowerOfTwo[U64T ~uint64](u U64T) U64T { if u <= 1 { return 1 } if u > 1<<63 { panic("Next power of 2 is 1 << 64.") } u-- u |= u >> 1 u |= u >> 2 u |= u >> 4 u |= u >> 8 u |= u >> 16 u |= u >> 32 u++ return u } ================================================ FILE: primitives/math/pow/pow_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package pow_test import ( "testing" "github.com/berachain/beacon-kit/primitives/math/pow" ) func TestPrevPowerOfTwo(t *testing.T) { t.Parallel() tests := []struct { input uint64 expected uint64 }{ {0, 1}, {1, 1}, {2, 2}, {3, 2}, {4, 4}, {5, 4}, {6, 4}, {7, 4}, {8, 8}, {9, 8}, {16, 16}, {17, 16}, {31, 16}, {32, 32}, {33, 32}, } for _, test := range tests { result := pow.PrevPowerOfTwo(test.input) if result != test.expected { t.Errorf( "PrevPowerOfTwo(%d) = %d; want %d", test.input, result, test.expected, ) } } } func TestNextPowerOfTwo(t *testing.T) { t.Parallel() tests := []struct { input uint64 expected uint64 }{ {0, 1}, {1, 1}, {2, 2}, {3, 4}, {4, 4}, {5, 8}, {6, 8}, {7, 8}, {8, 8}, {9, 16}, {16, 16}, {17, 32}, {31, 32}, {32, 32}, {33, 64}, } for _, test := range tests { result := pow.NextPowerOfTwo(test.input) if result != test.expected { t.Errorf( "NextPowerOfTwo(%d) = %d; want %d", test.input, result, test.expected, ) } } } ================================================ FILE: primitives/math/u256.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package math import ( "fmt" "math/big" "github.com/holiman/uint256" ) // U256 represents a 256-bit unsigned integer that is both SSZ and JSON. type U256 = uint256.Int // NewU256 creates a new U256 from a uint64. func NewU256(v uint64) *U256 { return uint256.NewInt(v) } // NewU256FromBigInt creates a new U256 from a big.Int. func NewU256FromBigInt(b *big.Int) (*U256, error) { // Negative integers ought to be rejected by math.NewU256FromBigInt(b) // since they cannot be expressed in the U256 type. However this does // not seem to happen (see holiman/uint256#115), so guarding here. if b.Sign() < 0 { return nil, fmt.Errorf( "cannot convert negative big.Int %s to uint256", b.String(), ) } return uint256.MustFromBig(b), nil } // U256Hex represents a 256-bit unsigned integer that is marshaled to JSON // as a hexadecimal string. type U256Hex uint256.Int // MarshalJSON implements the json.Marshaler interface. // It returns the hexadecimal string representation of the U256Hex value. func (u *U256Hex) MarshalJSON() ([]byte, error) { return []byte(`"` + (*uint256.Int)(u).Hex() + `"`), nil } // UnmarshalJSON implements the json.Unmarshaler interface. // It expects the input to be a hexadecimal string. func (u *U256Hex) UnmarshalJSON(data []byte) error { return (*uint256.Int)(u).UnmarshalJSON(data) } ================================================ FILE: primitives/math/u64.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package math import ( "encoding/binary" "math/big" "strconv" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/math/log" "github.com/berachain/beacon-kit/primitives/math/pow" "github.com/ethereum/go-ethereum/params" ) type ( // U64 represents a 64-bit unsigned integer that is both SSZ and JSON // marshallable. We marshal U64 as hex strings in JSON in order to keep the // execution client apis happy, and we marshal U64 as little-endian in SSZ // to be // compatible with the spec. U64 uint64 // Gwei is a denomination of 1e9 Wei represented as a U64. Gwei = U64 // Slot as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types Slot = U64 // CommitteeIndex as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types CommitteeIndex = U64 // ValidatorIndex as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types ValidatorIndex = U64 // Epoch as per the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#custom-types Epoch = U64 ) // -------------------------- JSONMarshallable ------------------------- // MarshalText implements encoding.TextMarshaler. func (u U64) MarshalText() ([]byte, error) { return hex.MarshalText(u.Unwrap()) } // UnmarshalJSON implements json.Unmarshaler. func (u *U64) UnmarshalJSON(input []byte) error { strippedInput, err := hex.ValidateQuotedString(input) if err != nil { return err } return u.UnmarshalText(strippedInput) } func U64FromString(id string) (U64, error) { u64, err := strconv.ParseUint(id, 10, 64) if err != nil { return 0, err } return U64(u64), nil } // ---------------------------------- Hex ---------------------------------- // UnmarshalText implements encoding.TextUnmarshaler. func (u *U64) UnmarshalText(input []byte) error { dec, err := hex.UnmarshalUint64Text(input) if err != nil { return err } *u = U64(dec) return nil } // String returns the string representation of the U64. func (u U64) Base10() string { return strconv.FormatUint(uint64(u), 10) } // ----------------------- U64 Mathematical Methods ----------------------- // Unwrap returns a copy of the underlying uint64 value of U64. func (u U64) Unwrap() uint64 { return uint64(u) } // UnwrapPtr returns a pointer to the underlying uint64 value of U64. func (u U64) UnwrapPtr() *uint64 { return (*uint64)(&u) } // Get the power of 2 for given input, or the closest higher power of 2 if the // input is not a power of 2. Commonly used for "how many nodes do I need for a // bottom tree layer fitting x elements?" // Example: 0->1, 1->1, 2->2, 3->4, 4->4, 5->8, 6->8, 7->8, 8->8, 9->16. // // https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md#helper-functions func (u U64) NextPowerOfTwo() U64 { return pow.NextPowerOfTwo(u) } // Get the power of 2 for given input, or the closest lower power of 2 if the // input is not a power of 2. The zero case is a placeholder and not used for // math with generalized indices. Commonly used for "what power of two makes up // the root bit of the generalized index?" // Example: 0->1, 1->1, 2->2, 3->2, 4->4, 5->4, 6->4, 7->4, 8->8, 9->8. // // https://github.com/ethereum/consensus-specs/blob/dev/ssz/merkle-proofs.md#helper-functions func (u U64) PrevPowerOfTwo() U64 { return pow.PrevPowerOfTwo(u) } // ILog2Ceil returns the ceiling of the base 2 logarithm of the U64. func (u U64) ILog2Ceil() uint8 { return log.ILog2Ceil(u) } // ILog2Floor returns the floor of the base 2 logarithm of the U64. func (u U64) ILog2Floor() uint8 { return log.ILog2Floor(u) } // -------------------------------- SSZ --------------------------------- // HashTreeRoot returns the hash tree root of the U64. func (u U64) HashTreeRoot() common.Root { var root common.Root binary.LittleEndian.PutUint64(root[:], u.Unwrap()) return root } // ---------------------------- Gwei Methods ---------------------------- var ErrGweiOverflow = errors.New("gwei from big.Int overflows") // GweiFromWei returns the value of Wei in Gwei. func GweiFromWei(i *big.Int) (Gwei, error) { intToGwei := big.NewInt(0).SetUint64(params.GWei) i.Div(i, intToGwei) if !i.IsUint64() { // a Gwei amount >= (2**64) * (10**9) or negative would not // be representable as uint64. This should not happen but // we still guard against a serialization bug or other mishap. return 0, ErrGweiOverflow } return Gwei(i.Uint64()), nil } // ToWei converts a value from Gwei to Wei. func (u Gwei) ToWei() *U256 { return (&U256{}).Mul(NewU256(uint64(u)), NewU256(params.GWei)) } ================================================ FILE: primitives/math/u64_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package math_test import ( "math/big" "testing" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/math" "github.com/ethereum/go-ethereum/params" "github.com/stretchr/testify/require" ) func TestU64_MarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input uint64 expected string }{ {"Zero value", 0, "0x0"}, {"Small value", 123, "0x7b"}, {"Max uint64 value", ^uint64(0), "0xffffffffffffffff"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() u := math.U64(tt.input) result, err := u.MarshalText() require.NoError(t, err) require.Equal(t, tt.expected, string(result)) }) } } func TestU64_UnmarshalJSON(t *testing.T) { t.Parallel() tests := []struct { name string json string expected uint64 err error }{ {"Valid hex string", "\"0x7b\"", 123, nil}, {"Zero value", "\"0x0\"", 0, nil}, {"Max uint64 value", "\"0xffffffffffffffff\"", ^uint64(0), nil}, {"Invalid hex string", "\"0xxyz\"", 0, hex.ErrInvalidString}, {"Invalid JSON text", "", 0, hex.ErrNonQuotedString}, {"Invalid quoted JSON text", `"0x`, 0, hex.ErrNonQuotedString}, {"Empty JSON text", `""`, 0, hex.ErrEmptyString}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var u math.U64 err := u.UnmarshalJSON([]byte(tt.json)) if tt.err != nil { require.Error(t, err) require.Equal(t, tt.err, err) } else { require.NoError(t, err) require.Equal(t, math.U64(tt.expected), u) } }) } } func TestU64_UnmarshalText(t *testing.T) { t.Parallel() tests := []struct { name string input string expected uint64 err error }{ {"Valid hex string", "0x7b", 123, nil}, {"Zero value", "0x0", 0, nil}, {"Max uint64 value", "0xffffffffffffffff", ^uint64(0), nil}, {"Invalid hex string", "0xxyz", 0, hex.ErrInvalidString}, {"Overflow hex string", "0x10000000000000000", 0, hex.ErrUint64Range}, {"Empty string", "", 0, hex.ErrEmptyString}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() var u math.U64 err := u.UnmarshalText([]byte(tt.input)) if tt.err != nil { require.Error(t, err) require.EqualError(t, err, tt.err.Error()) } else { require.NoError(t, err) require.Equal(t, math.U64(tt.expected), u) } }) } } func TestU64_NextPowerOfTwo(t *testing.T) { t.Parallel() tests := []struct { name string value math.U64 expected math.U64 }{ { name: "zero", value: math.U64(0), expected: math.U64(1), }, { name: "one", value: math.U64(1), expected: math.U64(1), }, { name: "already a power of two", value: math.U64(8), expected: math.U64(8), }, { name: "not a power of two", value: math.U64(9), expected: math.U64(16), }, { name: "large number", value: math.U64(1<<20 + 1<<46), expected: math.U64(1 << 47), }, { name: "large number with lots zeros", value: math.U64(1<<62 + 1), expected: math.U64(1 << 63), }, { name: "large number at the limit", value: math.U64(1 << 63), expected: math.U64(1 << 63), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.value.NextPowerOfTwo() require.Equal(t, tt.expected, result) require.Equal( t, tt.expected, math.U64(uint64(1)< 0 } // Sibling returns the sibling index of the current generalized index. func (g GeneralizedIndex) Sibling() GeneralizedIndex { return g ^ 1 } // LeftChild returns the left child index of the current generalized index. // //nolint:mnd // from spec. func (g GeneralizedIndex) LeftChild() GeneralizedIndex { return 2 * g } // RightChild returns the right child index of the current generalized index. func (g GeneralizedIndex) RightChild() GeneralizedIndex { return 2*g + 1 } // Parent returns the parent index of the current generalized index. // //nolint:mnd // from spec. func (g GeneralizedIndex) Parent() GeneralizedIndex { return g / 2 } // GetBranchIndices returns the generalized indices of the nodes on the path // from the root to the leaf. func (g GeneralizedIndex) GetBranchIndices() GeneralizedIndices { // Get the generalized indices of the sister chunks along the path from the // chunk with the given tree index to the root. o := GeneralizedIndices{g.Sibling()} for o[len(o)-1] > 1 { o = append(o, o[len(o)-1].Parent().Sibling()) } return o[:len(o)-1] } // GetPathIndices returns the generalized indices of the nodes on the path from // the leaf to the root. func (g GeneralizedIndex) GetPathIndices() GeneralizedIndices { // Get the generalized indices of the sister chunks along the path from the // chunk with the given tree index to the root. o := GeneralizedIndices{g} for o[len(o)-1] > 1 { o = append(o, o[len(o)-1].Parent()) } return o[:len(o)-1] } // Concat multiple generalized indices into a single generalized index // representing the path from the first to the last node. func (gs GeneralizedIndices) Concat() GeneralizedIndex { o := GeneralizedIndex(1) for _, i := range gs { floorPower := pow.PrevPowerOfTwo(i) o *= floorPower o += i - floorPower } return o } // GetHelperIndices returns the generalized indices of all "extra" chunks in the // tree needed to prove the chunks with the given generalized indices. The // decreasing order is chosen deliberately to ensure equivalence to the order of // hashes in a regular single-item Merkle proof in the single-item case. func (gs GeneralizedIndices) GetHelperIndices() GeneralizedIndices { allHelperIndices := make(map[GeneralizedIndex]struct{}) allPathIndices := make(map[GeneralizedIndex]struct{}) for _, index := range gs { for _, helperIndex := range index.GetBranchIndices() { allHelperIndices[helperIndex] = struct{}{} } for _, pathIndex := range index.GetPathIndices() { allPathIndices[pathIndex] = struct{}{} } } difference := make(GeneralizedIndices, 0, len(allHelperIndices)) for helperIndex := range allHelperIndices { if _, exists := allPathIndices[helperIndex]; !exists { difference = append(difference, helperIndex) } } // Sort in decreasing order. slices.SortFunc(difference, GeneralizedIndexReverseComparator) return difference } // Comparator function used to sort generalized indices in reverse order. func GeneralizedIndexReverseComparator(i, j GeneralizedIndex) int { switch { case i < j: return 1 case i == j: return 0 case i > j: return -1 default: panic("unreachable") } } ================================================ FILE: primitives/merkle/index_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "testing" "github.com/berachain/beacon-kit/primitives/merkle" "github.com/stretchr/testify/require" ) func TestNewGeneralizedIndex(t *testing.T) { t.Parallel() tests := []struct { depth uint8 index uint64 expect merkle.GeneralizedIndex }{ {depth: 0, index: 0, expect: 1}, {depth: 1, index: 1, expect: 3}, {depth: 2, index: 2, expect: 6}, {depth: 3, index: 5, expect: 13}, } for _, tt := range tests { result := merkle.NewGeneralizedIndex( tt.depth, tt.index, ) require.Equal( t, tt.expect, result, "Failed at depth %d and index %d", tt.depth, tt.index, ) } } func TestConcatGeneralizedIndices(t *testing.T) { t.Parallel() tests := []struct { indices merkle.GeneralizedIndices expect merkle.GeneralizedIndex }{ {indices: []merkle.GeneralizedIndex{1, 2, 3}, expect: 0x05}, {indices: []merkle.GeneralizedIndex{4, 5, 6}, expect: 0x46}, } for _, tt := range tests { result := tt.indices.Concat() require.Equal( t, tt.expect, result, "Failed with indices %v", tt.indices, ) } } func TestGeneralizedIndexMethods(t *testing.T) { t.Parallel() gi := merkle.GeneralizedIndex(12) // Example index require.Equal( t, 3, gi.Length(), "Incorrect length for GeneralizedIndex", ) require.True( t, gi.IndexBit(2), "IndexBit should return true for bit position 2", ) require.False( t, gi.IndexBit(1), "IndexBit should return false for bit position 1", ) require.Equal( t, merkle.GeneralizedIndex(13), gi.Sibling(), "Incorrect sibling index", ) require.Equal( t, merkle.GeneralizedIndex(24), gi.LeftChild(), "Incorrect right child index", ) require.Equal( t, merkle.GeneralizedIndex(25), gi.RightChild(), "Incorrect left child index", ) require.Equal( t, merkle.GeneralizedIndex(6), gi.Parent(), "Incorrect parent index", ) } func TestGetBranchIndices(t *testing.T) { t.Parallel() tests := []struct { name string index merkle.GeneralizedIndex expect merkle.GeneralizedIndices }{ {name: "Single Branch", index: 1, expect: []merkle.GeneralizedIndex{}}, {name: "Two Branches", index: 3, expect: []merkle.GeneralizedIndex{2}}, {name: "Multiple Branches", index: 5, expect: []merkle.GeneralizedIndex{4, 3}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.index.GetBranchIndices() require.Equal( t, tt.expect, result, "Failed for index %d", tt.index, ) }) } } func TestGetPathIndices(t *testing.T) { t.Parallel() tests := []struct { name string index merkle.GeneralizedIndex expect merkle.GeneralizedIndices }{ { name: "No Path", index: 1, expect: []merkle.GeneralizedIndex{}, }, {name: "Single Path", index: 3, expect: []merkle.GeneralizedIndex{3}}, { name: "Multiple Paths", index: 5, expect: []merkle.GeneralizedIndex{5, 2}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.index.GetPathIndices() require.Equal( t, tt.expect, result, "Failed for index %d", tt.index, ) }) } } func TestGetHelperIndices(t *testing.T) { t.Parallel() tests := []struct { name string indices merkle.GeneralizedIndices expect merkle.GeneralizedIndices }{ { name: "No Indices", indices: []merkle.GeneralizedIndex{}, expect: []merkle.GeneralizedIndex{}, }, { name: "Single Index", indices: []merkle.GeneralizedIndex{1}, expect: []merkle.GeneralizedIndex{}, }, { name: "Multiple Indices", indices: []merkle.GeneralizedIndex{3, 5}, expect: []merkle.GeneralizedIndex{4}, }, { name: "Overlapping Indices", indices: []merkle.GeneralizedIndex{3, 7}, expect: []merkle.GeneralizedIndex{6, 2}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() result := tt.indices.GetHelperIndices() require.Equal(t, tt.expect, result, "Failed for indices %v", tt.indices) }) } } ================================================ FILE: primitives/merkle/object_path.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( "errors" "strings" "github.com/berachain/beacon-kit/primitives/encoding/ssz/schema" "github.com/berachain/beacon-kit/primitives/math/pow" ) // ObjectPath represents a path to an object in a Merkle tree. type ObjectPath string // Split returns the path split by "/". func (p ObjectPath) Split() []string { return strings.Split(string(p), "/") } // GetGeneralizedIndex converts a path to a generalized index representing its // position in the Merkle tree. // // """ // // Converts a path (eg. `[7, "foo", 3]` for `x[7].foo[3]`, `[12, "bar", // "__len__"]` for `len(x[12].bar)`) into the generalized index representing its // position in the Merkle tree. // """ // root = GeneralizedIndex(1) // for p in path: // // assert not issubclass(typ, BasicValue) # If we descend to a basic type, the // // path cannot continue further // // if p == '__len__': // typ = uint64 // assert issubclass(typ, (List, ByteList)) // root = GeneralizedIndex(root * 2 + 1) // else: // pos, _, _ = get_item_position(typ, p) // base_index = (GeneralizedIndex(2) if issubclass(typ, (List, ByteList)) else // // GeneralizedIndex(1)) root = GeneralizedIndex(root * base_index * // get_power_of_two_ceil(chunk_count(typ)) + pos) // // typ = get_elem_type(typ, p) // // return root. func (p ObjectPath) GetGeneralizedIndex( typ schema.SSZType, ) (schema.SSZType, uint64, uint8, error) { gIndex := uint64(1) offset := uint8(0) for _, part := range p.Split() { // If we descend to a basic type, the path cannot continue further if typ.ID().IsBasic() { return nil, 0, 0, errors.New( "cannot descend further from basic type", ) } if part == "__len__" { if !typ.ID().IsList() { return nil, 0, 0, errors.New( "__len__ is only valid for List types", ) } typ = schema.U64() //nolint:mnd // from spec. gIndex = gIndex*2 + 1 } else { pos, start, _, err := typ.ItemPosition(part) if err != nil { return nil, 0, 0, err } gIndex = gIndex*getBaseIndex(typ)* pow.NextPowerOfTwo(typ.HashChunkCount()) + pos typ = typ.ElementType(part) offset = start } } return typ, gIndex, offset, nil } // getBaseIndex returns the base index for a given SSZ type. // For list types, it returns 2, for all other types it returns 1. func getBaseIndex(typ schema.SSZType) uint64 { if typ.ID().IsList() { //nolint:mnd // 2 is allowed. return 2 } return 1 } ================================================ FILE: primitives/merkle/object_path_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "strings" "testing" "github.com/berachain/beacon-kit/primitives/encoding/ssz/schema" "github.com/berachain/beacon-kit/primitives/merkle" "github.com/stretchr/testify/require" ) func Test_ObjectPath(t *testing.T) { t.Parallel() nested := schema.DefineContainer( schema.NewField("bytes32", schema.B32()), schema.NewField("uint64", schema.U64()), schema.NewField("list_bytes32", schema.DefineList(schema.B32(), 10)), schema.NewField("bytes256", schema.DefineVector(schema.U8(), 256)), ) root := schema.DefineContainer( schema.NewField("bytes32", schema.B32()), schema.NewField("uint32", schema.U32()), schema.NewField("list_uint64", schema.DefineList(schema.U64(), 1000)), schema.NewField("list_nested", schema.DefineList(nested, 1000)), schema.NewField("nested", nested), schema.NewField("vector_uint64", schema.DefineVector(schema.U64(), 40)), ) cases := []struct { path string gindex uint64 offset uint8 error string }{ // happy paths {path: "bytes32", gindex: 8}, {path: "bytes32/3", gindex: 8, offset: 3}, {path: "uint32", gindex: 9}, {path: "list_nested", gindex: 11}, {path: "list_nested/__len__", gindex: 2*11 + 1}, {path: "list_nested/12", gindex: 11*2*1024 + 12}, {path: "list_nested/12/uint64", gindex: (11*2*1024+12)*4 + 1}, {path: "nested", gindex: 12}, {path: "nested/uint64", gindex: 12*4 + 1}, {path: "nested/bytes256", gindex: 12*4 + 3}, {path: "nested/bytes256/30", gindex: (12*4 + 3) * 8, offset: 30}, {path: "vector_uint64", gindex: 13}, // 40 64-bit ints occupy 320 bytes (10 chunks), nextPowerOfTwo(10) = 16 {path: "vector_uint64/5", gindex: 13*16 + (5 / 4), offset: 8}, // error cases {path: "nested/__len__", error: "__len__ is only valid"}, } for _, tc := range cases { t.Run(strings.ReplaceAll(tc.path, "/", "."), func(t *testing.T) { t.Parallel() objectPath := merkle.ObjectPath(tc.path) typ, gindex, offset, err := objectPath.GetGeneralizedIndex(root) if tc.error != "" { require.ErrorContains(t, err, tc.error) return } require.NoError(t, err) require.NotNil( t, typ, "Type should not be nil") require.Equal( t, tc.gindex, gindex, "Unexpected generalized index", ) require.Equal(t, tc.offset, offset, "Unexpected offset") }) } } ================================================ FILE: primitives/merkle/proof.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import "github.com/berachain/beacon-kit/primitives/crypto/sha256" // VerifyProof given a tree root, a leaf, the generalized merkle index // of the leaf in the tree, and the proof itself. func VerifyProof[RootT, ProofT ~[32]byte]( root, leaf RootT, merkleIndex uint64, proof []ProofT, ) bool { //#nosec:G701 `int`` is at minimum 32-bits and thus a // uint8 will always fit. if len(proof) > int(^uint8(0)) { return false } return IsValidMerkleBranch( leaf, proof, uint8(len(proof)), // #nosec G115 -- we check the length of the proof above. merkleIndex, root, ) } // IsValidMerkleBranch as per the Ethereum 2.0 spec: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#is_valid_merkle_branch func IsValidMerkleBranch[RootT, BranchT ~[32]byte]( leaf RootT, branch []BranchT, depth uint8, index uint64, root RootT, ) bool { //#nosec:G701 `int`` is at minimum 32-bits and thus a // uint8 will always fit. if len(branch) != int(depth) { return false } return RootFromBranch(leaf, branch, depth, index) == root } // RootFromBranch calculates the Merkle root from a leaf and a branch. // Inspired by: // https://github.com/sigp/lighthouse/blob/stable/consensus/merkle_proof/src/lib.rs#L372 func RootFromBranch[RootT, BranchT ~[32]byte]( leaf RootT, branch []BranchT, depth uint8, index uint64, ) RootT { var ( hashInput [64]byte hashFn func([]byte) [32]byte merkleRoot = leaf ) //nolint:mnd // 5 as defined by the library. if depth > 5 { hashFn = sha256.CustomHashFn() } else { hashFn = sha256.Hash } for i := range depth { ithBit := (index >> i) & 1 if ithBit == 1 { copy(hashInput[:32], branch[i][:]) copy(hashInput[32:], merkleRoot[:]) } else { copy(hashInput[:32], merkleRoot[:]) copy(hashInput[32:], branch[i][:]) } merkleRoot = hashFn(hashInput[:]) } return merkleRoot } ================================================ FILE: primitives/merkle/root_hasher.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( "runtime" "unsafe" "github.com/prysmaticlabs/gohashtree" "golang.org/x/sync/errgroup" ) const ( // MinParallelizationSize is the minimum size of the input list that // should be hashed using the default method. If the input list is smaller // than this size, the overhead of parallelizing the hashing process is. // // TODO: This value is arbitrary and should be benchmarked to find the // optimal value. MinParallelizationSize = 5000 // two is a constant to make the linter happy. two = 2 ) // BuildParentTreeRoots calls BuildParentTreeRootsWithNRoutines to // parallelize the hashing process. func BuildParentTreeRoots[RootT ~[32]byte]( outputList, inputList []RootT, ) error { return BuildParentTreeRootsWithNRoutines( //#nosec:G103 // on purpose. *(*[][32]byte)(unsafe.Pointer(&outputList)), //#nosec:G103 // on purpose. *(*[][32]byte)(unsafe.Pointer(&inputList)), MinParallelizationSize, ) } // BuildParentTreeRootsWithNRoutines optimizes hashing of a list of roots // using CPU-specific vector instructions and parallel processing. This // method adapts to the host machine's hardware for potential performance // gains over sequential hashing. // // NOTE: Currently we use `runtime.GOMAXPROCS(0)-1` as the number of // goroutines to use. // // TODO: We do not use generics here due to the gohashtree library not // supporting generics. func BuildParentTreeRootsWithNRoutines( outputList, inputList [][32]byte, minParallelizationSize int, ) error { // Validate input list length. inputLength := len(inputList) if inputLength%2 != 0 { return ErrOddLengthTreeRoots } // If the input list is small, hash it using the default method since // the overhead of parallelizing the hashing process is not worth it. if inputLength < minParallelizationSize { return gohashtree.Hash(outputList, inputList) } // Get the number of goroutines to use. // // TODO: parameterize n and allow this to be specified by caller. n := runtime.GOMAXPROCS(0) - 1 // Otherwise parallelize the hashing process for large inputs. groupSize := inputLength / (two * (n + 1)) twiceGroupSize := two * groupSize eg := new(errgroup.Group) // If n is 0 the parallelization is disabled and the whole inputList is // hashed in the main goroutine at the end of this function. for j := range n { eg.Go(func() error { // inputList: [-------------------2*groupSize-------------------] // ______^ ____^ ^ ^ // | | | | // j*2*groupSize (j+1)*2*groupSize (j+2)*2*groupSize End // // outputList: [---------groupSize---------] // ^ ^ // | | // j*groupSize (j+1)*groupSize // // Each goroutine processes a segment of inputList that is twice as // large as the segment it fills in outputList. This is because the // hash operation reduces the size of the input by half. // Define the segment of the inputList each goroutine will process. segmentStart := j * twiceGroupSize segmentEnd := (j + 1) * twiceGroupSize return gohashtree.Hash( outputList[j*groupSize:], inputList[segmentStart:segmentEnd], ) }) } // Hash the last segment of the inputList. if err := gohashtree.Hash( outputList[n*groupSize:], inputList[n*twiceGroupSize:], ); err != nil { return err } return eg.Wait() } ================================================ FILE: primitives/merkle/root_hasher_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "fmt" "math/rand" "testing" "time" "github.com/berachain/beacon-kit/primitives/merkle" "github.com/prysmaticlabs/gohashtree" "github.com/stretchr/testify/require" ) func Test_HashTreeRootEqualInputs(t *testing.T) { t.Parallel() // Test with slices of varying sizes to ensure robustness across different // conditions sliceSizes := []int{16, 32, 64} for _, size := range sliceSizes { t.Run( fmt.Sprintf("Size%d", size*merkle.MinParallelizationSize), func(t *testing.T) { t.Parallel() largeSlice := make( [][32]byte, size*merkle.MinParallelizationSize, ) secondLargeSlice := make( [][32]byte, size*merkle.MinParallelizationSize, ) hash1 := make([][32]byte, size*merkle.MinParallelizationSize) hash2 := make([][32]byte, size*merkle.MinParallelizationSize) var err error err = merkle.BuildParentTreeRoots(hash1, largeSlice) require.NoError(t, err) err = merkle.BuildParentTreeRoots(hash2, secondLargeSlice) require.NoError(t, err) require.Equal( t, len(hash1), len(hash2), "Hash lengths should be equal", ) for i, r := range hash1 { require.Equal( t, r, hash2[i], fmt.Errorf("Hash mismatch at index %d", i), ) } }, ) } } func Test_GoHashTreeHashConformance(t *testing.T) { t.Parallel() // Define a test table with various input sizes, // including ones above and below MinParallelizationSize testCases := []struct { name string size int wantErr bool }{ { "BelowMinParallelizationSize", merkle.MinParallelizationSize / 2, false, }, {"AtMinParallelizationSize", merkle.MinParallelizationSize, false}, { "AboveMinParallelizationSize", merkle.MinParallelizationSize * 2, false, }, {"SmallSize", 16, false}, {"MediumSize", 64, false}, {"LargeSize", 128, false}, { "TestRemainderStartIndexSmall", merkle.MinParallelizationSize + 6, false, }, { "TestRemainderStartIndexBig", merkle.MinParallelizationSize - 2, false, }, {"TestOddLength", merkle.MinParallelizationSize + 1, true}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { t.Parallel() inputList := make([][32]byte, tc.size) // Fill inputList with pseudo-random data randSource := rand.NewSource(time.Now().UnixNano()) randGen := rand.New(randSource) for i := range inputList { for j := range inputList[i] { inputList[i][j] = byte(randGen.Intn(256)) } } requireGoHashTreeEquivalence( t, inputList, merkle.MinParallelizationSize, tc.wantErr, ) }) } } // TODO: Re-enable once N routines is parameterized. // func TestBuildParentTreeRootsWithNRoutines_DivisionByZero(t *testing.T) { // // Attempt to call BuildParentTreeRootsWithNRoutines with n set to 0 // // to test handling of division by zero. // inputList := make([][32]byte, 10) // Arbitrary size larger than 0 // output := make([][32]byte, 8) // Arbitrary size smaller than inputList // err := merkle.BuildParentTreeRootsWithNRoutines( // output, // inputList, // merkle.MinParallelizationSize, // ) // require.NoError( // t, // err, // "BuildParentTreeRootsWithNRoutines should handle n=0 without error", // ) // } // requireGoHashTreeEquivalence is a helper function to ensure that the output // of merkle.BuildParentTreeRootsWithNRoutines is equivalent to the output of // gohashtree.Hash. func requireGoHashTreeEquivalence( t *testing.T, inputList [][32]byte, minParallelizationSize int, expectError bool, ) { t.Helper() // Deep copy inputList inputListCopy := make([][32]byte, len(inputList)) copy(inputListCopy, inputList) expectedOutput := make([][32]byte, len(inputListCopy)/2) output := make([][32]byte, len(inputListCopy)/2) var err1, err2 error // Run parallel hasher. err1 = merkle.BuildParentTreeRootsWithNRoutines( output, inputListCopy, minParallelizationSize, ) // Run gohashtree.Hash err2 = gohashtree.Hash( expectedOutput, inputListCopy, ) // Check for errors if !expectError { require.NoError(t, err1, "BuildParentTreeRootsWithNRoutines failed") require.NoError(t, err2, "gohashtree.Hash failed") } else { if err1 == nil && err2 == nil { t.Error("Expected error did not occur") } return } // Ensure the lengths are the same require.Equal(t, len(expectedOutput), len(output)) // Compare the outputs element by element for i := range output { require.Equal(t, expectedOutput[i], output[i]) } } ================================================ FILE: primitives/merkle/tree.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( "encoding/binary" "fmt" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto/sha256" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/merkle/zero" ) // 2^63 would overflow. const MaxTreeDepth = 62 // Tree[RootT] implements a Merkle tree that has been optimized to // handle leaves that are 32 bytes in size. type Tree[RootT ~[32]byte] struct { depth uint8 branches [][]RootT leaves []RootT hasher Hasher[[32]byte] } // NewTreeFromLeaves constructs a Merkle tree, with the minimum // depth required to support the number of leaves. func NewTreeFromLeaves[RootT ~[32]byte]( leaves []RootT, ) (*Tree[RootT], error) { return NewTreeFromLeavesWithDepth( leaves, math.U64(len(leaves)).NextPowerOfTwo().ILog2Ceil(), ) } // NewTreeWithMaxLeaves constructs a Merkle tree with a maximum number of // leaves. func NewTreeWithMaxLeaves[RootT ~[32]byte]( leaves []RootT, maxLeaves uint64, ) (*Tree[RootT], error) { return NewTreeFromLeavesWithDepth( leaves, math.U64(maxLeaves).NextPowerOfTwo().ILog2Ceil(), ) } // NewTreeFromLeavesWithDepth constructs a Merkle tree // from a sequence of byte slices. // It will fill the tree with zero hashes to create the required depth. func NewTreeFromLeavesWithDepth[RootT ~[32]byte]( leaves []RootT, depth uint8, ) (*Tree[RootT], error) { if err := verifySufficientDepth(len(leaves), depth); err != nil { return &Tree[RootT]{}, err } layers := make([][]RootT, depth+1) layers[0] = leaves // Preallocate layers based on depth // TODO: This should be done virtually.... for i := uint8(1); i <= depth; i++ { layerSize := (len(leaves) + (1 << i) - 1) >> i layers[i] = make([]RootT, layerSize) } for d := range depth { currentLayer := layers[d] if len(currentLayer)%2 == 1 { currentLayer = append(currentLayer, zero.Hashes[d]) } if err := BuildParentTreeRoots( layers[d+1], currentLayer, ); err != nil { return &Tree[RootT]{}, err } } return &Tree[RootT]{ branches: layers, leaves: leaves, depth: depth, hasher: NewHasher[[32]byte](sha256.Hash), }, nil } // Insert an item into the tree. func (m *Tree[RootT]) Insert(item [32]byte, index int) error { if index < 0 { return errors.Wrap(ErrNegativeIndex, fmt.Sprintf("index: %d", index)) } for index >= len(m.branches[0]) { m.branches[0] = append(m.branches[0], zero.Hashes[0]) } m.branches[0][index] = item if index >= len(m.leaves) { m.leaves = append(m.leaves, item) } else { m.leaves[index] = item } var ( hashFn func([]byte) [32]byte neighbor = [32]byte{} input = [64]byte{} currentIndex = index root = item ) //nolint:mnd // 5 as defined by the library. if m.depth > 5 { hashFn = sha256.CustomHashFn() } else { hashFn = sha256.Hash } for i := range m.depth { if neighborIdx := currentIndex ^ 1; neighborIdx >= len(m.branches[i]) { neighbor = zero.Hashes[i] } else { neighbor = m.branches[i][neighborIdx] } //nolint:mnd // 2 is allowed. if isLeft := currentIndex%2 == 0; isLeft { copy(input[0:32], root[:]) copy(input[32:64], neighbor[:]) } else { copy(input[0:32], neighbor[:]) copy(input[32:64], root[:]) } root = hashFn(input[:]) //nolint:mnd // 2 is allowed. parentIdx := currentIndex / 2 if len(m.branches[i+1]) == 0 || parentIdx >= len(m.branches[i+1]) { m.branches[i+1] = append(m.branches[i+1], root) } else { m.branches[i+1][parentIdx] = root } currentIndex = parentIdx } return nil } // Root returns the root of the Merkle tree. func (m *Tree[RootT]) Root() [32]byte { return m.branches[len(m.branches)-1][0] } // HashTreeRoot returns the Root of the Merkle tree with the // number of leaves mixed in. func (m *Tree[RootT]) HashTreeRoot() common.Root { numItems := uint64(len(m.leaves)) if len(m.leaves) == 1 && m.leaves[0] == zero.Hashes[0] { numItems = 0 } return m.hasher.MixIn(m.Root(), numItems) } // MerkleProof computes a proof from a tree's branches using a Merkle index. func (m *Tree[RootT]) MerkleProof(leafIndex uint64) ([]RootT, error) { numLeaves := uint64(len(m.branches[0])) if leafIndex >= numLeaves { return nil, errors.Wrapf( errors.New("merkle index out of range in tree"), "max range: %d, received: %d", numLeaves, leafIndex, ) } proof := make([]RootT, m.depth) for i := range m.depth { subIndex := (leafIndex >> i) ^ 1 if subIndex < uint64(len(m.branches[i])) { proof[i] = m.branches[i][subIndex] } else { proof[i] = zero.Hashes[i] } } return proof, nil } // MerkleProofWithMixin computes a proof from a tree's branches using a Merkle // index. func (m *Tree[RootT]) MerkleProofWithMixin( index uint64, ) ([]RootT, error) { proof, err := m.MerkleProof(index) if err != nil { return nil, err } mixin := [32]byte{} binary.LittleEndian.PutUint64(mixin[:8], uint64(len(m.leaves))) return append(proof, mixin), nil } ================================================ FILE: primitives/merkle/tree_fuzz_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "testing" byteslib "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/merkle" "github.com/stretchr/testify/require" ) const depth = uint8(16) func FuzzTree_IsValidMerkleBranch(f *testing.F) { splitProofs := func(proofRaw []byte) [][32]byte { var proofs [][32]byte for i := 0; i < len(proofRaw); i += 32 { end := i + 32 if end >= len(proofRaw) { end = len(proofRaw) - 1 } var proofSegment [32]byte copy(proofSegment[:], proofRaw[i:end]) proofs = append(proofs, proofSegment) } return proofs } items := make([][32]byte, 0) for _, v := range [][]byte{ byteslib.ExtendToSize([]byte("A"), byteslib.B32Size), byteslib.ExtendToSize([]byte("B"), byteslib.B32Size), byteslib.ExtendToSize([]byte("C"), byteslib.B32Size), byteslib.ExtendToSize([]byte("D"), byteslib.B32Size), byteslib.ExtendToSize([]byte("E"), byteslib.B32Size), byteslib.ExtendToSize([]byte("F"), byteslib.B32Size), byteslib.ExtendToSize([]byte("G"), byteslib.B32Size), } { item, err := byteslib.ToBytes32(v) require.NoError(f, err) items = append(items, item) } require.NotEmpty(f, items) // appease nilaway m, err := merkle.NewTreeFromLeavesWithDepth(items, depth) require.NoError(f, err) proof, err := m.MerkleProofWithMixin(0) require.NoError(f, err) require.Len(f, proof, int(depth)+1) root := m.HashTreeRoot() var proofRaw []byte for _, p := range proof { proofRaw = append(proofRaw, p[:]...) } f.Add(root[:], items[0][:], uint64(0), proofRaw, depth) f.Fuzz( func(t *testing.T, root, item []byte, merkleIndex uint64, proofRaw []byte, depth uint8, ) { var r, leaf byteslib.B32 item = byteslib.ExtendToSize(item, byteslib.B32Size)[:byteslib.B32Size] leaf, err = byteslib.ToBytes32(item) require.NoError(t, err) root = byteslib.ExtendToSize(root, byteslib.B32Size)[:byteslib.B32Size] r, err = byteslib.ToBytes32(root) require.NoError(t, err) merkle.IsValidMerkleBranch( leaf, splitProofs(proofRaw), depth, merkleIndex, r, ) }, ) } ================================================ FILE: primitives/merkle/tree_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle_test import ( "strconv" "testing" byteslib "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/merkle" "github.com/stretchr/testify/require" ) func TestNewTreeFromLeavesWithDepth_NoItemsProvided(t *testing.T) { t.Parallel() treeDepth := uint8(32) _, err := merkle.NewTreeFromLeavesWithDepth[[32]byte]( nil, treeDepth, ) require.ErrorIs(t, err, merkle.ErrEmptyLeaves) } func TestNewTreeFromLeavesWithDepth_DepthSupport(t *testing.T) { t.Parallel() items := make([][32]byte, 0) for _, v := range [][]byte{ byteslib.ExtendToSize([]byte("A"), byteslib.B32Size), byteslib.ExtendToSize([]byte("BB"), byteslib.B32Size), byteslib.ExtendToSize([]byte("CCC"), byteslib.B32Size), byteslib.ExtendToSize([]byte("DDDD"), byteslib.B32Size), byteslib.ExtendToSize([]byte("EEEEE"), byteslib.B32Size), byteslib.ExtendToSize([]byte("FFFFFF"), byteslib.B32Size), byteslib.ExtendToSize([]byte("GGGGGGG"), byteslib.B32Size), } { item, err := byteslib.ToBytes32(v) require.NoError(t, err) items = append(items, item) } // Supported depth m1, err := merkle.NewTreeFromLeavesWithDepth( items, merkle.MaxTreeDepth, ) require.NoError(t, err) proof, err := m1.MerkleProofWithMixin(2) require.NoError(t, err) require.Len(t, proof, int(merkle.MaxTreeDepth)+1) // Unsupported depth _, err = merkle.NewTreeFromLeavesWithDepth( items, merkle.MaxTreeDepth+1, ) require.ErrorIs(t, err, merkle.ErrExceededDepth) } func TestMerkleTree_IsValidMerkleBranch(t *testing.T) { t.Parallel() treeDepth := uint8(32) items := make([][32]byte, 0) for _, v := range [][]byte{ byteslib.ExtendToSize([]byte("A"), byteslib.B32Size), byteslib.ExtendToSize([]byte("B"), byteslib.B32Size), byteslib.ExtendToSize([]byte("C"), byteslib.B32Size), byteslib.ExtendToSize([]byte("D"), byteslib.B32Size), byteslib.ExtendToSize([]byte("E"), byteslib.B32Size), byteslib.ExtendToSize([]byte("F"), byteslib.B32Size), byteslib.ExtendToSize([]byte("G"), byteslib.B32Size), } { item, err := byteslib.ToBytes32(v) require.NoError(t, err) items = append(items, item) } require.NotEmpty(t, items) m, err := merkle.NewTreeFromLeavesWithDepth( items, treeDepth, ) require.NoError(t, err) proof, err := m.MerkleProofWithMixin(0) require.NoError(t, err) require.Len( t, proof, int(treeDepth)+1, ) root := m.HashTreeRoot() require.True(t, merkle.VerifyProof( root, items[0], 0, proof, ), "First Merkle proof did not verify") proof, err = m.MerkleProofWithMixin(3) require.NoError(t, err) require.True( t, merkle.VerifyProof( root, items[3], 3, proof, ), ) it := byteslib.ExtendToSize([]byte("buzz"), byteslib.B32Size) item, err := byteslib.ToBytes32(it) require.NoError(t, err) require.False( t, merkle.IsValidMerkleBranch( common.Root(item), proof, treeDepth, 3, root, ), ) } func TestMerkleTree_VerifyProof(t *testing.T) { t.Parallel() treeDepth := uint8(32) items := make([][32]byte, 0) for _, v := range [][]byte{ byteslib.ExtendToSize([]byte("A"), byteslib.B32Size), byteslib.ExtendToSize([]byte("B"), byteslib.B32Size), byteslib.ExtendToSize([]byte("C"), byteslib.B32Size), byteslib.ExtendToSize([]byte("D"), byteslib.B32Size), byteslib.ExtendToSize([]byte("E"), byteslib.B32Size), byteslib.ExtendToSize([]byte("F"), byteslib.B32Size), byteslib.ExtendToSize([]byte("G"), byteslib.B32Size), } { item, err := byteslib.ToBytes32(v) require.NoError(t, err) items = append(items, item) } require.NotEmpty(t, items) // appease nilaway m, err := merkle.NewTreeFromLeavesWithDepth[[32]byte]( items, treeDepth, ) require.NoError(t, err) proof, err := m.MerkleProofWithMixin(0) require.NoError(t, err) require.Len( t, proof, int(treeDepth)+1, ) root := m.HashTreeRoot() if ok := merkle.VerifyProof(root, items[0], 0, proof); !ok { t.Error("First Merkle proof did not verify") } proof, err = m.MerkleProofWithMixin(3) require.NoError(t, err) require.True(t, merkle.VerifyProof(root, items[3], 3, proof)) it := byteslib.ExtendToSize([]byte("buzz"), byteslib.B32Size) item, err := byteslib.ToBytes32(it) require.NoError(t, err) require.False( t, merkle.VerifyProof( root, common.Root(item), 3, proof, ), ) } func TestMerkleTree_NegativeIndexes(t *testing.T) { t.Parallel() treeDepth := uint8(32) items := make([][32]byte, 0) for _, v := range [][]byte{ byteslib.ExtendToSize([]byte("A"), byteslib.B32Size), byteslib.ExtendToSize([]byte("B"), byteslib.B32Size), byteslib.ExtendToSize([]byte("C"), byteslib.B32Size), byteslib.ExtendToSize([]byte("D"), byteslib.B32Size), byteslib.ExtendToSize([]byte("E"), byteslib.B32Size), byteslib.ExtendToSize([]byte("F"), byteslib.B32Size), byteslib.ExtendToSize([]byte("G"), byteslib.B32Size), } { item, err := byteslib.ToBytes32(v) require.NoError(t, err) items = append(items, item) } m, err := merkle.NewTreeFromLeavesWithDepth( items, treeDepth, ) require.NoError(t, err) it := byteslib.ExtendToSize([]byte("J"), byteslib.B32Size) extraItem, err := byteslib.ToBytes32(it) require.NoError(t, err) err = m.Insert(extraItem, -1) require.ErrorIs(t, err, merkle.ErrNegativeIndex) } func TestMerkleTree_VerifyProof_TrieUpdated(t *testing.T) { t.Parallel() treeDepth := uint8(32) items := [][32]byte{ {1}, {2}, {3}, {4}, } m, err := merkle.NewTreeFromLeavesWithDepth( items, treeDepth+1, ) require.NoError(t, err) proof, err := m.MerkleProofWithMixin(0) require.NoError(t, err) root := m.HashTreeRoot() require.True( t, merkle.VerifyProof( root, items[0], 0, proof, ), ) // Now we update the merkle it := byteslib.ExtendToSize([]byte{5}, byteslib.B32Size) item, err := byteslib.ToBytes32(it) require.NoError(t, err) require.NoError(t, m.Insert(item, 3)) proof, err = m.MerkleProofWithMixin(3) require.NoError(t, err) root = m.HashTreeRoot() require.True(t, merkle.VerifyProof( root, [32]byte{5}, 3, proof, ), "Second Merkle proof did not verify") require.False(t, merkle.VerifyProof( root, [32]byte{4}, 3, proof, ), "Old item should not verify") // Now we update the tree at an index larger than the number of items. it = byteslib.ExtendToSize([]byte{6}, byteslib.B32Size) item, err = byteslib.ToBytes32(it) require.NoError(t, err) require.NoError(t, m.Insert(item, 15)) } func BenchmarkNewTreeFromLeavesWithDepth(b *testing.B) { treeDepth := uint8(32) items := make([][32]byte, 0) for _, v := range [][]byte{ byteslib.ExtendToSize([]byte("A"), byteslib.B32Size), byteslib.ExtendToSize([]byte("BB"), byteslib.B32Size), byteslib.ExtendToSize([]byte("CCC"), byteslib.B32Size), byteslib.ExtendToSize([]byte("DDDD"), byteslib.B32Size), byteslib.ExtendToSize([]byte("EEEEE"), byteslib.B32Size), byteslib.ExtendToSize([]byte("FFFFFF"), byteslib.B32Size), byteslib.ExtendToSize([]byte("GGGGGGG"), byteslib.B32Size), } { item, err := byteslib.ToBytes32(v) require.NoError(b, err) items = append(items, item) } for range b.N { _, err := merkle.NewTreeFromLeavesWithDepth( items, treeDepth, ) require.NoError(b, err, "Could not generate Merkle tree from items") } } func BenchmarkInsertTrie_Optimized(b *testing.B) { treeDepth := uint8(32) b.StopTimer() var ( numDeposits = 16000 items = make([][32]byte, numDeposits) err error ) for i := range numDeposits { it := byteslib.ExtendToSize([]byte(strconv.Itoa(i)), byteslib.B32Size) items[i], err = byteslib.ToBytes32(it) require.NoError(b, err) } tr, err := merkle.NewTreeFromLeavesWithDepth[[32]byte]( items, treeDepth, ) require.NoError(b, err) it := byteslib.ExtendToSize([]byte("hello-world"), byteslib.B32Size) someItem, err := byteslib.ToBytes32(it) require.NoError(b, err) b.StartTimer() for i := range b.N { require.NoError(b, tr.Insert(someItem, i%numDeposits)) } } func BenchmarkGenerateProof(b *testing.B) { treeDepth := uint8(32) b.StopTimer() items := make([][32]byte, 0) for _, v := range [][]byte{ byteslib.ExtendToSize([]byte("A"), byteslib.B32Size), byteslib.ExtendToSize([]byte("BB"), byteslib.B32Size), byteslib.ExtendToSize([]byte("CCC"), byteslib.B32Size), byteslib.ExtendToSize([]byte("DDDD"), byteslib.B32Size), byteslib.ExtendToSize([]byte("EEEEE"), byteslib.B32Size), byteslib.ExtendToSize([]byte("FFFFFF"), byteslib.B32Size), byteslib.ExtendToSize([]byte("GGGGGGG"), byteslib.B32Size), } { item, err := byteslib.ToBytes32(v) require.NoError(b, err) items = append(items, item) } goodTree, err := merkle.NewTreeFromLeavesWithDepth[[32]byte]( items, treeDepth, ) require.NoError(b, err) b.StartTimer() for range b.N { _, err = goodTree.MerkleProofWithMixin(3) require.NoError(b, err) } } func BenchmarkIsValidMerkleBranch(b *testing.B) { treeDepth := uint8(4) b.StopTimer() items := make([][32]byte, 0) for _, v := range [][]byte{ byteslib.ExtendToSize([]byte("A"), byteslib.B32Size), byteslib.ExtendToSize([]byte("BB"), byteslib.B32Size), byteslib.ExtendToSize([]byte("CCC"), byteslib.B32Size), byteslib.ExtendToSize([]byte("DDDD"), byteslib.B32Size), byteslib.ExtendToSize([]byte("EEEEE"), byteslib.B32Size), byteslib.ExtendToSize([]byte("FFFFFF"), byteslib.B32Size), byteslib.ExtendToSize([]byte("GGGGGGG"), byteslib.B32Size), } { item, err := byteslib.ToBytes32(v) require.NoError(b, err) items = append(items, item) } require.NotEmpty(b, items) // appease nilaway m, err := merkle.NewTreeFromLeavesWithDepth[[32]byte]( items, treeDepth, ) require.NoError(b, err) proof, err := m.MerkleProofWithMixin(2) require.NoError(b, err) b.StartTimer() for range b.N { ok := merkle.IsValidMerkleBranch( items[2], proof, treeDepth+1, 2, m.HashTreeRoot(), ) require.True(b, ok, "Merkle proof did not verify") } } ================================================ FILE: primitives/merkle/utils.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package merkle import ( "fmt" "github.com/berachain/beacon-kit/errors" ) // verifySufficientDepth ensures that the depth is sufficient to build a tree. func verifySufficientDepth(numLeaves int, depth uint8) error { switch { case numLeaves == 0: return ErrEmptyLeaves case depth == 0: return ErrZeroDepth case depth > MaxTreeDepth: return ErrExceededDepth case numLeaves > (1 << depth): return errors.Wrap( ErrInsufficientDepthForLeaves, fmt.Sprintf( "attempted to build tree/root with %d leaves at depth %d", numLeaves, depth), ) } return nil } ================================================ FILE: primitives/merkle/zero/zero.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package zero import "github.com/berachain/beacon-kit/primitives/crypto/sha256" // NumZeroHashes is the number of pre-computed zero-hashes. const NumZeroHashes = 64 // Hashes is a pre-computed list of zero-hashes for each depth level. // //nolint:gochecknoglobals // saves recomputing. var Hashes [NumZeroHashes + 1][32]byte // InitZeroHashes the zero-hashes pre-computed data // with the given hash-function. func InitZeroHashes(zeroHashesLevels int) { v := [64]byte{} for i := range zeroHashesLevels { copy(v[:32], Hashes[i][:]) copy(v[32:], Hashes[i][:]) Hashes[i+1] = sha256.Hash(v[:]) } } //nolint:gochecknoinits // saves recomputing. func init() { InitZeroHashes(NumZeroHashes) } ================================================ FILE: primitives/net/http/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package http import ( "errors" ) var ( // ErrTimeout indicates a timeout error from http.Client. ErrTimeout = errors.New("timeout from HTTP client") // ErrUnauthorized indicates an unauthorized error from http.Client. ErrUnauthorized = errors.New("401 unauthorized request") ) // TimeoutError defines an interface for timeout errors. // It includes methods for error message retrieval and timeout status checking. type TimeoutError interface { // Error returns the error message. Error() string // Timeout indicates whether the error is a timeout error. Timeout() bool } // IsTimeoutError checks if the given error is a timeout error. // It asserts the error to the httpTimeoutError interface and checks its Timeout // status. // Returns true if the error is a timeout error, false otherwise. func IsTimeoutError(e error) bool { var t TimeoutError ok := errors.As(e, &t) return ok && t != nil && t.Timeout() } ================================================ FILE: primitives/net/json-rpc/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package jsonrpc import ( "github.com/berachain/beacon-kit/errors" ) // Error wraps RPC errors, which contain an error code in addition to the // message. type Error interface { // Error returns the error message. Error() string // ErrorCode returns the JSON-RPC error code. ErrorCode() int } // IsPreDefinedError returns true if the given // error is a predefined JSON-RPC errors. func IsPreDefinedError(err error) bool { return errors.IsAny( err, ErrParse, ErrInvalidRequest, ErrMethodNotFound, ErrInvalidParams, ErrInternal, ErrServer, ErrServerParse, ) } var ( // ErrParse indicates that invalid JSON was received by the server. // (code: -32700). ErrParse = errors.New( "invalid JSON was received by the server (code: -32700)", ) // ErrInvalidRequest indicates that the JSON sent is not a valid Request // object. (code: -32600). ErrInvalidRequest = errors.New( "the JSON sent is not a valid Request object (code: -32600)", ) // ErrMethodNotFound indicates that the method does not exist or is not // available. (code: -32601). ErrMethodNotFound = errors.New( "the method does not exist / is not available (code: -32601)", ) // ErrInvalidParams indicates invalid method parameters. (code: -32602). ErrInvalidParams = errors.New("invalid method parameter(s) (code: -32602)") // ErrInternal indicates an internal JSON-RPC error. (code: -32603). ErrInternal = errors.New("internal JSON-RPC error (code: -32603)") // ErrServer is reserved for implementation-defined server errors. // (code: -32000 to -32099). ErrServer = errors.New( "received implementation-defined server-error (code: -32000 to -32099)", ) // ErrServerParse indicates an error occurred on the server while // parsing the JSON text. (code: -32700). ErrServerParse = errors.New( "an error occurred on the server while parsing the JSON text (code: -32700)", ) ) ================================================ FILE: primitives/net/jwt/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package jwt import "github.com/berachain/beacon-kit/errors" var ( // ErrLengthMismatch is returned when a JWT secret length is not as // expected. ErrLengthMismatch = errors.New( "JWT secret length mismatch") // ErrContainsIllegalCharacter is returned when a JWT secret contains // illegal characters. ErrContainsIllegalCharacter = errors.New( "JWT secret contains illegal character(s)") // ErrCreateJWT is returned when a JWT token fails to be created. ErrCreateJWT = errors.New("failed to create JWT token") ) ================================================ FILE: primitives/net/jwt/jwt.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package jwt import ( "crypto/rand" "regexp" "strings" "time" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/encoding/hex" gjwt "github.com/golang-jwt/jwt/v5" ) // HexRegexp is a regular expression to match hexadecimal characters. var HexRegexp = regexp.MustCompile(`^(?:0x)?[0-9a-fA-F]*$`) // EthereumJWTLength defines the length of the JWT byte array to be 32 bytes as // defined the Engine API specification. // https://github.com/ethereum/execution-apis/blob/main/src/engine/authentication.md const EthereumJWTLength = 32 // Secret represents a JSON Web Token as a fixed-size byte array. type Secret [EthereumJWTLength]byte // NewFromHex creates a new JWT secret from a hexadecimal string. func NewFromHex(hexStr string) (*Secret, error) { // Ensure the hex string contains only hexadecimal characters. if !HexRegexp.MatchString(hexStr) { return nil, ErrContainsIllegalCharacter } // Convert the hex string to a byte array. bz, err := hex.ToBytes(hexStr) if err != nil { return nil, err } if bz == nil || len(bz) != EthereumJWTLength { return nil, ErrLengthMismatch } s := Secret(bz) return &s, nil } // NewRandom creates a new random JWT secret. func NewRandom() (*Secret, error) { secret := make([]byte, EthereumJWTLength) // We don't need to check n since: // n == len(b) if and only if err == nil. _, err := rand.Read(secret) if err != nil { return nil, err } return NewFromHex(hex.EncodeBytes(secret)) } // BuildSignedToken creates a signed JWT token from the secret. func (s *Secret) BuildSignedToken() (string, error) { token := gjwt.NewWithClaims(gjwt.SigningMethodHS256, gjwt.MapClaims{ "iat": &gjwt.NumericDate{Time: time.Now()}, }) str, err := token.SignedString(s[:]) if err != nil { return "", errors.Wrapf(ErrCreateJWT, "%w", err) } return str, nil } // String returns the JWT secret as a string with the first 8 characters // visible and the rest masked out for security. func (s *Secret) String() string { secret := hex.EncodeBytes(s[:]) return secret[:8] + strings.Repeat("*", len(secret[8:])) } // Hex returns the JWT secret as a hexadecimal string. func (s *Secret) Hex() string { return hex.EncodeBytes(s[:]) } // Bytes returns the JWT secret as a byte array. func (s *Secret) Bytes() []byte { return s[:] } ================================================ FILE: primitives/net/jwt/jwt_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package jwt_test import ( "strings" "testing" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/net/jwt" "github.com/stretchr/testify/require" ) func TestNewFromHex(t *testing.T) { t.Parallel() wantValid := jwt.Secret( hex.MustToBytes( "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", ), ) tests := []struct { name string hexStr string want *jwt.Secret wantErr bool }{ { name: "valid hex string w/ 0x prefix", hexStr: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", want: &(wantValid), wantErr: false, }, { name: "valid hex string no 0x prefix", hexStr: "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", want: &(wantValid), wantErr: true, }, { name: "invalid hex string", hexStr: "0x123", want: nil, wantErr: true, }, { name: "empty hex string", hexStr: "", want: nil, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := jwt.NewFromHex(tt.hexStr) if tt.wantErr { require.Error(t, err) return } require.Equal(t, tt.want, got) }) } } func TestSecretString(t *testing.T) { t.Parallel() tests := []struct { name string secret jwt.Secret want string }{ { name: "mask secret correctly", secret: jwt.Secret( hex.MustToBytes( "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", ), ), want: "0x123456**********************************************************", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() require.Equal( t, tt.want, tt.secret.String(), "Secret.String() mismatch", ) }) } } func TestNewRandom(t *testing.T) { t.Parallel() secret, err := jwt.NewRandom() require.NoError(t, err, "NewRandom() error") require.Len(t, secret.Bytes(), 32, "NewRandom() length mismatch") } func TestSecretBytes(t *testing.T) { t.Parallel() expectedLength := 32 // Assuming the secret is expected to be 32 bytes long secret, _ := jwt.NewRandom() bytes := secret.Bytes() require.Len(t, bytes, expectedLength, "Bytes() length mismatch") } func TestSecretHexWithFixedInput(t *testing.T) { t.Parallel() expectedHex := "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef" expectedHexLength := 64 secret, err := jwt.NewFromHex(expectedHex) require.NoError(t, err, "NewFromHex() error") hexStr := secret.Hex() require.Equal(t, expectedHex, hexStr, "Hex() output mismatch") // Check if the hex string is of the expected length and format. require.Len(t, hexStr, expectedHexLength+2, "Hex() length mismatch") // Strip the '0x' prefix and check if the remaining string is valid hex. hexStr = strings.TrimPrefix(hexStr, "0x") require.Len( t, hexStr, expectedHexLength, "Hex() length after stripping '0x' mismatch", ) require.True( t, jwt.HexRegexp.MatchString(hexStr), "Hex() output does not match hexadecimal format", ) } func TestSecretRoundTripEncoding(t *testing.T) { t.Parallel() originalSecret, err := jwt.NewRandom() require.NoError(t, err, "NewRandom() error") // Encode the original secret to hex string encodedSecret := hex.EncodeBytes(originalSecret.Bytes()) // Decode the hex string back to secret decodedSecret, err := jwt.NewFromHex(encodedSecret) require.NoError(t, err, "NewFromHex() error") // Compare the original and decoded secrets require.Equal( t, originalSecret, decodedSecret, "Round trip encoding failed", ) } func TestBuildSignedToken(t *testing.T) { t.Parallel() secret, err := jwt.NewRandom() require.NoError(t, err, "NewRandom() error") token, err := secret.BuildSignedToken() require.NoError(t, err, "BuildSignedToken() error") require.NotEmpty(t, token, "BuildSignedToken() returned empty token") // Verify the token structure (header.payload.signature) parts := strings.Split(token, ".") require.Len(t, parts, 3, "Token should have three parts") } func TestNewFromHexEdgeCases(t *testing.T) { t.Parallel() tests := []struct { name string hexStr string wantErr bool }{ { name: "lowercase hex string", hexStr: "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", wantErr: false, }, { name: "uppercase hex string", hexStr: "0xABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890", wantErr: false, }, { name: "mixed case hex string", hexStr: "0xaBcDeF1234567890aBcDeF1234567890aBcDeF1234567890aBcDeF1234567890", wantErr: false, }, { name: "invalid characters", hexStr: "0x123G567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", wantErr: true, }, { name: "too short", hexStr: "0x1234567890abcdef", wantErr: true, }, { name: "too long", hexStr: "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef00", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() _, err := jwt.NewFromHex(tt.hexStr) if tt.wantErr { require.Error(t, err) } else { require.NoError(t, err) } }) } } func TestHexRegexp(t *testing.T) { t.Parallel() validHexStrings := []string{ "0x1234567890abcdef", "1234567890ABCDEF", "0xABCDEF1234567890", "abcdef1234567890", } invalidHexStrings := []string{ "0x123G567890abcdef", "GHIJKLMNOPQRSTUV", "0xABCDEF12345678@0", "abcdef123456789g", } for _, validHex := range validHexStrings { require.True( t, jwt.HexRegexp.MatchString(validHex), "Valid hex string not matched: %s", validHex, ) } for _, invalidHex := range invalidHexStrings { require.False( t, jwt.HexRegexp.MatchString(invalidHex), "Invalid hex string matched: %s", invalidHex, ) } } func TestSecretComparison(t *testing.T) { t.Parallel() secret1, err := jwt.NewRandom() require.NoError(t, err, "NewRandom() error for secret1") secret2, err := jwt.NewRandom() require.NoError(t, err, "NewRandom() error for secret2") require.NotEqual( t, secret1, secret2, "Two random secrets should not be equal", ) secret3 := *secret1 require.Equal( t, secret1, &secret3, "Copied secret should be equal to original", ) } ================================================ FILE: primitives/net/url/url.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package url import "net/url" // ConnectionURL is a URL struct that is used to dial the execution client. type ConnectionURL struct { *url.URL } // NewDialURL creates a new DialURL. func NewDialURL(u *url.URL) *ConnectionURL { return &ConnectionURL{u} } func NewFromRaw(raw string) (*ConnectionURL, error) { u, err := url.Parse(raw) if err != nil { return nil, err } return NewDialURL(u), nil } // IsHTTP checks if the DialURL scheme is HTTP. func (d *ConnectionURL) IsHTTP() bool { return d.Scheme == "http" } // IsHTTPS checks if the DialURL scheme is HTTPS. func (d *ConnectionURL) IsHTTPS() bool { return d.Scheme == "https" } // IsIPC checks if the DialURL scheme is IPC. func (d *ConnectionURL) IsIPC() bool { return d.Scheme == "ipc" } ================================================ FILE: primitives/transition/context.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package transition import ( "context" "github.com/berachain/beacon-kit/primitives/math" ) // Context is the context for the state transition. type Context struct { // consensusCtx is the context passed by CometBFT callbacks // We pass it down to be able to cancel processing (although // currently CometBFT context is set to TODO) consensusCtx context.Context // consensusTime returns the timestamp of current consensus request. // It is used to build next payload and to validate currentpayload. consensusTime math.U64 // Address of current block proposer proposerAddress []byte // verifyPayload indicates whether to call NewPayload on the // execution client. This can be done when the node is not // syncing, and the payload is already known to the execution client. verifyPayload bool // verifyRandao indicates whether to validate the Randao mix. verifyRandao bool // verifyResult indicates whether to validate the result of // the state transition. verifyResult bool // meterGas controls whether gas data related to the execution // layer payload should be meter or not. We currently meter only // finalized blocks. meterGas bool } func NewTransitionCtx( consensusCtx context.Context, time math.U64, address []byte, ) *Context { return &Context{ consensusCtx: consensusCtx, consensusTime: time, proposerAddress: address, // by default we don't meter gas // (we care only about finalized blocks gas) meterGas: false, // by default we keep all verification verifyPayload: true, verifyRandao: true, verifyResult: true, } } // Setters to control context attributes. func (c *Context) WithMeterGas(meter bool) *Context { c.meterGas = meter return c } func (c *Context) WithVerifyPayload(verifyPayload bool) *Context { c.verifyPayload = verifyPayload return c } func (c *Context) WithVerifyRandao(verifyRandao bool) *Context { c.verifyRandao = verifyRandao return c } func (c *Context) WithVerifyResult(verifyResult bool) *Context { c.verifyResult = verifyResult return c } // Getters of context attributes. func (c *Context) ConsensusCtx() context.Context { return c.consensusCtx } func (c *Context) ConsensusTime() math.U64 { return c.consensusTime } func (c *Context) ProposerAddress() []byte { return c.proposerAddress } func (c *Context) VerifyPayload() bool { return c.verifyPayload } func (c *Context) VerifyRandao() bool { return c.verifyRandao } func (c *Context) VerifyResult() bool { return c.verifyResult } func (c *Context) MeterGas() bool { return c.meterGas } ================================================ FILE: primitives/transition/validator_update.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package transition import ( "sort" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" ) // ValidatorUpdates is a list of validator updates. type ValidatorUpdates []*ValidatorUpdate // ValidatorUpdate is a struct that holds the validator update. type ValidatorUpdate struct { // Pubkey is the public key of the validator. PubKey identifies // updates, meaning that two validator updates are considered equal // if they refer to the same PubKey Pubkey crypto.BLSPubkey // EffectiveBalance is the effective balance of the validator. EffectiveBalance math.Gwei } // CanonicalSort sorts validator updates in the canonical order. // Canonical order requires validators updates being sorted // by their PubKey, with no duplicates. In case of duplicates // the latest is preferred. func (vu ValidatorUpdates) CanonicalSort() ValidatorUpdates { return vu.removeDuplicates().sort() } // removeDuplicates removes duplicate validator updates. We // iterate through the list backwards since we want the last // update to be the one that is kept. func (vu ValidatorUpdates) removeDuplicates() ValidatorUpdates { duplicateCheck := make(map[crypto.BLSPubkey]struct{}) j := len(vu) - 1 for i := j; i >= 0; i-- { update := vu[i] if _, exists := duplicateCheck[update.Pubkey]; !exists { duplicateCheck[update.Pubkey] = struct{}{} vu[j] = vu[i] j-- } } vu = vu[j+1:] return vu } // sort sorts the validator updates. func (vu ValidatorUpdates) sort() ValidatorUpdates { sort.SliceStable(vu, func(i, j int) bool { return string((vu)[i].Pubkey[:]) < string((vu)[j].Pubkey[:]) }) return vu } ================================================ FILE: primitives/transition/validator_update_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package transition_test import ( "testing" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/stretchr/testify/require" ) func TestValidatorUpdate_CanonicalSort(t *testing.T) { t.Parallel() pubkey1 := crypto.BLSPubkey{1} pubkey2 := crypto.BLSPubkey{2} pubkey3 := crypto.BLSPubkey{3} type test struct { name string input transition.ValidatorUpdates want transition.ValidatorUpdates } tests := []test{ { name: "RemoveDuplicates-PickLatest", input: transition.ValidatorUpdates{ &transition.ValidatorUpdate{ Pubkey: pubkey1, EffectiveBalance: math.Gwei(1000), }, &transition.ValidatorUpdate{ Pubkey: pubkey1, EffectiveBalance: math.Gwei(500), }, &transition.ValidatorUpdate{ Pubkey: pubkey2, EffectiveBalance: math.Gwei(2000), }, }, want: transition.ValidatorUpdates{ &transition.ValidatorUpdate{ Pubkey: pubkey1, EffectiveBalance: math.Gwei(500), }, &transition.ValidatorUpdate{ Pubkey: pubkey2, EffectiveBalance: math.Gwei(2000), }, }, }, { name: "SortByPubKey", input: transition.ValidatorUpdates{ &transition.ValidatorUpdate{ Pubkey: pubkey3, EffectiveBalance: math.Gwei(2000), }, &transition.ValidatorUpdate{ Pubkey: pubkey1, EffectiveBalance: math.Gwei(5000), }, &transition.ValidatorUpdate{ Pubkey: pubkey2, EffectiveBalance: math.Gwei(1000), }, }, want: transition.ValidatorUpdates{ &transition.ValidatorUpdate{ Pubkey: pubkey1, EffectiveBalance: math.Gwei(5000), }, &transition.ValidatorUpdate{ Pubkey: pubkey2, EffectiveBalance: math.Gwei(1000), }, &transition.ValidatorUpdate{ Pubkey: pubkey3, EffectiveBalance: math.Gwei(2000), }, }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() got := tc.input.CanonicalSort() require.Equal(t, tc.want, got) }) } } ================================================ FILE: primitives/version/comparable.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package version import ( "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" ) /* -------------------------------------------------------------------------- */ /* Comparable */ /* -------------------------------------------------------------------------- */ // NOTE: IsBefore and Equals are implemented to set a canonical sorting // algorithm for the common.Version type. A standard cmp function would require // IsBefore and Equals and could be implemented as: // // func cmp(a, b common.Version) int { // // a is before b // if version.IsBefore(a, b) { // return -1 // } // // a is the same version as b // if version.Equals(a, b) { // return 0 // } // // a is after b // return 1 // } // IsBefore returns true if a is before b. This compares bytes from most significant // to least significant in "little-endian" order. func IsBefore(a, b common.Version) bool { // Iterate in order of significance. for i := range bytes.B4Size { // We short-circuit if a[i] != b[i] since we are iterating in order of significance. if a[i] < b[i] { return true } else if a[i] > b[i] { return false } } // If we reach this point, a and b are the same version. return false } // IsBeforeOrEquals returns true if a is before or at the same version as b. func IsBeforeOrEquals(a, b common.Version) bool { return IsBefore(a, b) || Equals(a, b) } // Equals returns true if a and b are equal (each byte in the 4-byte vector is the same). func Equals(a, b common.Version) bool { return a == b } // IsAfter returns true if a is after b. This compares bytes from most significant // to least significant in "little-endian" order. func IsAfter(a, b common.Version) bool { return !IsBefore(a, b) && !Equals(a, b) } // EqualsOrIsAfter returns true if a is the same version as b or after. func EqualsOrIsAfter(a, b common.Version) bool { return !IsBefore(a, b) } ================================================ FILE: primitives/version/comparable_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package version_test import ( "slices" "testing" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) func TestIsBefore(t *testing.T) { t.Parallel() tests := []struct { name string a, b common.Version expected bool }{ { name: "equal versions", a: common.Version{1, 0, 0, 0}, b: common.Version{1, 0, 0, 0}, expected: false, }, { name: "clearly before", a: common.Version{1, 0, 0, 0}, b: common.Version{2, 0, 0, 0}, expected: true, }, { name: "clearly after", a: common.Version{2, 0, 0, 0}, b: common.Version{1, 0, 0, 0}, expected: false, }, { name: "minor version before", a: common.Version{1, 1, 0, 0}, b: common.Version{1, 2, 0, 0}, expected: true, }, { name: "patch version before", a: common.Version{1, 1, 1, 0}, b: common.Version{1, 1, 2, 0}, expected: true, }, { name: "beacon version before", a: version.Phase0(), b: version.Altair(), expected: true, }, { name: "beacon version before minor", a: version.Deneb(), b: version.Deneb1(), expected: true, }, { name: "beacon version after minor", a: common.Version{0x05, 0x00, 0x00, 0x00}, b: common.Version{0x04, 0x01, 0x00, 0x00}, expected: false, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() result := version.IsBefore(tc.a, tc.b) require.Equal(t, tc.expected, result) }) } } func TestIsBeforeOrEquals(t *testing.T) { t.Parallel() tests := []struct { name string a, b common.Version expected bool }{ { name: "equal versions", a: common.Version{1, 2, 1, 0}, b: common.Version{1, 2, 1, 0}, expected: true, }, { name: "clearly after", a: common.Version{2, 0, 0, 0}, b: common.Version{1, 0, 0, 0}, expected: false, }, { name: "minor version before", a: common.Version{1, 1, 0, 0}, b: common.Version{1, 2, 0, 0}, expected: true, }, { name: "patch version before", a: common.Version{1, 1, 1, 0}, b: common.Version{1, 1, 2, 0}, expected: true, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() result := version.IsBeforeOrEquals(tc.a, tc.b) require.Equal(t, tc.expected, result) }) } } func TestEquals(t *testing.T) { t.Parallel() tests := []struct { name string a, b common.Version expected bool }{ { name: "empty versions", a: common.Version{}, b: common.Version{}, expected: true, }, { name: "equal versions", a: common.Version{1, 0, 0, 0}, b: common.Version{1, 0, 0, 0}, expected: true, }, { name: "different major version", a: common.Version{1, 0, 0, 0}, b: common.Version{2, 0, 0, 0}, expected: false, }, { name: "different minor version", a: common.Version{1, 1, 0, 0}, b: common.Version{1, 2, 0, 0}, expected: false, }, { name: "different patch version", a: common.Version{1, 1, 1, 0}, b: common.Version{1, 1, 2, 0}, expected: false, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() result := version.Equals(tc.a, tc.b) require.Equal(t, tc.expected, result) }) } } func TestIsAfter(t *testing.T) { t.Parallel() tests := []struct { name string a, b common.Version expected bool }{ { name: "equal versions", a: common.Version{1, 0, 0, 0}, b: common.Version{1, 0, 0, 0}, expected: false, }, { name: "clearly after", a: common.Version{2, 0, 0, 0}, b: common.Version{1, 0, 0, 0}, expected: true, }, { name: "clearly before", a: common.Version{1, 0, 0, 0}, b: common.Version{2, 0, 0, 0}, expected: false, }, { name: "minor version after", a: common.Version{1, 2, 0, 0}, b: common.Version{1, 1, 0, 0}, expected: true, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() result := version.IsAfter(tc.a, tc.b) require.Equal(t, tc.expected, result) }) } } func TestEqualsOrIsAfter(t *testing.T) { t.Parallel() tests := []struct { name string a, b common.Version expected bool }{ { name: "equal versions", a: common.Version{1, 2, 1, 0}, b: common.Version{1, 2, 1, 0}, expected: true, }, { name: "clearly after", a: common.Version{2, 0, 0, 0}, b: common.Version{1, 0, 0, 0}, expected: true, }, { name: "minor version before", a: common.Version{1, 1, 0, 0}, b: common.Version{1, 2, 0, 0}, expected: false, }, { name: "patch version before", a: common.Version{1, 1, 1, 0}, b: common.Version{1, 1, 2, 0}, expected: false, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() result := version.EqualsOrIsAfter(tc.a, tc.b) require.Equal(t, tc.expected, result) }) } } func TestSort(t *testing.T) { t.Parallel() // Recommended function implementing cmp from the comments. cmp := func(a, b common.Version) int { if version.IsBefore(a, b) { return -1 } if version.Equals(a, b) { return 0 } return 1 } tests := []struct { name string input []common.Version expected []common.Version }{ { name: "already sorted", input: []common.Version{ version.Phase0(), version.Altair(), version.Bellatrix(), version.Capella(), }, expected: []common.Version{ version.Phase0(), version.Altair(), version.Bellatrix(), version.Capella(), }, }, { name: "reverse sorted", input: []common.Version{ version.Capella(), version.Bellatrix(), version.Altair(), version.Phase0(), }, expected: []common.Version{ version.Phase0(), version.Altair(), version.Bellatrix(), version.Capella(), }, }, { name: "mixed versions with minors", input: []common.Version{ version.Deneb1(), version.Deneb(), version.Phase0(), version.Electra(), version.Capella(), }, expected: []common.Version{ version.Phase0(), version.Capella(), version.Deneb(), version.Deneb1(), version.Electra(), }, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { t.Parallel() // Sort the input slice using the cmp function slices.SortFunc(tc.input, cmp) require.Equal(t, tc.expected, tc.input) }) } } ================================================ FILE: primitives/version/name.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package version import "github.com/berachain/beacon-kit/primitives/common" // Name returns the name of the fork version. func Name(v common.Version) string { switch v { case phase0: return "phase0" case altair: return "altair" case bellatrix: return "bellatrix" case capella: return "capella" case deneb: return "deneb" case deneb1: return "deneb1" case electra: return "electra" case electra1: return "electra1" case fulu: return "fulu" default: return "unknown" } } ================================================ FILE: primitives/version/supported.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package version import "github.com/berachain/beacon-kit/primitives/common" //nolint:gochecknoglobals // used for testing var supportedVersions = []common.Version{ deneb, deneb1, electra, electra1, fulu, } // GetSupportedVersions returns the supported versions of beacon-kit. // Primarily for testing so that we can easily extend test case coverage // with new versions by modifying the return value rather than each test. func GetSupportedVersions() []common.Version { return supportedVersions } ================================================ FILE: primitives/version/versions.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package version import ( "github.com/berachain/beacon-kit/primitives/common" ) // These are the versions of the Beacon Chain. // //nolint:gochecknoglobals // Kept as private to avoid modification of these variables at runtime. var ( // phase0 is the first version of the Beacon Chain. phase0 = common.Version{0x00, 0x00, 0x00, 0x00} // altair is the first hardfork of the Beacon Chain. altair = common.Version{0x01, 0x00, 0x00, 0x00} // bellatrix is the second hardfork of the Beacon Chain. bellatrix = common.Version{0x02, 0x00, 0x00, 0x00} // capella is the third hardfork of the Beacon Chain. capella = common.Version{0x03, 0x00, 0x00, 0x00} // deneb is the first version of the Deneb hardfork, used for genesis of Berachain mainnet. deneb = common.Version{0x04, 0x00, 0x00, 0x00} // deneb1 is the first hardfork of Deneb on Berachain mainnet. deneb1 = common.Version{0x04, 0x01, 0x00, 0x00} // electra is the first version of the Electra hardfork on Berachain mainnet. electra = common.Version{0x05, 0x00, 0x00, 0x00} // electra1 is the first hardfork of Electra on Berachain mainnet. electra1 = common.Version{0x05, 0x01, 0x00, 0x00} // fulu is the first version of the Fulu hardfork on Berachain mainnet. fulu = common.Version{0x06, 0x00, 0x00, 0x00} ) // Phase0 returns phase0 as a common.Version. func Phase0() common.Version { return phase0 } // Altair returns altair as a common.Version. func Altair() common.Version { return altair } // Bellatrix returns bellatrix as a common.Version. func Bellatrix() common.Version { return bellatrix } // Capella returns capella as a common.Version. func Capella() common.Version { return capella } // Deneb returns deneb as a common.Version. Deneb is the genesis fork version for Berachain // mainnet and Bepolia testnet. func Deneb() common.Version { return deneb } // Deneb1 returns deneb1 as a common.Version. func Deneb1() common.Version { return deneb1 } // Electra returns electra as a common.Version. func Electra() common.Version { return electra } // Electra1 returns electra1 as a common.Version. func Electra1() common.Version { return electra1 } // Fulu returns fulu as a common.Version. Fulu is the CL component of the // Fusaka hardfork on Berachain mainnet. func Fulu() common.Version { return fulu } ================================================ FILE: scripts/build/build.mk ================================================ #!/usr/bin/make -f ifeq ($(VERSION),) VERSION := $(shell git describe --tags --always --match "v*") endif COMMIT = $(shell git log -1 --format='%H') CURRENT_DIR = $(shell pwd) OUT_DIR ?= $(CURDIR)/build/bin TESTNAME = beacon TESTAPP = beacond TESTAPP_FILES_DIR = testing/files TESTAPP_CMD_DIR = cmd/$(TESTAPP) PROJECT_NAME = $(shell git remote get-url origin | xargs basename -s .git) # process build tags build_tags = netgo ifeq (legacy,$(findstring legacy,$(COSMOS_BUILD_OPTIONS))) build_tags += app_v1 endif # DB backend selection ifeq (cleveldb,$(findstring cleveldb,$(COSMOS_BUILD_OPTIONS))) build_tags += gcc endif ifeq (badgerdb,$(findstring badgerdb,$(COSMOS_BUILD_OPTIONS))) build_tags += badgerdb endif # handle rocksdb ifeq (rocksdb,$(findstring rocksdb,$(COSMOS_BUILD_OPTIONS))) CGO_ENABLED=1 build_tags += rocksdb grocksdb_clean_link endif # handle boltdb ifeq (boltdb,$(findstring boltdb,$(COSMOS_BUILD_OPTIONS))) build_tags += boltdb endif # always include pebble build_tags += pebbledb # always include blst build_tags += blst build_tags += bls12381 # always include cgo build_tags += cgo whitespace := whitespace += $(whitespace) comma := , build_tags_comma_sep := $(subst $(whitespace),$(comma),$(build_tags)) # process linker flags ldflags = -X github.com/cosmos/cosmos-sdk/version.Name=$(TESTNAME) \ -X github.com/cosmos/cosmos-sdk/version.AppName=$(TESTAPP) \ -X github.com/cosmos/cosmos-sdk/version.Version=$(VERSION) \ -X github.com/cosmos/cosmos-sdk/version.Commit=$(COMMIT) \ -X "github.com/cosmos/cosmos-sdk/version.BuildTags=$(build_tags_comma_sep)" ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS))) ldflags += -w -s endif ldflags += $(LDFLAGS) ldflags := $(strip $(ldflags)) build_tags += $(BUILD_TAGS) BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)' # check for nostrip option ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS))) BUILD_FLAGS += -trimpath endif # Check for debug option ifeq (debug,$(findstring debug,$(COSMOS_BUILD_OPTIONS))) BUILD_FLAGS += -gcflags "all=-N -l" endif # This allows us to reuse the build target steps for both go build and go install BUILD_TARGETS := build install ## Build: build: BUILD_ARGS=-o $(OUT_DIR)/$(TESTAPP) ## build `beacond` $(BUILD_TARGETS): $(OUT_DIR)/ @echo "Building ${TESTAPP_CMD_DIR}" @go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) $(TESTAPP_CMD_DIR)/*.go $(OUT_DIR)/: mkdir -p $(OUT_DIR)/ # Variables ARCH ?= $(shell uname -m) ifeq ($(ARCH),) ARCH = arm64 endif IMAGE_NAME ?= $(TESTAPP) # Docker Paths DOCKERFILE = ./Dockerfile # Go version extracted from go.mod (single source of truth). GO_VERSION := $(or \ $(shell awk '/^go /{print $$2}' $(CURDIR)/go.mod 2>/dev/null), \ $(shell sed -n 's/^go \(.*\)/\1/p' $(CURDIR)/go.mod 2>/dev/null)) ifeq ($(GO_VERSION),) $(error GO_VERSION could not be parsed from $(CURDIR)/go.mod) endif build-docker: ## build a docker image containing `beacond` @echo "Build a release docker image for the Cosmos SDK chain..." docker build \ --platform linux/$(ARCH) \ --build-arg GO_VERSION=$(GO_VERSION) \ --build-arg GIT_COMMIT=$(shell git rev-parse HEAD) \ --build-arg GIT_VERSION=$(VERSION) \ --build-arg GIT_BRANCH=$(shell git rev-parse --abbrev-ref HEAD) \ --build-arg GOOS=linux \ --build-arg GOARCH=$(ARCH) \ -f ${DOCKERFILE} \ -t $(IMAGE_NAME):$(VERSION) \ . push-docker-github: ## push the docker image to the ghcr registry @echo "Push the release docker image to the ghcr registry..." docker tag $(IMAGE_NAME):$(VERSION) ghcr.io/berachain/beacon-kit:$(VERSION) docker push ghcr.io/berachain/beacon-kit:$(VERSION) ================================================ FILE: scripts/build/codegen.mk ================================================ #!usr/bin/make -f GETH_GO_GENERATE_VERSION := $(shell grep 'github.com/ethereum/go-ethereum' go.mod | awk '{print $$2}') GOPATH = $(shell go env GOPATH) GETH_PKG_INCLUDE := $(GOPATH)/pkg/mod/github.com/ethereum/go-ethereum@$(GETH_GO_GENERATE_VERSION) ## Codegen: generate: ## generate all the code @$(MAKE) forge-build @for module in $(MODULES); do \ echo "Running go generate in $$module"; \ (cd $$module && \ GETH_PKG_INCLUDE=$(GETH_PKG_INCLUDE) go generate ./...) || exit 1; \ done @go run github.com/vektra/mockery/v2@v2.53.5 abigen-install: @go install github.com/ethereum/go-ethereum/cmd/abigen@latest generate-check: abigen-install @$(MAKE) forge-build @$(MAKE) generate @if [ -n "$$(git status --porcelain | grep -vE '\.ssz\.go$$')" ]; then \ echo "Generated files are not up to date"; \ git status -s | grep -vE '\.ssz\.go$$'; \ git diff -- . ':(exclude)*.ssz.go'; \ exit 1; \ fi ================================================ FILE: scripts/build/constants.mk ================================================ #!/usr/bin/make -f MODULES := $(shell find . -type f -name 'go.mod' -exec dirname {} \;) # Exclude root module MODULES := $(filter-out ./,$(MODULES)) CONTRACTS_DIR := ./contracts ================================================ FILE: scripts/build/devtools.mk ================================================ #!/usr/bin/make -f repo-rinse: | ## dangerous!!! make sure you know what you are doing git clean -xfd git submodule foreach --recursive git clean -xfd git submodule foreach --recursive git reset --hard git submodule update --init --recursive # tidy-sync-check runs `go mod tidy` and checks if go.mod/go.sum files are in sync with # the dependencies in the codebase. If they are not in sync, it will exit with a # non-zero status code. tidy-sync-check: @{ \ pre_tidy_diff=$$(git diff --ignore-space-change go.mod go.sum); \ go mod tidy; \ post_tidy_diff=$$(git diff --ignore-space-change go.mod go.sum); \ if [ "$$pre_tidy_diff" != "$$post_tidy_diff" ]; then \ echo "go.mod or go.sum changed after running 'go mod tidy'"; \ git diff go.mod go.sum; \ exit 1; \ fi; \ } ================================================ FILE: scripts/build/golines.sh ================================================ #!/usr/bin/env bash # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # Define the root directory of your Go project ROOT_DIR="." # Find all .go files in the project directory and its subdirectories, ignoring .pb.go and .pb_encoding.go files find "${ROOT_DIR}" -type f -name "*.go" ! -name "*.pb.go" ! -name "*_test.go" ! -name "*.pb_encoding.go" | while read -r file; do echo "Processing $file..." golines --reformat-tags --shorten-comments --write-output --max-len=140 "$file" done echo "✅ All files processed." ================================================ FILE: scripts/build/help.mk ================================================ #!/usr/bin/make -f GREEN := $(shell tput -Txterm setaf 2) YELLOW := $(shell tput -Txterm setaf 3) WHITE := $(shell tput -Txterm setaf 7) CYAN := $(shell tput -Txterm setaf 6) RESET := $(shell tput -Txterm sgr0) ## Help: help: ## Show this help. @echo '' @echo ' ${CYAN}🌈 Welcome to the BeaconKit Makefile Help Page 🌈${RESET}' @echo '' @echo 'Usage:' @echo ' ${YELLOW}make${RESET} ${GREEN}${RESET}' @echo '' @echo 'Targets:' @awk 'BEGIN {FS = ":.*?## "} { \ if (/^[a-zA-Z_-]+:.*?##.*$$/) {printf " ${YELLOW}%-20s${GREEN}%s${RESET}\n", $$1, $$2} \ else if (/^## .*$$/) {printf " ${CYAN}%s${RESET}\n", substr($$1,4)} \ }' $(MAKEFILE_LIST) ================================================ FILE: scripts/build/linting.mk ================================================ #!/usr/bin/make -f ## Linting: format: ## run all configured formatters @$(MAKE) license-fix forge-lint-fix golines golangci-fix star-fix lint: ## run all configured linters @$(MAKE) license markdownlint forge-lint golangci star-lint ################# # golangci-lint # ################# golangci-install: @go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest # TODO: Remove GODEBUG override once: https://github.com/golang/go/issues/68877 is resolved. golangci: golangci-install @echo "--> Running linter on all modules" (GODEBUG=gotypesalias=0 golangci-lint run --config $(ROOT_DIR)/.golangci.yaml --timeout=10m --concurrency 8) || exit 1; @printf "All modules complete\n" # TODO: Remove GODEBUG override once: https://github.com/golang/go/issues/68877 is resolved. golangci-fix: golangci-install @echo "--> Running linter with fixes on all modules" (GODEBUG=gotypesalias=0 golangci-lint run --config $(ROOT_DIR)/.golangci.yaml --timeout=10m --fix --concurrency 8) || exit 1; @printf "All modules complete\n" ################# # golines # ################# golines-install: @go install github.com/segmentio/golines@latest golines: golines-install @echo "--> Running golines" @./scripts/build/golines.sh ################# # license # ################# license-install: @go install github.com/google/addlicense@latest license: license-install @echo "--> Running addlicense with -check" (addlicense -check -v -f $(ROOT_DIR)/LICENSE.header -ignore "**/*.toml" -ignore "contracts/**" -ignore ".idea/**" .) || exit 1; @printf "License check complete\n" license-fix: license-install echo "--> Running addlicense" (addlicense -v -f $(ROOT_DIR)/LICENSE.header -ignore "**/*.toml" -ignore "contracts/**" -ignore ".idea/**" .) || exit 1; @printf "License check complete\n" ################# # nilaway # ################# nilaway-install: @go install go.uber.org/nilaway/cmd/nilaway@latest nilaway: nilaway-install @echo "--> Running nilaway" (nilaway -test=false -exclude-errors-in-files "gethlib/deposit/","gethlib/ssztest/" -v ./...) || exit 1; @printf "Nilaway check complete\n" ################# # gosec # ################# gosec-install: @go install github.com/securego/gosec/v2/cmd/gosec@latest gosec: gosec-install @echo "--> Running gosec" @gosec ./... ################# # vulncheck # ################# vulncheck: @echo "--> Running govulncheck" @export GOTOOLCHAIN=go$$(sed -n 's/^go //p' go.mod) && \ go run golang.org/x/vuln/cmd/govulncheck@latest $$(go list ./... | grep -v '/testing/') ################# # slither # ################# slither: chmod -R o+rw ./contracts docker run \ -t \ --platform linux/amd64 \ -v ./contracts:/contracts:rw \ trailofbits/eth-security-toolbox:edge \ /bin/bash -c "cd /contracts/ && slither ./." ################# # markdown-lint # ################# markdownlint: @echo "--> Running markdownlint" @docker run --rm -v $(ROOT_DIR):/workspace -w /workspace -t markdownlint/markdownlint:latest --git-recurse **/**.md ################# # all ci linters # ################# lint-ci: lint slither gosec vulncheck nilaway markdownlint generate-check \ tidy-sync-check test-unit-cover test-unit-bench test-unit-fuzz \ test-forge-cover test-forge-fuzz ================================================ FILE: scripts/build/proto_generate_pulsar.sh ================================================ # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # this script is for generating protobuf files for the new google.golang.org/protobuf API set -eo pipefail protoc_install_gopulsar() { go install github.com/cosmos/cosmos-proto/cmd/protoc-gen-go-pulsar@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest } protoc_install_gopulsar echo "Cleaning API directory" mkdir -p cosmos/api (cd cosmos/api; find ./ -type f \( -iname \*.pulsar.go -o -iname \*.pb.go -o -iname \*.cosmos_orm.go -o -iname \*.pb.gw.go \) -delete; find . -empty -type d -delete; cd ../../..) echo "Generating API module" (cd node-core/components/module/proto; buf generate --template buf.gen.pulsar.yaml; cd ../) # # cp -r api cosmos # cp -r api/mod/node-core/pkg/components/module/* mod/node-core/pkg/components/module/api # rm -rf api # # rm -rf cosmos/api/ethereum # # rm -rf cosmos/api/types ================================================ FILE: scripts/build/protobuf.mk ================================================ #!/usr/bin/make -f protoImageName := "ghcr.io/cosmos/proto-builder" protoImageVersion := "0.14.0" modulesProtoDir := "node-core/components/module/proto" ## Protobuf: proto: ## run all the proto tasks @$(MAKE) proto-build proto-build: ## build the proto files @docker run --rm -v ${CURRENT_DIR}:/workspace --workdir /workspace $(protoImageName):$(protoImageVersion) sh ./scripts/build/proto_generate_pulsar.sh proto-clean: ## clean the proto files @find . -name '*.pb.go' -delete @find . -name '*.pb.gw.go' -delete ================================================ FILE: scripts/build/release.mk ================================================ #!/usr/bin/make -f RELEASE_TARGETS := build-linux-amd64 build-linux-arm64 build-darwin-arm64 define build_release echo "Building beacond for $(shell echo $(4) | tr '/' '-')-$(1)-$(2)-..." GOOS=$(1) GOARCH=$(2) CGO_ENABLED=$(3) \ cd ${CURRENT_DIR}/$(TESTAPP_CMD_DIR) && \ go build -mod=readonly $(BUILD_FLAGS) -o $(OUT_DIR)/beacond-$(shell echo $(4) | tr '/' '-')-$(1)-$(2) ./. endef build-linux-amd64-%: $(call build_release,linux,amd64,1,$*) build-linux-arm64-%: $(call build_release,linux,arm64,1,$*) build-darwin-arm64-%: $(call build_release,darwin,arm64,1,$*) ================================================ FILE: scripts/build/testing.mk ================================================ #!/usr/bin/make -f ############################################################################### ### Tests & Simulation ### ############################################################################### # ask_reset_dir_func checks if the directory passed in exists, and if so asks the user whether it # should delete it. Note that on linux, docker may have created the directory with root # permissions, so we may need to ask the user to delete it with sudo define ask_reset_dir_func @abs_path=$(abspath $(1)); \ if test -d "$$abs_path"; then \ read -p "Directory '$$abs_path' exists. Do you want to delete it? (y/n): " confirm && \ if [ "$$confirm" = "y" ]; then \ echo "Deleting directory '$$abs_path'..."; \ rm -rf "$$abs_path" 2>/dev/null || sudo rm -rf "$$abs_path"; \ if test -d "$$abs_path"; then \ echo "Failed to delete directory '$$abs_path'."; \ exit 1; \ fi; \ fi \ else \ echo "Directory '$$abs_path' does not exist."; \ fi endef ################# # Local # ################# # Use the genesis file from the beacond folder as it has been modified by # beacond genesis set-deposit-storage. ETH_GENESIS_PATH = ${HOMEDIR}/eth-genesis.json HOMEDIR = .tmp/beacond JWT_PATH = ${TESTAPP_FILES_DIR}/jwt.hex ETH_DATA_DIR = .tmp/eth-home ## Start an ephemeral `beacond` node. Must be run before running the EL to ## configure the deposit contract storage slots pre-genesis. start: @JWT_SECRET_PATH=$(JWT_PATH) \ ${TESTAPP_FILES_DIR}/entrypoint.sh devnet # URLs used for dialing the eth client IPC_PATH = .tmp/eth-home/eth-engine.ipc IPC_PREFIX = ipc:// ## Start an ephemeral `beacond` node with a custom chain spec. The path to the chain spec ## file must be passed as an argument. Usage: make start-custom /path/to/chain/spec.toml start-custom: @JWT_SECRET_PATH=$(JWT_PATH) \ ${TESTAPP_FILES_DIR}/entrypoint.sh file $(word 2,$(MAKECMDGOALS)) ## Start an ephemeral `reth` node start-reth: $(call ask_reset_dir_func, $(ETH_DATA_DIR)) @docker run \ -p 30303:30303 \ -p 8545:8545 \ -p 8551:8551 \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-reth:nightly node \ --chain ${ETH_GENESIS_PATH} \ --http \ --http.addr "0.0.0.0" \ --http.api eth,net \ --authrpc.addr "0.0.0.0" \ --authrpc.jwtsecret $(JWT_PATH) \ --datadir ${ETH_DATA_DIR} \ --ipcpath ${IPC_PATH} \ --engine.persistence-threshold 0 \ --engine.memory-block-buffer-target 0 ## Start an ephemeral `geth` node with docker start-geth: $(call ask_reset_dir_func, $(ETH_DATA_DIR)) docker run \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-geth:latest init \ --datadir ${ETH_DATA_DIR} \ ${ETH_GENESIS_PATH} docker run \ -p 30303:30303 \ -p 8545:8545 \ -p 8551:8551 \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-geth:latest \ --syncmode=full \ --http \ --http.addr 0.0.0.0 \ --http.api eth,net \ --authrpc.addr 0.0.0.0 \ --authrpc.jwtsecret $(JWT_PATH) \ --authrpc.vhosts "*" \ --datadir ${ETH_DATA_DIR} \ --ipcpath ${IPC_PATH} ################# # Bepolia # ################# BEPOLIA_NETWORK_FILES_DIR = ${TESTAPP_FILES_DIR}/../networks/80069 BEPOLIA_ETH_GENESIS_PATH = ${BEPOLIA_NETWORK_FILES_DIR}/eth-genesis.json start-bepolia: @JWT_SECRET_PATH=$(JWT_PATH) \ ${TESTAPP_FILES_DIR}/entrypoint.sh testnet start-geth-bepolia: $(call ask_reset_dir_func, $(ETH_DATA_DIR)) docker run \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ --rm -v $(PWD)/${BEPOLIA_NETWORK_FILES_DIR}:/${BEPOLIA_NETWORK_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-geth:latest init \ --datadir ${ETH_DATA_DIR} \ ${BEPOLIA_ETH_GENESIS_PATH} @# Read bootnodes from the file; the file is mounted into the container. @bootnodes=`cat $(PWD)/$(BEPOLIA_NETWORK_FILES_DIR)/el-bootnodes.txt`; \ echo "Using bootnodes: $$bootnodes"; \ docker run \ -p 30303:30303 \ -p 8545:8545 \ -p 8551:8551 \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ --rm -v $(PWD)/${BEPOLIA_NETWORK_FILES_DIR}:/${BEPOLIA_NETWORK_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-geth:latest \ --http \ --http.addr 0.0.0.0 \ --http.api eth,net \ --authrpc.addr 0.0.0.0 \ --authrpc.jwtsecret $(JWT_PATH) \ --authrpc.vhosts "*" \ --datadir ${ETH_DATA_DIR} \ --ipcpath ${IPC_PATH} \ --syncmode=full \ --bootnodes $$bootnodes start-reth-bepolia: $(call ask_reset_dir_func, $(ETH_DATA_DIR)) @trustedpeers=`cat $(PWD)/$(BEPOLIA_NETWORK_FILES_DIR)/el-peers.txt`; \ echo "Using truted peers: $$trustedpeers"; \ docker run \ -p 30303:30303 \ -p 8545:8545 \ -p 8551:8551 \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ --rm -v $(PWD)/${BEPOLIA_NETWORK_FILES_DIR}:/${BEPOLIA_NETWORK_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-reth:nightly node \ --chain ${BEPOLIA_ETH_GENESIS_PATH} \ --http \ --http.addr "0.0.0.0" \ --http.api eth,net \ --authrpc.addr "0.0.0.0" \ --authrpc.jwtsecret $(JWT_PATH) \ --datadir ${ETH_DATA_DIR} \ --ipcpath ${IPC_PATH} \ --trusted-peers $$trustedpeers ################# # Mainnet # ################# MAINNET_NETWORK_FILES_DIR = ${TESTAPP_FILES_DIR}/../networks/80094 MAINNET_ETH_GENESIS_PATH = ${MAINNET_NETWORK_FILES_DIR}/eth-genesis.json start-mainnet: @JWT_SECRET_PATH=$(JWT_PATH) \ ${TESTAPP_FILES_DIR}/entrypoint.sh mainnet # NOTE: By default this will use the EL peers as your bootnodes. If you want specific # discovery bootnodes by region, refer to testing/networks/80094/el-bootnodes.txt start-geth-mainnet: $(call ask_reset_dir_func, $(ETH_DATA_DIR)) docker run \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ --rm -v $(PWD)/${MAINNET_NETWORK_FILES_DIR}:/${MAINNET_NETWORK_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-geth:latest init \ --datadir ${ETH_DATA_DIR} \ ${MAINNET_ETH_GENESIS_PATH} @# Read bootnodes from the file; the file is mounted into the container. @bootnodes=`cat $(PWD)/$(MAINNET_NETWORK_FILES_DIR)/el-peers.txt`; \ echo "Using bootnodes: $$bootnodes"; \ docker run \ -p 30303:30303 \ -p 8545:8545 \ -p 8551:8551 \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ --rm -v $(PWD)/${MAINNET_NETWORK_FILES_DIR}:/${MAINNET_NETWORK_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-geth:latest \ --http \ --http.addr 0.0.0.0 \ --http.api eth,net \ --authrpc.addr 0.0.0.0 \ --authrpc.jwtsecret $(JWT_PATH) \ --authrpc.vhosts "*" \ --datadir ${ETH_DATA_DIR} \ --ipcpath ${IPC_PATH} \ --syncmode=full \ --bootnodes $$bootnodes start-reth-mainnet: $(call ask_reset_dir_func, $(ETH_DATA_DIR)) @trustedpeers=`cat $(PWD)/$(MAINNET_NETWORK_FILES_DIR)/el-peers.txt`; \ echo "Using truted peers: $$trustedpeers"; \ docker run \ -p 30303:30303 \ -p 8545:8545 \ -p 8551:8551 \ --rm -v $(PWD)/${TESTAPP_FILES_DIR}:/${TESTAPP_FILES_DIR} \ --rm -v $(PWD)/${MAINNET_NETWORK_FILES_DIR}:/${MAINNET_NETWORK_FILES_DIR} \ -v $(PWD)/.tmp:/.tmp \ ghcr.io/berachain/bera-reth:nightly node \ --chain ${MAINNET_ETH_GENESIS_PATH} \ --http \ --http.addr "0.0.0.0" \ --http.api eth,net \ --authrpc.addr "0.0.0.0" \ --authrpc.jwtsecret $(JWT_PATH) \ --datadir ${ETH_DATA_DIR} \ --ipcpath ${IPC_PATH} \ --trusted-peers $$trustedpeers ################# # Testing # ################# SHORT_FUZZ_TIME=10s MEDIUM_FUZZ_TIME=30s LONG_FUZZ_TIME=3m # Define a function to filter out lines with "/testing/", "/mock/", "/mocks/", or ".mock.go" define FILTER_COVERAGE grep -Ev '(/testing/|/mock/|/mocks/|\.mock\.go)' $(1) > $(2) endef test: @$(MAKE) test-unit test-forge-fuzz test-unit-no-coverage: ## run golang unit tests @echo "Running unit tests..." @go list -f '{{.Dir}}/...' -m | xargs \ go test -race -tags bls12381,test coverage-summary: test-unit test-simulated @echo "Merging coverage reports..." @go install github.com/wadey/gocovmerge@latest @gocovmerge test-unit-cover.txt test-simulated.txt > coverage-merged.txt @echo "Coverage Summary:" @go tool cover -html=coverage-merged.txt test-unit-cover: test-unit test-simulated test-unit-quick ## run golang unit tests with coverage test-unit: @echo "Running unit tests with coverage and race checks..." @go list -f '{{.Dir}}/...' -m | xargs \ go test -race -covermode=atomic -coverpkg=github.com/berachain/beacon-kit/... -coverprofile=temp-test-unit-cover.txt -tags bls12381,test # Filter out any coverage lines from the testing directory $(call FILTER_COVERAGE, temp-test-unit-cover.txt, test-unit-cover.txt) @rm temp-test-unit-cover.txt test-unit-quick: ## run quick tests. We run these without coverage as covermode=atomic is too slow and coverage here provides little value @echo "Running 'quick' tests..." @go list -f '{{.Dir}}/testing/quick' -m | xargs \ go test -v -tags quick test-simulated: ## run simulation tests @echo "Running simulation tests with coverage" @go list -f '{{.Dir}}/testing/simulated' -m | xargs \ go test -cover -covermode=atomic -coverpkg=github.com/berachain/beacon-kit/... -coverprofile=temp-test-simulated.txt -tags simulated -v # Filter out any coverage lines from the testing directory $(call FILTER_COVERAGE, temp-test-simulated.txt, test-simulated.txt) @rm temp-test-simulated.txt test-unit-bench: ## run golang unit benchmarks @echo "Running unit tests with benchmarks..." @go list -f '{{.Dir}}/...' -m | xargs \ go test -bench=. -run=^$ -benchmem -tags bls12381,test # On MacOS, if there is a linking issue on the fuzz tests, # use the old linker with flags -ldflags=-extldflags=-Wl,-ld_classic test-unit-fuzz: ## run fuzz tests @echo "Running fuzz tests with coverage..." go test -run ^FuzzPayloadIDCacheBasic -fuzztime=${SHORT_FUZZ_TIME} github.com/berachain/beacon-kit/payload/cache go test -run ^FuzzPayloadIDInvalidInput -fuzztime=${SHORT_FUZZ_TIME} github.com/berachain/beacon-kit/payload/cache go test -run ^FuzzPayloadIDCacheConcurrency -fuzztime=${SHORT_FUZZ_TIME} github.com/berachain/beacon-kit/payload/cache go test -run ^FuzzHashTreeRoot -fuzztime=${MEDIUM_FUZZ_TIME} github.com/berachain/beacon-kit/primitives/merkle test-e2e: ## run all e2e tests (standard) @$(MAKE) build-docker VERSION=kurtosis-local test-e2e-no-build test-e2e-no-build: @$(MAKE) test-e2e-standard-no-build test-e2e-standard: ## run standard e2e tests @$(MAKE) build-docker VERSION=kurtosis-local test-e2e-standard-no-build test-e2e-standard-no-build: go test -timeout 0 -tags e2e,bls12381,test ./testing/e2e/standard/. -v test-e2e-4844: ## run e2e blob tests @$(MAKE) build-docker VERSION=kurtosis-local test-e2e-4844-no-build test-e2e-4844-no-build: go test -timeout 0 -tags e2e,bls12381,test ./testing/e2e/standard/. -v -testify.m Test4844Live test-e2e-deposits: ## run e2e deposit tests @$(MAKE) build-docker VERSION=kurtosis-local test-e2e-deposits-no-build test-e2e-deposits-no-build: go test -timeout 0 -tags e2e,bls12381,test ./testing/e2e/standard/. -v -testify.m TestDepositRobustness ================================================ FILE: scripts/rollback_cl.sh ================================================ #!/usr/bin/env bash # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # fail immediately on errors including any commands in a pipeline set -Eeuo pipefail # include linenumber and command if an error occurs trap 'echo "Script failed at line $LINENO when running command: \"$BASH_COMMAND\""' ERR usage() { echo "Usage: $(basename "$0")" echo "" echo "This script compares the Consensus Layer (CL) height with the Execution Layer (EL) height," echo "and performs rollbacks on CL until it is at or below the EL height." echo "" echo "Environment Variables:" echo " BEACOND_BIN (default: 'beacond') - Path to the beacon-kit binary." echo " BEACOND_HOME (default: '~/.beacond') - Path to the beacon-kit home directory." echo " EL_RPC_URL (default: '127.0.0.1:8545') - Execution Layer RPC endpoint." echo "" echo "Example usage:" echo " BEACOND_HOME=/data/.beacond ./$(basename "$0")" echo " BEACOND_BIN=/custom/path/beacond ./$(basename "$0")" exit 0 } if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then usage fi BEACOND_BIN="${BEACOND_BIN:-beacond}" BEACOND_HOME="${BEACOND_HOME:-$HOME/.beacond}" EL_RPC_URL="${EL_RPC_URL:-127.0.0.1:8545}" echo "Starting rollback process:" echo "- BEACOND_BIN: $BEACOND_BIN" echo "- BEACOND_HOME: $BEACOND_HOME" echo "- EL_RPC_URL: $EL_RPC_URL" # Validate BEACOND_HOME already exists if [[ ! -d "$BEACOND_HOME" ]]; then echo "Error: BEACOND_HOME is not a valid directory." exit 1 fi # Validate BEACOND_BIN (must be in PATH or specified) if ! "$BEACOND_BIN" version &>/dev/null; then echo "Error: BEACOND_BIN is not a valid executable or not found." exit 1 fi echo "[Fetching EL height...]" EL_HEX=$(curl -s -X POST --location "$EL_RPC_URL" --header 'Content-Type: application/json' --data '{ "jsonrpc":"2.0", "method":"eth_getBlockByNumber", "params":["latest", false], "id":1 }' | jq -r .result.number) [[ -z "$EL_HEX" || "$EL_HEX" == "null" || "$EL_HEX" -le 0 ]] && echo "Error: Invalid Execution Layer height (EL). EL must be greater than zero." && exit 1 EL=$((${EL_HEX})) echo "-> EL height: $EL ($EL_HEX)" echo "[Fetching CL height...]" ROLLBACK_OUTPUT=$("$BEACOND_BIN" rollback --home="$BEACOND_HOME") CL=$(echo "$ROLLBACK_OUTPUT" | sed -n 's/.*height=\([0-9][0-9]*\).*/\1/p') echo "-> CL height: $CL" # Check if CL is already at or below EL if (( CL <= EL )); then echo "No rollback needed. Consensus Layer height is already at or below Execution Layer height." exit 0 fi # Start the rollback loop from CL down to EL echo "[Starting rolling back of CL]" while true; do echo "Rolling back CL height $CL..." ROLLBACK_OUTPUT=$("$BEACOND_BIN" rollback --hard --home="$BEACOND_HOME") CL=$(echo "$ROLLBACK_OUTPUT" | sed -n 's/.*height=\([0-9][0-9]*\).*/\1/p') echo "New CL height after rollback: $CL (required height: $EL)" if (( CL <= EL )); then echo "Reached target Execution Layer height. Exiting." break fi done echo "Rollback process completed successfully." ================================================ FILE: state-transition/core/README.md ================================================ # State Processor ## Validators handling As a general principle, BeaconKit strives to keep validators handling aligned with Ethereum 2.0 specs. There currently two notable exceptions to this principle: - BeaconKit **does not** enforce a cap on validators churn, neither in the activation nor in the exit queue. - BeaconKit **does** enforce an explicit cap on the validators set. - BeaconKit **does not** currently support voluntary withdrawals. We list below a few relevant facts. ## `Balance` and `EffectiveBalance` BeaconKit distingishes a validator `Balance` and a validator `EffectiveBalance`. - `Balance` is updated slot by slot, when a deposit in made over the deposit contract and events are subsequently processed by BeaconKit. - `Balance` can increase only in multiples of `MinDepositAmount`, which is specified in the deposit contract. There is no cap on the `Balance`. - `EffectiveBalance` is updated at the turn of every epoch. - `EffectiveBalance` is enforced to be a multiple of `EffectiveBalanceIncrement` - `EffectiveBalance` is capped at `MaxEffectiveBalance`. Any `Balance` in excess of `MaxEffectiveBalance` is automatically withdrawn. - `EffectiveBalance` is aligned to `Balance`, within the constrains listed above, and accounting for hysteresys, at the turn of every epoch, via [`processEffectiveBalanceUpdates`](./state_processor.go#L491) ## Validator lifecycle Validators are created by a deposit made to the deposit contract, as soon as the corresponding event is emitted. Say a deposit is made at slot `S`, epoch `N`, that creates a validator. The funds deposited will be locked and the validator will stay inactive until the a minimum staking balance is hit. The minimum staking balance is set to `EjectionBalance + EffectiveBalanceIncrement` to account for hysteresys. However if the active validator set has already reached the `ValidatorSetCap`, a new prospective validator must deposit more funds than the effective balance of the active validator with the lowest stake. So let's assumed that `S`, epoch `N`, is the slot where finally the validator `Balance` equals the minimum required for staking (one or multiple deposits may have been done to get there). Then: - The validator is marked as `EligibleForActivationQueue` as soon as epoch `N+1` starts. This is guaranteed since there is no cap on the activation queue size. - The validator is marked as active as soon as epoch `N+2` starts. However - if the size of validator set goes beyond the `ValidatorSetCap` enough validators with the lowest stake are marked for eviction, to make the cap be fullfilled. Validators are sorted by increasing `EffectiveBalance` and ties are broken ordering their pub keys alphabetically. - BeaconKit does not currently support voluntary withdrawals, nor slashing or inactivity leaks. Therefore a validator keeps validating indefinitely. - The only case in which a validator may be evicted from the validator set (and its funds returned) is when `ValidatorSetCap` is hit and a validator with greater priority is added (i.e. with larger `EffectiveBalance` or equal `EffectiveBalance` and larger PubKey in alphabetical order). - Once a validator is marked as active, `CometBFT` consensus will reach it out for block proposals, validations and voting. The higher a validator `EffectiveBalance`, the higher its voting power the frequency it is polled for block proposal. Now say the validator is marked for exit (i.e. a result of validator set cap being hit or a full withdrawal request), at epoch `M`. Then its funds will be fully withdrawn at epoch `M+MinValidatorWithdrawabilityDelay` during and after electra, at epoch `M+1` before electra. BeaconKit does not currently enforce a cap on validators churn. ================================================ FILE: state-transition/core/core_test.go ================================================ //go:build test // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core_test import ( "strconv" "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" gethtypes "github.com/berachain/beacon-kit/gethlib/types" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/state-transition/core" statetransition "github.com/berachain/beacon-kit/testing/state-transition" "github.com/stretchr/testify/require" ) func setupChain(t *testing.T) chain.Spec { t.Helper() chainSpec, err := spec.DevnetChainSpec() require.NoError(t, err) return chainSpec } //nolint:unused // may be used in the future. func progressStateToSlot( t *testing.T, beaconState *statetransition.TestBeaconStateT, slot math.U64, ) { t.Helper() if slot == math.U64(0) { t.Fatal("for genesis slot, use InitializeBeaconStateFromEth1") } err := beaconState.SetSlot(slot) require.NoError(t, err) err = beaconState.SetLatestBlockHeader(types.NewBeaconBlockHeader( slot, math.U64(0), common.Root{}, common.Root{}, common.Root{}, )) require.NoError(t, err) } func buildNextBlock( t *testing.T, cs chain.Spec, beaconState *statetransition.TestBeaconStateT, eth1Data *types.Eth1Data, timestamp math.U64, blockDeposits types.Deposits, executionRequests *types.ExecutionRequests, withdrawals ...*engineprimitives.Withdrawal, ) *types.BeaconBlock { t.Helper() require.NotNil(t, cs) // first update state root, similarly to what we do in processSlot parentBlkHeader, err := beaconState.GetLatestBlockHeader() require.NoError(t, err) root := beaconState.HashTreeRoot() parentBlkHeader.SetStateRoot(root) // build the block fv := cs.ActiveForkVersionForTimestamp(timestamp) versionable := types.NewVersionable(fv) blk, err := types.NewBeaconBlockWithVersion( parentBlkHeader.GetSlot()+1, parentBlkHeader.GetProposerIndex(), parentBlkHeader.HashTreeRoot(), fv, ) require.NoError(t, err) // build the payload payload := &types.ExecutionPayload{ Versionable: versionable, Timestamp: timestamp, ExtraData: []byte("testing"), Transactions: [][]byte{}, Withdrawals: withdrawals, BaseFeePerGas: math.NewU256(0), } parentBeaconBlockRoot := parentBlkHeader.HashTreeRoot() var ethBlk *gethtypes.Block if version.IsBefore(fv, version.Electra()) { ethBlk, _, err = types.MakeEthBlock(payload, parentBeaconBlockRoot, nil, nil) require.NoError(t, err) } else { encodedER, erErr := types.GetExecutionRequestsList(executionRequests) require.NoError(t, erErr) require.NotNil(t, encodedER) parentProposerPubkey, errPk := beaconState.ParentProposerPubkey(timestamp) require.NoError(t, errPk) ethBlk, _, err = types.MakeEthBlock(payload, parentBeaconBlockRoot, encodedER, parentProposerPubkey) require.NoError(t, err) } payload.BlockHash = common.ExecutionHash(ethBlk.Hash()) require.NoError(t, err) blk.Body = &types.BeaconBlockBody{ Versionable: versionable, ExecutionPayload: payload, Eth1Data: eth1Data, Deposits: blockDeposits, } if version.EqualsOrIsAfter(fv, version.Electra()) { err = blk.Body.SetExecutionRequests(executionRequests) require.NoError(t, err) } return blk } func generateTestExecutionAddress( t *testing.T, rndSeed int, ) (types.WithdrawalCredentials, int) { t.Helper() addrStr := strconv.Itoa(rndSeed) addrBytes := bytes.ExtendToSize([]byte(addrStr), bytes.B20Size) execAddr, err := bytes.ToBytes20(addrBytes) require.NoError(t, err) rndSeed++ return types.NewCredentialsFromExecutionAddress( common.ExecutionAddress(execAddr), ), rndSeed } func generateTestPK(t *testing.T, rndSeed int) (bytes.B48, int) { t.Helper() keyStr := strconv.Itoa(rndSeed) keyBytes := bytes.ExtendToSize([]byte(keyStr), bytes.B48Size) key, err := bytes.ToBytes48(keyBytes) require.NoError(t, err) rndSeed++ return key, rndSeed } func moveToEndOfEpoch( t *testing.T, tip *types.BeaconBlock, cs chain.Spec, sp *statetransition.TestStateProcessorT, st *statetransition.TestBeaconStateT, ctx core.ReadOnlyContext, depRoot common.Root, ) *types.BeaconBlock { t.Helper() blk := tip currEpoch := cs.SlotToEpoch(blk.GetSlot()) for currEpoch == cs.SlotToEpoch(blk.GetSlot()+1) { timestamp := blk.Body.ExecutionPayload.Timestamp + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), timestamp, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(timestamp), ) vals, err := sp.Transition(ctx, st, blk) require.NoError(t, err) require.Empty(t, vals) // no vals changes expected before next epoch } return blk } ================================================ FILE: state-transition/core/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import "github.com/berachain/beacon-kit/errors" var ( // ErrValSetCapExceeded is returned when the number of genesis deposits // exceeds the validator set cap. ErrValSetCapExceeded = errors.New("validator set cap exceeded at genesis") // ErrBlockSlotTooLow is returned when the block slot is too low. ErrBlockSlotTooLow = errors.New("block slot too low") // ErrSlotMismatch is returned when the slot in a block header does not // match the expected value. ErrSlotMismatch = errors.New("slot mismatch") // ErrProposerMismatch is returned when block builder does not match // with the proposer reported by consensus. ErrProposerMismatch = errors.New("proposer key mismatch") ErrDepositsRootMismatch = errors.New("deposits root mismatch") // ErrDepositsLengthMismatch is returned when length of deposits // listed in block is different from deposits from store. ErrDepositsLengthMismatch = errors.New("deposits lengths mismatched") // ErrDepositMismatch is returned when a specific deposit listed in // block is different from the correspondent one from store. ErrDepositMismatch = errors.New("deposit mismatched") // ErrDepositIndexOutOfOrder is returned when deposits are not in // contiguous order. ErrDepositIndexOutOfOrder = errors.New("deposit index out of order") // ErrParentRootMismatch is returned when the parent root in an execution // payload does not match the expected value. ErrParentRootMismatch = errors.New("parent root mismatch") // ErrParentPayloadHashMismatch is returned when the parent hash of an // execution payload does not match the expected value. ErrParentPayloadHashMismatch = errors.New("payload parent hash mismatch") // ErrRandaoMixMismatch is returned when the randao mix in an execution // payload does not match the expected value. ErrRandaoMixMismatch = errors.New("randao mix mismatch") // ErrExceedsBlockDepositLimit is returned when the block exceeds the // deposit limit. ErrExceedsBlockDepositLimit = errors.New("block exceeds deposit limit") // ErrRewardsLengthMismatch is returned when the length of the rewards // in a block does not match the expected value. ErrRewardsLengthMismatch = errors.New("rewards length mismatch") // ErrPenaltiesLengthMismatch is returned when the length of the penalties // in a block does not match the expected value. ErrPenaltiesLengthMismatch = errors.New("penalties length mismatch") // ErrExceedsBlockBlobLimit is returned when the block exceeds the blob // limit. ErrExceedsBlockBlobLimit = errors.New("block exceeds blob limit") // ErrSlashedProposer is returned when a block is processed in which // the proposer is slashed. ErrSlashedProposer = errors.New( "attempted to process a block with a slashed proposer") // ErrStateRootMismatch is returned when the state root in a block header // does not match the expected value. ErrStateRootMismatch = errors.New("state root mismatch") // ErrExceedMaximumWithdrawals is returned when the number of withdrawals // in a block exceeds the maximum allowed. ErrExceedMaximumWithdrawals = errors.New("exceeds maximum withdrawals") // ErrZeroWithdrawals is returned when the number of withdrawals in a // block is zero. At least the EVM inflation withdrawal is always expected. ErrZeroWithdrawals = errors.New("zero withdrawals") // ErrNumWithdrawalsMismatch is returned when the number of withdrawals // in a block does not match the expected value. ErrNumWithdrawalsMismatch = errors.New("number of withdrawals mismatch") // ErrFirstWithdrawalNotEVMInflation is returned when the first withdrawal // in a block is not the EVM inflation withdrawal. ErrFirstWithdrawalNotEVMInflation = errors.New( "first withdrawal is not the EVM inflation withdrawal", ) // ErrWithdrawalMismatch is returned when the withdrawals in a payload do // not match the local state's expected value. ErrWithdrawalMismatch = errors.New( "withdrawal mismatch between local state and payload") ) ================================================ FILE: state-transition/core/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "context" "github.com/berachain/beacon-kit/chain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/delay" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) type ReadOnlyBeaconState interface { GetLatestExecutionPayloadHeader() (*ctypes.ExecutionPayloadHeader, error) GetSlot() (math.Slot, error) GetEpoch() (math.Epoch, error) GetRandaoMixAtIndex(uint64) (common.Bytes32, error) } // ReadOnlyContext defines an interface for managing state transition context. type ReadOnlyContext interface { ConsensusCtx() context.Context ConsensusTime() math.U64 ProposerAddress() []byte VerifyPayload() bool VerifyRandao() bool VerifyResult() bool MeterGas() bool } // ExecutionEngine is the interface for the execution engine. type ExecutionEngine interface { NotifyForkchoiceUpdate( // added to simplify mocks ctx context.Context, req *ctypes.ForkchoiceUpdateRequest, ) (*engineprimitives.PayloadID, error) // NotifyNewPayload notifies the execution client of the new payload. NotifyNewPayload( ctx context.Context, req ctypes.NewPayloadRequest, retryOnSyncingStatus bool, ) error } // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { SetGauge(key string, value int64, args ...string) // IncrementCounter increments the counter identified by // the provided key. IncrementCounter(key string, args ...string) } type ChainSpec interface { chain.HysteresisSpec chain.BalancesSpec chain.DepositSpec chain.ForkSpec chain.DomainTypeSpec chain.WithdrawalsSpec delay.ConfigGetter SlotsPerEpoch() uint64 SlotToEpoch(slot math.Slot) math.Epoch SlotsPerHistoricalRoot() uint64 EpochsPerHistoricalVector() uint64 GenesisForkVersion() common.Version ActiveForkVersionForTimestamp(timestamp math.U64) common.Version ValidatorSetCap() uint64 HistoricalRootsLimit() uint64 IsMainnet() bool } ================================================ FILE: state-transition/core/metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "github.com/berachain/beacon-kit/primitives/math" ) type stateProcessorMetrics struct { // sink is the sink for the metrics. sink TelemetrySink } // newStateProcessorMetrics creates a new stateProcessorMetrics. func newStateProcessorMetrics(sink TelemetrySink) *stateProcessorMetrics { return &stateProcessorMetrics{ sink: sink, } } func (s *stateProcessorMetrics) gaugeBlockGasUsed(blockNumber, txGasUsed, blobGasUsed math.U64) { blockNumberStr := blockNumber.Base10() s.sink.SetGauge( "beacon_kit.state.block_tx_gas_used", int64(txGasUsed.Unwrap()), // #nosec G115 "block_number", blockNumberStr, ) s.sink.SetGauge( "beacon_kit.state.block_blob_gas_used", int64(blobGasUsed.Unwrap()), // #nosec G115 "block_number", blockNumberStr, ) } func (s *stateProcessorMetrics) gaugePartialWithdrawalsEnqueued(count int) { s.sink.SetGauge("beacon_kit.state.partial_withdrawals_enqueued", int64(count)) } func (s *stateProcessorMetrics) gaugeTimestamps(payloadTimestamp, consensusTimestamp uint64) { // the diff can be positive or negative depending on whether the payload // timestamp is ahead or behind the consensus timestamp diff := int64(payloadTimestamp) - int64(consensusTimestamp) // #nosec G115 s.sink.SetGauge("beacon_kit.state.payload_consensus_timestamp_diff", diff) } func (s *stateProcessorMetrics) incrementDepositStakeLost() { s.sink.IncrementCounter("beacon_kit.state.deposit_stake_lost") } func (s *stateProcessorMetrics) incrementPartialWithdrawalRequestDropped() { s.sink.IncrementCounter("beacon_kit.state.partial_withdrawal_request_dropped") } func (s *stateProcessorMetrics) incrementPartialWithdrawalRequestInvalid() { s.sink.IncrementCounter("beacon_kit.state.partial_withdrawal_request_invalid") } func (s *stateProcessorMetrics) incrementValidatorNotWithdrawable() { s.sink.IncrementCounter("beacon_kit.state.validator_not_withdrawable") } ================================================ FILE: state-transition/core/mocks/execution_engine.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import ( context "context" types "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" mock "github.com/stretchr/testify/mock" ) // ExecutionEngine is an autogenerated mock type for the ExecutionEngine type type ExecutionEngine struct { mock.Mock } type ExecutionEngine_Expecter struct { mock *mock.Mock } func (_m *ExecutionEngine) EXPECT() *ExecutionEngine_Expecter { return &ExecutionEngine_Expecter{mock: &_m.Mock} } // NotifyForkchoiceUpdate provides a mock function with given fields: ctx, req func (_m *ExecutionEngine) NotifyForkchoiceUpdate(ctx context.Context, req *types.ForkchoiceUpdateRequest) (*engineprimitives.PayloadID, error) { ret := _m.Called(ctx, req) if len(ret) == 0 { panic("no return value specified for NotifyForkchoiceUpdate") } var r0 *engineprimitives.PayloadID var r1 error if rf, ok := ret.Get(0).(func(context.Context, *types.ForkchoiceUpdateRequest) (*engineprimitives.PayloadID, error)); ok { return rf(ctx, req) } if rf, ok := ret.Get(0).(func(context.Context, *types.ForkchoiceUpdateRequest) *engineprimitives.PayloadID); ok { r0 = rf(ctx, req) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*engineprimitives.PayloadID) } } if rf, ok := ret.Get(1).(func(context.Context, *types.ForkchoiceUpdateRequest) error); ok { r1 = rf(ctx, req) } else { r1 = ret.Error(1) } return r0, r1 } // ExecutionEngine_NotifyForkchoiceUpdate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NotifyForkchoiceUpdate' type ExecutionEngine_NotifyForkchoiceUpdate_Call struct { *mock.Call } // NotifyForkchoiceUpdate is a helper method to define mock.On call // - ctx context.Context // - req *types.ForkchoiceUpdateRequest func (_e *ExecutionEngine_Expecter) NotifyForkchoiceUpdate(ctx interface{}, req interface{}) *ExecutionEngine_NotifyForkchoiceUpdate_Call { return &ExecutionEngine_NotifyForkchoiceUpdate_Call{Call: _e.mock.On("NotifyForkchoiceUpdate", ctx, req)} } func (_c *ExecutionEngine_NotifyForkchoiceUpdate_Call) Run(run func(ctx context.Context, req *types.ForkchoiceUpdateRequest)) *ExecutionEngine_NotifyForkchoiceUpdate_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(*types.ForkchoiceUpdateRequest)) }) return _c } func (_c *ExecutionEngine_NotifyForkchoiceUpdate_Call) Return(_a0 *engineprimitives.PayloadID, _a1 error) *ExecutionEngine_NotifyForkchoiceUpdate_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *ExecutionEngine_NotifyForkchoiceUpdate_Call) RunAndReturn(run func(context.Context, *types.ForkchoiceUpdateRequest) (*engineprimitives.PayloadID, error)) *ExecutionEngine_NotifyForkchoiceUpdate_Call { _c.Call.Return(run) return _c } // NotifyNewPayload provides a mock function with given fields: ctx, req, retryOnSyncingStatus func (_m *ExecutionEngine) NotifyNewPayload(ctx context.Context, req types.NewPayloadRequest, retryOnSyncingStatus bool) error { ret := _m.Called(ctx, req, retryOnSyncingStatus) if len(ret) == 0 { panic("no return value specified for NotifyNewPayload") } var r0 error if rf, ok := ret.Get(0).(func(context.Context, types.NewPayloadRequest, bool) error); ok { r0 = rf(ctx, req, retryOnSyncingStatus) } else { r0 = ret.Error(0) } return r0 } // ExecutionEngine_NotifyNewPayload_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NotifyNewPayload' type ExecutionEngine_NotifyNewPayload_Call struct { *mock.Call } // NotifyNewPayload is a helper method to define mock.On call // - ctx context.Context // - req types.NewPayloadRequest // - retryOnSyncingStatus bool func (_e *ExecutionEngine_Expecter) NotifyNewPayload(ctx interface{}, req interface{}, retryOnSyncingStatus interface{}) *ExecutionEngine_NotifyNewPayload_Call { return &ExecutionEngine_NotifyNewPayload_Call{Call: _e.mock.On("NotifyNewPayload", ctx, req, retryOnSyncingStatus)} } func (_c *ExecutionEngine_NotifyNewPayload_Call) Run(run func(ctx context.Context, req types.NewPayloadRequest, retryOnSyncingStatus bool)) *ExecutionEngine_NotifyNewPayload_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].(types.NewPayloadRequest), args[2].(bool)) }) return _c } func (_c *ExecutionEngine_NotifyNewPayload_Call) Return(_a0 error) *ExecutionEngine_NotifyNewPayload_Call { _c.Call.Return(_a0) return _c } func (_c *ExecutionEngine_NotifyNewPayload_Call) RunAndReturn(run func(context.Context, types.NewPayloadRequest, bool) error) *ExecutionEngine_NotifyNewPayload_Call { _c.Call.Return(run) return _c } // NewExecutionEngine creates a new instance of ExecutionEngine. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewExecutionEngine(t interface { mock.TestingT Cleanup(func()) }) *ExecutionEngine { mock := &ExecutionEngine{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: state-transition/core/state/constants.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package state import ( "math" ) const ( // EVMInflationWithdrawalIndex is the fixed withdrawal index to be used for // the EVM inflation withdrawal in every block. It should remain unused // during processing. EVMInflationWithdrawalIndex = math.MaxUint64 // EVMInflationWithdrawalValidatorIndex is the fixed validator index to be // used for the EVM inflation withdrawal in every block. It should remain // unused during processing. EVMInflationWithdrawalValidatorIndex = math.MaxUint64 ) ================================================ FILE: state-transition/core/state/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package state import ( "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) type ChainSpec interface { chain.BerachainSpec chain.WithdrawalsSpec SlotToEpoch(slot math.Slot) math.Epoch SlotsPerHistoricalRoot() uint64 MaxEffectiveBalance() math.Gwei EpochsPerHistoricalVector() uint64 ActiveForkVersionForTimestamp(timestamp math.U64) common.Version MinActivationBalance() math.Gwei } // TelemetrySink is an interface for sending metrics to a telemetry backend. type TelemetrySink interface { IncrementCounter(key string, args ...string) } ================================================ FILE: state-transition/core/state/metrics.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package state func (s *StateDB) incrementPartialWithdrawalRequestInvalid() { s.telemetrySink.IncrementCounter("beacon_kit.statedb.partial_withdrawal_request_invalid") } // incrementExcessStakePartialWithdrawal increments the telemetry counter when a withdrawal is created // because a validator's stake went over the MaxEffectiveBalance. func (s *StateDB) incrementExcessStakePartialWithdrawal() { s.telemetrySink.IncrementCounter("beacon_kit.statedb.excess_stake_partial_withdrawal") } ================================================ FILE: state-transition/core/state/parent_proposer_pubkey.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package state import ( "fmt" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" ) // ParentProposerPubkey returns the parent proposer pubkey for the given timestamp. // It must return nil if we are before Electra1. // //nolint:nilnil // TODO: consider addressing this func (s *StateDB) ParentProposerPubkey(timestamp math.U64) (*crypto.BLSPubkey, error) { if version.IsBefore(s.cs.ActiveForkVersionForTimestamp(timestamp), version.Electra1()) { return nil, nil } latestBlockHeader, err := s.GetLatestBlockHeader() if err != nil { return nil, fmt.Errorf("failed retrieving latest block header: %w", err) } prevProposer, err := s.ValidatorByIndex(latestBlockHeader.GetProposerIndex()) if err != nil { return nil, fmt.Errorf("failed retrieving prev proposer: %w", err) } p := prevProposer.GetPubkey() return &p, nil } ================================================ FILE: state-transition/core/state/statedb.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package state import ( "context" "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/storage/beacondb" ) // StateDB is the underlying struct behind the BeaconState interface. // //nolint:revive // todo fix somehow type StateDB struct { beacondb.KVStore cs ChainSpec logger log.Logger telemetrySink TelemetrySink } // NewBeaconStateFromDB creates a new beacon state from an underlying state db. func NewBeaconStateFromDB( bdb *beacondb.KVStore, cs ChainSpec, logger log.Logger, telemetrySink TelemetrySink, ) *StateDB { return &StateDB{ KVStore: *bdb, cs: cs, logger: logger, telemetrySink: telemetrySink, } } // Protect returns an almost copy of stateDB. Specifically Protect guarantees that: // - No changes done on the returned state will affect the original state // - However, changes done on the original state will be carried over to the returned state. // The behaviour is probably best understood by considering the context hosts a stack of cache layers. // So write operations to the top cache won't be flushed to the lower layer but read operations will walk // through the cache stack, so bubbling up changes from the lower layers to the top ones. func (s *StateDB) Protect(ctx context.Context) *StateDB { return NewBeaconStateFromDB(s.KVStore.Copy(ctx), s.cs, s.logger, s.telemetrySink) } // GetEpoch returns the current epoch. func (s *StateDB) GetEpoch() (math.Epoch, error) { slot, err := s.GetSlot() if err != nil { return 0, err } return s.cs.SlotToEpoch(slot), nil } // IncreaseBalance increases the balance of a validator. func (s *StateDB) IncreaseBalance(idx math.ValidatorIndex, delta math.Gwei) error { balance, err := s.GetBalance(idx) if err != nil { return err } return s.SetBalance(idx, balance+delta) } // DecreaseBalance decreases the balance of a validator. func (s *StateDB) DecreaseBalance(idx math.ValidatorIndex, delta math.Gwei) error { balance, err := s.GetBalance(idx) if err != nil { return err } return s.SetBalance(idx, balance-min(balance, delta)) } // ExpectedWithdrawals is modified from the ETH2.0 spec: // https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-get_expected_withdrawals // to allow a fixed withdrawal (as the first withdrawal) used for EVM inflation. // // NOTE for caller: ProcessSlots must be called before this function as the "current" slot is // retrieved from the state in this function. // //nolint:gocognit,funlen // Spec aligned. func (s *StateDB) ExpectedWithdrawals(timestamp math.U64) (engineprimitives.Withdrawals, uint64, error) { var ( validator *ctypes.Validator balance math.Gwei withdrawalAddress common.ExecutionAddress ) processedPartialWithdrawals := uint64(0) epoch, err := s.GetEpoch() if err != nil { return nil, 0, err } maxWithdrawals := s.cs.MaxWithdrawalsPerPayload() withdrawals := make([]*engineprimitives.Withdrawal, 0, maxWithdrawals) // The first withdrawal is fixed to be the EVM inflation withdrawal. withdrawals = append(withdrawals, s.EVMInflationWithdrawal(timestamp)) withdrawalIndex, err := s.GetNextWithdrawalIndex() if err != nil { return nil, 0, err } validatorIndex, err := s.GetNextWithdrawalValidatorIndex() if err != nil { return nil, 0, err } totalValidators, err := s.GetTotalValidators() if err != nil { return nil, 0, err } // [New in Electra:EIP7251] Consume pending partial withdrawals forkVersion := s.cs.ActiveForkVersionForTimestamp(timestamp) if version.EqualsOrIsAfter(forkVersion, version.Electra()) { withdrawals, withdrawalIndex, processedPartialWithdrawals, err = s.consumePendingPartialWithdrawals(epoch, withdrawals, withdrawalIndex) if err != nil { return nil, 0, err } } bound := min(totalValidators, s.cs.MaxValidatorsPerWithdrawalsSweep()) // Iterate through indices to find the next validators to withdraw. for range bound { validator, err = s.ValidatorByIndex(validatorIndex) if err != nil { return nil, 0, err } balance, err = s.GetBalance(validatorIndex) if err != nil { return nil, 0, err } if version.EqualsOrIsAfter(forkVersion, version.Electra()) { var totalWithdrawn math.Gwei for _, withdrawal := range withdrawals { if withdrawal.Validator == validatorIndex { totalWithdrawn += withdrawal.Amount } } // After electra, partiallyWithdrawnBalance can be non-zero, which we must account for. balance -= totalWithdrawn } // Set the amount of the withdrawal depending on the balance of the validator. if validator.IsFullyWithdrawable(balance, epoch) { withdrawalAddress, err = validator.GetWithdrawalCredentials().ToExecutionAddress() if err != nil { return nil, 0, err } withdrawals = append(withdrawals, engineprimitives.NewWithdrawal( math.U64(withdrawalIndex), validatorIndex, withdrawalAddress, balance, )) // Increment the withdrawal index to process the next withdrawal. withdrawalIndex++ } else if validator.IsPartiallyWithdrawable(balance, s.cs.MaxEffectiveBalance()) { withdrawalAddress, err = validator.GetWithdrawalCredentials().ToExecutionAddress() if err != nil { return nil, 0, err } withdrawals = append(withdrawals, engineprimitives.NewWithdrawal( math.U64(withdrawalIndex), validatorIndex, withdrawalAddress, balance-s.cs.MaxEffectiveBalance(), )) s.logger.Info("expectedWithdrawals: validator withdrawal due to excess balance", "validator_pubkey", validator.GetPubkey().String(), "balance", balance, "effective_balance", validator.GetEffectiveBalance(), "exit_epoch", validator.GetExitEpoch(), "withdrawal_credentials", validator.GetWithdrawalCredentials().String(), ) s.incrementExcessStakePartialWithdrawal() // Increment the withdrawal index to process the next withdrawal. withdrawalIndex++ } // Cap the number of withdrawals to the maximum allowed per payload. if uint64(len(withdrawals)) == maxWithdrawals { break } // Increment the validator index to process the next validator. validatorIndex = (validatorIndex + 1) % totalValidators } return withdrawals, processedPartialWithdrawals, nil } //nolint:gocognit // Spec aligned. func (s *StateDB) consumePendingPartialWithdrawals( epoch math.Epoch, withdrawals engineprimitives.Withdrawals, withdrawalIndex uint64, ) ( engineprimitives.Withdrawals, uint64, // withdrawalIndex uint64, // processedPartialWithdrawals error, ) { // By this point, if we're post-Electra, the fork version on the BeaconState will have been set as part of `PrepareStateForFork`. // This will fail if the state has not been prepared for a post-Electra fork version. ppWithdrawals, getErr := s.GetPendingPartialWithdrawals() if getErr != nil { return nil, 0, 0, fmt.Errorf("consumePendingPartialWithdrawals: failed retrieving pending partial withdrawals: %w", getErr) } processedPartialWithdrawals := uint64(0) minActivationBalance := s.cs.MinActivationBalance() for _, withdrawal := range ppWithdrawals { if withdrawal.WithdrawableEpoch > epoch || len(withdrawals) == constants.MaxPendingPartialsPerWithdrawalsSweep { // If the first withdrawal in the queue is not withdrawable, then all subsequent withdrawals will also be in later // epochs and hence are not withdrawable, so we can break early. s.logger.Debug("consumePendingPartialWithdrawals: early break for partial withdrawals", "current_epoch", epoch, "next_withdrawable_epoch", withdrawal.WithdrawableEpoch, ) break } validator, err := s.ValidatorByIndex(withdrawal.ValidatorIndex) if err != nil { return nil, 0, 0, err } hasSufficientEffectiveBalance := validator.GetEffectiveBalance() >= minActivationBalance balance, err := s.GetBalance(withdrawal.ValidatorIndex) if err != nil { return nil, 0, 0, err } var totalWithdrawn math.Gwei for _, w := range withdrawals { if w.Validator == withdrawal.ValidatorIndex { totalWithdrawn += w.Amount } } balance -= totalWithdrawn hasExcessBalance := balance > minActivationBalance isWithdrawable := validator.GetExitEpoch() == constants.FarFutureEpoch && hasSufficientEffectiveBalance && hasExcessBalance if isWithdrawable { // A validator can only partial withdraw an amount such that: // 1. never withdraw more than what the validator asked for. // 2. never withdraw so much that the validator’s remaining balance would drop below MIN_ACTIVATION_BALANCE. withdrawableBalance := min(balance-minActivationBalance, withdrawal.Amount) withdrawalAddress, addrErr := validator.WithdrawalCredentials.ToExecutionAddress() if addrErr != nil { return nil, 0, 0, addrErr } withdrawals = append( withdrawals, engineprimitives.NewWithdrawal( math.U64(withdrawalIndex), withdrawal.ValidatorIndex, withdrawalAddress, withdrawableBalance, ), ) // Increment the withdrawal index to process the next withdrawal. withdrawalIndex++ } else { s.logger.Info("consumePendingPartialWithdrawals: validator not withdrawable", "validator_index", withdrawal.ValidatorIndex, "validator_pubkey", validator.GetPubkey().String(), "balance", balance, "effective_balance", validator.GetEffectiveBalance(), "exit_epoch", validator.GetExitEpoch(), "withdrawable_epoch", withdrawal.WithdrawableEpoch, ) s.incrementPartialWithdrawalRequestInvalid() } // Even if a withdrawal was not created, e.g. the validator did not have sufficient balance, we will consider // this withdrawal processed (spec defined) and hence increment the processedPartialWithdrawals count. processedPartialWithdrawals++ } return withdrawals, withdrawalIndex, processedPartialWithdrawals, nil } // EVMInflationWithdrawal returns the withdrawal used for EVM balance inflation. // // NOTE: The withdrawal index and validator index are both set to max(uint64) as // they are not used during processing. func (s *StateDB) EVMInflationWithdrawal(timestamp math.U64) *engineprimitives.Withdrawal { return engineprimitives.NewWithdrawal( EVMInflationWithdrawalIndex, EVMInflationWithdrawalValidatorIndex, s.cs.EVMInflationAddress(timestamp), s.cs.EVMInflationPerBlock(timestamp), ) } // GetMarshallable is the interface for the beacon store. // //nolint:funlen,gocognit // todo fix somehow func (s *StateDB) GetMarshallable() (*ctypes.BeaconState, error) { slot, err := s.GetSlot() if err != nil { return nil, err } fork, err := s.GetFork() if err != nil { return nil, err } genesisValidatorsRoot, err := s.GetGenesisValidatorsRoot() if err != nil { return nil, err } latestBlockHeader, err := s.GetLatestBlockHeader() if err != nil { return nil, err } blockRoots := make([]common.Root, s.cs.SlotsPerHistoricalRoot()) for i := range s.cs.SlotsPerHistoricalRoot() { blockRoots[i], err = s.GetBlockRootAtIndex(i) if err != nil { return nil, err } } stateRoots := make([]common.Root, s.cs.SlotsPerHistoricalRoot()) for i := range s.cs.SlotsPerHistoricalRoot() { stateRoots[i], err = s.StateRootAtIndex(i) if err != nil { return nil, err } } latestExecutionPayloadHeader, err := s.GetLatestExecutionPayloadHeader() if err != nil { return nil, err } eth1Data, err := s.GetEth1Data() if err != nil { return nil, err } eth1DepositIndex, err := s.GetEth1DepositIndex() if err != nil { return nil, err } validators, err := s.GetValidators() if err != nil { return nil, err } balances, err := s.GetBalances() if err != nil { return nil, err } randaoMixes := make([]common.Bytes32, s.cs.EpochsPerHistoricalVector()) for i := range s.cs.EpochsPerHistoricalVector() { randaoMixes[i], err = s.GetRandaoMixAtIndex(i) if err != nil { return nil, err } } nextWithdrawalIndex, err := s.GetNextWithdrawalIndex() if err != nil { return nil, err } nextWithdrawalValidatorIndex, err := s.GetNextWithdrawalValidatorIndex() if err != nil { return nil, err } slashings, err := s.GetSlashings() if err != nil { return nil, err } totalSlashings, err := s.GetTotalSlashing() if err != nil { return nil, err } beaconState := ctypes.NewEmptyBeaconStateWithVersion(fork.CurrentVersion) beaconState.Slot = slot beaconState.GenesisValidatorsRoot = genesisValidatorsRoot beaconState.Fork = fork beaconState.LatestBlockHeader = latestBlockHeader beaconState.BlockRoots = blockRoots beaconState.StateRoots = stateRoots beaconState.LatestExecutionPayloadHeader = latestExecutionPayloadHeader beaconState.Eth1Data = eth1Data beaconState.Eth1DepositIndex = eth1DepositIndex beaconState.Validators = validators beaconState.Balances = balances beaconState.RandaoMixes = randaoMixes beaconState.NextWithdrawalIndex = nextWithdrawalIndex beaconState.NextWithdrawalValidatorIndex = nextWithdrawalValidatorIndex beaconState.Slashings = slashings beaconState.TotalSlashing = totalSlashings if version.EqualsOrIsAfter(beaconState.GetForkVersion(), version.Electra()) { pendingPartialWithdrawals, getErr := s.GetPendingPartialWithdrawals() if getErr != nil { return nil, getErr } beaconState.PendingPartialWithdrawals = pendingPartialWithdrawals } return beaconState, nil } // HashTreeRoot is the interface for the beacon store. func (s *StateDB) HashTreeRoot() common.Root { st, err := s.GetMarshallable() if err != nil { panic(err) } return st.HashTreeRoot() } ================================================ FILE: state-transition/core/state/statedb_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package state_test import ( "testing" "cosmossdk.io/collections" "cosmossdk.io/log" "cosmossdk.io/store" sdkmetrics "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" "github.com/berachain/beacon-kit/config/spec" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage" "github.com/berachain/beacon-kit/storage/beacondb" "github.com/berachain/beacon-kit/storage/db" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) func TestStateProtect(t *testing.T) { t.Parallel() db, err := db.OpenDB("", dbm.MemDBBackend) require.NoError(t, err) cs, errSpec := spec.MainnetChainSpec() require.NoError(t, errSpec) var ( nopLog = log.NewNopLogger() nopMetrics = sdkmetrics.NewNoOpMetrics() ) cms := store.NewCommitMultiStore(db, nopLog, nopMetrics) cms.MountStoreWithDB(testStoreKey, storetypes.StoreTypeIAVL, nil) require.NoError(t, cms.LoadLatestVersion()) backendStoreService := &storage.KVStoreService{Key: testStoreKey} kvStore := beacondb.New(backendStoreService) ms := cms.CacheMultiStore() sdkCtx := sdk.NewContext(ms, true, nopLog) originalState := state.NewBeaconStateFromDB( kvStore.WithContext(sdkCtx), cs, sdkCtx.Logger(), metrics.NewNoOpTelemetrySink(), ) protectingState := originalState.Protect(sdkCtx) // 1- set an attribute in the original state and show // that value is carried over the protecting state wantSlot := math.Slot(1234) require.NoError(t, originalState.SetSlot(wantSlot)) gotSlot, err := protectingState.GetSlot() require.NoError(t, err) require.Equal(t, wantSlot, gotSlot) // 2- Show that modifying the protecting state // does not affect the original state wantFork := &ctypes.Fork{ PreviousVersion: common.Version{0x11, 0x22, 0x33, 0x44}, CurrentVersion: common.Version{0xff, 0xff, 0xff, 0xff}, Epoch: math.Epoch(1234), } require.NoError(t, protectingState.SetFork(wantFork)) _, err = originalState.GetFork() require.ErrorIs(t, err, collections.ErrNotFound) // 3- Show that changes made to original state after protection // are carried over the protecting state wantEthIdx := uint64(1987) require.NoError(t, originalState.SetEth1DepositIndex(wantEthIdx)) gotEthIdx, err := protectingState.GetEth1DepositIndex() require.NoError(t, err) require.Equal(t, wantEthIdx, gotEthIdx) } var testStoreKey = storetypes.NewKVStoreKey("test-stateDB") ================================================ FILE: state-transition/core/state_processor.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "bytes" "fmt" "sync" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/cache" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage/deposit" ) // StateProcessor is a basic Processor, which takes care of the // main state transition for the beacon chain. type StateProcessor struct { // logger is used for logging information and errors. logger log.Logger // cs is the chain specification for the beacon chain. cs ChainSpec // signer is the BLS signer used for cryptographic operations. signer crypto.BLSSigner // fGetAddressFromPubKey verifies that a validator public key // matches with the proposer address passed by the consensus // Injected via ctor to simplify testing. fGetAddressFromPubKey func(crypto.BLSPubkey) ([]byte, error) // executionEngine is the engine responsible for executing transactions. executionEngine ExecutionEngine // ds allows checking payload deposits against the deposit contract ds deposit.StoreManager // metrics is the metrics for the service. metrics *stateProcessorMetrics // logDeneb1Once enforces logging the Deneb1 fork information at most once. logDeneb1Once sync.Once } // NewStateProcessor creates a new state processor. func NewStateProcessor( logger log.Logger, cs ChainSpec, executionEngine ExecutionEngine, ds deposit.StoreManager, signer crypto.BLSSigner, fGetAddressFromPubKey func(crypto.BLSPubkey) ([]byte, error), telemetrySink TelemetrySink, ) *StateProcessor { return &StateProcessor{ logger: logger, cs: cs, executionEngine: executionEngine, signer: signer, fGetAddressFromPubKey: fGetAddressFromPubKey, ds: ds, metrics: newStateProcessorMetrics(telemetrySink), } } // Transition is the main function for processing a state transition. func (sp *StateProcessor) Transition( ctx ReadOnlyContext, st *state.StateDB, blk *ctypes.BeaconBlock, ) (transition.ValidatorUpdates, error) { if blk == nil { return nil, nil } // Process the next slot. validatorUpdates, err := sp.ProcessSlots(st, blk.GetSlot()) if err != nil { return nil, err } // Prepare the state for the next block's fork version. // Ideally we want to log only in case we are processing the // block to be finalized. Pre cache activation this is easy. // Post activation we log every time we verify a block logForkProcessing := ctx.VerifyPayload() && !ctx.VerifyRandao() if cache.IsStateCachingActive(sp.cs, blk.Slot) { logForkProcessing = ctx.VerifyPayload() } if err = sp.ProcessFork(st, blk.GetTimestamp(), logForkProcessing); err != nil { return nil, err } // Process the block. if err = sp.ProcessBlock(ctx, st, blk); err != nil { return nil, err } return validatorUpdates, nil } // ProcessSlots deviates from the ethereum consensus specs `process_slots`. The `process_slots` function must // iterate and process slots in which the target `slot` can be several slots ahead of the `stateSlot`. This is because // the beacon chain can miss blocks for a given slot, resulting in not processing the slot. For example, the current // slot is 100, and no blocks were proposed for slots 101 and 102. Upon receiving a block at slot 103, the beacon state // must "catch up" the state and trigger slot and epoch transitions that may have happened during slot 101 and 102. // // Beacon-kit does not allow missed slots. Each height from cometBFT will always correspond to a beacon block slot, so // `ProcessSlots` will always be called at every slot. Thus, we will only process the state up to the next slot. // The reasoning behind this deviation is to be explicit in this behavior and also to better support the usage of fork // logic in the `processEpoch` function. Since we do not fork by slot but instead fork by timestamp, we must be able to // strictly tie each call of `processSlot` and `processEpoch` to a timestamp. Since we don't have beacon blocks during // each iteration of the slot loop, we cannot correlate each slot to a timestamp. We instead identify that we process // only one slot, allowing us to simply use the fork version from the state. func (sp *StateProcessor) ProcessSlots( st *state.StateDB, slot math.Slot, ) (transition.ValidatorUpdates, error) { var res transition.ValidatorUpdates stateSlot, err := st.GetSlot() if err != nil { return nil, err } if slot == stateSlot { return res, nil } if slot != stateSlot+1 { return nil, fmt.Errorf("slot %d does not match expected slot %d", slot, stateSlot+1) } if err = sp.processSlot(st); err != nil { return nil, err } // Process the Epoch Boundary. if slot.Unwrap()%sp.cs.SlotsPerEpoch() == 0 { var epochUpdates transition.ValidatorUpdates if epochUpdates, err = sp.processEpoch(st); err != nil { return nil, err } res = append(res, epochUpdates...) } // Update the state slot. if err = st.SetSlot(slot); err != nil { return nil, err } return res, nil } // processSlot as defined in the Ethereum 2.0 Specification: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function func (sp *StateProcessor) processSlot(st *state.StateDB) error { stateSlot, err := st.GetSlot() if err != nil { return err } // Before we make any changes, we calculate the previous state root. prevStateRoot := st.HashTreeRoot() if err = st.UpdateStateRootAtIndex( stateSlot.Unwrap()%sp.cs.SlotsPerHistoricalRoot(), prevStateRoot, ); err != nil { return err } // We get the latest block header, this will not have // a state root on it. latestHeader, err := st.GetLatestBlockHeader() if err != nil { return err } // We set the "rawHeader" in the StateProcessor, but cannot fill in // the StateRoot until the following block. if (latestHeader.GetStateRoot() == common.Root{}) { latestHeader.SetStateRoot(prevStateRoot) if err = st.SetLatestBlockHeader(latestHeader); err != nil { return err } } // We update the block root. return st.UpdateBlockRootAtIndex( stateSlot.Unwrap()%sp.cs.SlotsPerHistoricalRoot(), latestHeader.HashTreeRoot(), ) } // ProcessBlock processes the block, it optionally verifies the // state root. func (sp *StateProcessor) ProcessBlock( ctx ReadOnlyContext, st *state.StateDB, blk *ctypes.BeaconBlock, ) error { // Before processing block header, we need to retrieve public key of // parent block proposer to be able to inform the EL client. parentProposerPubkey, err := st.ParentProposerPubkey(blk.GetTimestamp()) if err != nil { return err } if err = sp.processBlockHeader(ctx, st, blk); err != nil { return err } if err = sp.processExecutionPayload(ctx, st, blk, parentProposerPubkey); err != nil { return err } if err = sp.processWithdrawals(st, blk); err != nil { return err } if err = sp.processRandaoReveal(ctx, st, blk); err != nil { return err } if err = sp.processOperations(ctx, st, blk); err != nil { return err } // If we are skipping validate, we can skip calculating the state // root to save compute. if !ctx.VerifyResult() { return nil } // Ensure the calculated state root matches the state root on // the block. stateRoot := st.HashTreeRoot() if blk.GetStateRoot() != stateRoot { return errors.Wrapf( ErrStateRootMismatch, "expected %s, got %s", stateRoot, blk.GetStateRoot(), ) } return nil } // processEpoch processes the epoch and ensures it matches the local state. // Currently, beacon-kit does not enforce rewards, penalties, and slashing for validators. // Extra caution is required when any fork-specific logic is added within the scope of this method // as epochs and fork slots may not always neatly overlap. func (sp *StateProcessor) processEpoch(st *state.StateDB) (transition.ValidatorUpdates, error) { currentEpoch, err := st.GetEpoch() if err != nil { return nil, err } // track validators set before updating it, to be able to // inform consensus of the validators set changes currentActiveVals, err := getActiveVals(st, currentEpoch) if err != nil { return nil, err } // if err = sp.processRewardsAndPenalties(st); err != nil { // return nil, err // } if err = sp.processRegistryUpdates(st); err != nil { return nil, err } if err = sp.processEffectiveBalanceUpdates(st); err != nil { return nil, err } // if err = sp.processSlashingsReset(st); err != nil { // return nil, err // } if err = sp.processRandaoMixesReset(st); err != nil { return nil, err } // only after we have fully updated validators, we enforce a cap on the validators set if err = sp.processValidatorSetCap(st); err != nil { return nil, err } // finally compute diffs in validator set to duly update consensus nextEpoch := currentEpoch + 1 nextActiveVals, err := getActiveVals(st, nextEpoch) if err != nil { return nil, err } return validatorSetsDiffs(currentActiveVals, nextActiveVals), nil } // processBlockHeader processes the header and ensures it matches the local state. func (sp *StateProcessor) processBlockHeader( ctx ReadOnlyContext, st *state.StateDB, blk *ctypes.BeaconBlock, ) error { // Ensure the block slot matches the state slot. slot, err := st.GetSlot() if err != nil { return err } if blk.GetSlot() != slot { return errors.Wrapf(ErrSlotMismatch, "expected: %d, got: %d", slot, blk.GetSlot()) } // Verify that the block is newer than latest block header latestBlockHeader, err := st.GetLatestBlockHeader() if err != nil { return err } if blk.GetSlot() <= latestBlockHeader.GetSlot() { return errors.Wrapf( ErrBlockSlotTooLow, "expected: > %d, got: %d", latestBlockHeader.GetSlot(), blk.GetSlot(), ) } // Verify that proposer matches with what consensus declares as proposer proposer, err := st.ValidatorByIndex(blk.GetProposerIndex()) if err != nil { return err } stateProposerAddress, err := sp.fGetAddressFromPubKey(proposer.GetPubkey()) if err != nil { return err } if !bytes.Equal(stateProposerAddress, ctx.ProposerAddress()) { return errors.Wrapf( ErrProposerMismatch, "store key: %s, consensus key: %s", stateProposerAddress, ctx.ProposerAddress(), ) } // Verify that the parent matches parentBlockRoot := latestBlockHeader.HashTreeRoot() if parentBlockRoot != blk.GetParentBlockRoot() { return errors.Wrapf( ErrParentRootMismatch, "expected: %s, got: %s", parentBlockRoot.String(), blk.GetParentBlockRoot().String(), ) } // Verify proposer is not slashed if proposer.IsSlashed() { return errors.Wrapf( ErrSlashedProposer, "index: %d", blk.GetProposerIndex(), ) } // Cache current block as the new latest block bodyRoot := blk.GetBody().HashTreeRoot() lbh := &ctypes.BeaconBlockHeader{ Slot: blk.GetSlot(), ProposerIndex: blk.GetProposerIndex(), ParentBlockRoot: blk.GetParentBlockRoot(), // state_root is zeroed and overwritten in the next `process_slot` call. StateRoot: common.Root{}, BodyRoot: bodyRoot, } return st.SetLatestBlockHeader(lbh) } // processEffectiveBalanceUpdates as defined in the Ethereum 2.0 specification. // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#effective-balances-updates func (sp *StateProcessor) processEffectiveBalanceUpdates(st *state.StateDB) error { // Update effective balances with hysteresis validators, err := st.GetValidators() if err != nil { return err } // Get the timestamp from the latest execution payload header to determine the active fork // version for fork-gated hysteresis parameters (BRIP-0008). // // Note: this uses the previous block's payload timestamp because processEpoch runs // inside ProcessSlots, before ProcessFork updates the state. If Fulu activates exactly // at an epoch boundary, the new hysteresis values take effect one epoch later. This is // acceptable because hysteresis only affects capital efficiency (not consensus safety), // and is consistent with how all fork-gated logic in processEpoch operates. lph, err := st.GetLatestExecutionPayloadHeader() if err != nil { return err } timestamp := lph.GetTimestamp() var ( effectiveBalanceIncrement = sp.cs.EffectiveBalanceIncrement() hysteresisIncrement = effectiveBalanceIncrement / sp.cs.HysteresisQuotient(timestamp) downwardThreshold = hysteresisIncrement * sp.cs.HysteresisDownwardMultiplier() upwardThreshold = hysteresisIncrement * sp.cs.HysteresisUpwardMultiplier(timestamp) idx math.U64 balance math.Gwei ) for _, val := range validators { idx, err = st.ValidatorIndexByPubkey(val.GetPubkey()) if err != nil { return err } balance, err = st.GetBalance(idx) if err != nil { return err } if balance+downwardThreshold < val.GetEffectiveBalance() || val.GetEffectiveBalance()+upwardThreshold < balance { updatedBalance := ctypes.ComputeEffectiveBalance( balance, effectiveBalanceIncrement, sp.cs.MaxEffectiveBalance(), ) val.SetEffectiveBalance(updatedBalance) if err = st.UpdateValidatorAtIndex(idx, val); err != nil { return err } } } return nil } ================================================ FILE: state-transition/core/state_processor_exits.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" statedb "github.com/berachain/beacon-kit/state-transition/core/state" ) // InitiateValidatorExit initiates the exit of the validator with index `idx`. Modified from ETH 2.0 spec: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#initiate-validator-exit // to handle pre-Electra validator exit logic. func (sp *StateProcessor) InitiateValidatorExit(st *statedb.StateDB, idx math.ValidatorIndex) error { validator, err := st.ValidatorByIndex(idx) if err != nil { return err } // We will use the fork version from the state to determine how to exit the validator. fork, err := st.GetFork() if err != nil { return err } currentEpoch, err := st.GetEpoch() if err != nil { return err } // We still have no cap on validator churn, choosing not to adopt any churn-related // Electra changes, so exit epoch is at the next epoch. exitEpoch := currentEpoch + 1 // The withdrawable epoch is `MinValidatorWithdrawabilityDelay` epoch's after `exitEpoch`. var withdrawableEpoch math.Epoch if version.IsBefore(fork.CurrentVersion, version.Electra()) { // Before Electra, this was the logic for exiting a validator: only trigger if the validator // set cap was reached. The withdrawable epoch does not include // `MinValidatorWithdrawabilityDelay`, but is instead the next epoch after exiting. withdrawableEpoch = exitEpoch + 1 } else { // Return if the validator already initiated an exit, so that we only exit validators once. if validator.GetExitEpoch() != constants.FarFutureEpoch { return nil } // The withdrawable Epoch is `MinValidatorWithdrawabilityDelay` epoch's after `exitEpoch`. withdrawableEpoch = exitEpoch + sp.cs.MinValidatorWithdrawabilityDelay() } // Set validator exit epoch and withdrawable epoch. validator.SetExitEpoch(exitEpoch) validator.SetWithdrawableEpoch(withdrawableEpoch) return st.UpdateValidatorAtIndex(idx, validator) } ================================================ FILE: state-transition/core/state_processor_fixes.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/ethereum/go-ethereum/params" ) // TODO: confirm data const ( luganodesPubKey = "0xafd0ad061f698eae0d483098948e26e254f4b7089244bda897895257c668196ffd5e2ddf458fdf8bcea295b7d47a5b37" luganodesCreds = "0x010000000000000000000000b0c615224a053236ac7d1c239f6c1b5fbf8f0617" luganodesAmount = 901_393_690_000_000 * params.Wei // 901_393.69 Gwei fixSmileePubKey = "0x84acfd38a13af12add8d82e1ef0842c4dfc1e4175fae5b8ab73770f9050cbf673cafdbf6d8ab679fe9ea13208f50b485" ) //nolint:gochecknoglobals // unexported var ( luganodesCredentials = ctypes.WithdrawalCredentials(hex.MustToBytes(luganodesCreds)) luganodesPubKeyBytes = crypto.BLSPubkey(hex.MustToBytes(luganodesPubKey)) smileePubKey = crypto.BLSPubkey(hex.MustToBytes(fixSmileePubKey)) ) // processElectra1Fixes handles some fixes made necessary by accidents or wrong validator choices in mainnet func (sp *StateProcessor) processElectra1Fixes(st *state.StateDB) error { if !sp.cs.IsMainnet() { return nil } if err := sp.processLuganodesRecovery(st); err != nil { return err } return sp.processSmileeFix(st) } func (sp *StateProcessor) processLuganodesRecovery(st *state.StateDB) error { sp.logger.Info("Luganodes recovery - creating deposit") // Make a one-time hardcoded deposit deposit := ctypes.Deposit{ Pubkey: luganodesPubKeyBytes, Credentials: luganodesCredentials, Amount: luganodesAmount, } sp.logger.Info( "Luganodes deposit", "pubkey", deposit.GetPubkey().String(), "amount", deposit.GetAmount().Unwrap(), "credentials", deposit.GetWithdrawalCredentials().String(), ) if err := sp.addValidatorToRegistry(st, &deposit); err != nil { return fmt.Errorf("failed to add Luganodes validator: %w", err) } sp.logger.Info("Luganodes recovery - created deposit") return nil } func (sp *StateProcessor) processSmileeFix(st *state.StateDB) error { sp.logger.Info("smilee fix - forcing validator exit") idx, err := st.ValidatorIndexByPubkey(smileePubKey) if err != nil { // Post fork activation, we skip the processing in case of errors. // This simplifies some UTs where we pick mainnet specs and activate // the fork during the test sp.logger.Warn("smilee fix - failed retrieving validator by pub key", "err", err) return nil } val, err := st.ValidatorByIndex(idx) if err != nil { // Skipping error here as well. sp.logger.Warn("smilee fix - failed retrieving validator", "err", err) return nil } if err = sp.InitiateValidatorExit(st, idx); err != nil { // We never want to skip this error instead. If the validator is // available we must succeed in kicking it out. return fmt.Errorf("smilee fix - failed initiating validator exit: %w", err) } sp.logger.Info( "smilee validator", "pubkey", val.Pubkey.String(), "amount", val.EffectiveBalance.Unwrap(), "credentials", val.WithdrawalCredentials.String(), ) sp.logger.Info("smilee fix - successfully forced validator exit") return nil } ================================================ FILE: state-transition/core/state_processor_forks.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "errors" "fmt" "cosmossdk.io/collections" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" statedb "github.com/berachain/beacon-kit/state-transition/core/state" ) // ProcessFork prepares the state for the fork version at the given timestamp. // - If this function is called for the same version as the state's current version, // it will do nothing. Unless it is the genesis slot, in which case we want to // prepare the state for the genesis fork version. // - If this function is called for a version before the state's current version, // it will return error as this is not allowed. // - If this function is called for a version after the state's current version, // it will upgrade the state to the new version. // // NOTE for caller: `ProcessSlots` must be called before this function. If we are // crossing into a new fork, the first slot of the new fork will be retrieved from // the state. The state must be prepared for this new slot. // //nolint:gocognit // switch-case is unavoidable here. func (sp *StateProcessor) ProcessFork( st *statedb.StateDB, timestamp math.U64, logUpgrade bool, ) error { stateFork, err := st.GetFork() if err != nil { return err } slot, err := st.GetSlot() if err != nil { return err } // Return early if the given fork version is before or equal to the current state fork version. forkVersion := sp.cs.ActiveForkVersionForTimestamp(timestamp) if version.IsBefore(forkVersion, stateFork.CurrentVersion) { return fmt.Errorf( "cannot downgrade state from %s to %s", stateFork.CurrentVersion, forkVersion, ) } else if slot > 0 && version.Equals(forkVersion, stateFork.CurrentVersion) { // If we are past genesis and the fork version remains consistent, do nothing. return nil } // If we are at genesis or moving to a new fork version, upgrade the state. switch forkVersion { case version.Deneb(): // Do nothing to the state. NOTE: Deneb is the genesis version of Berachain mainnet and // Bepolia testnet. // Log the upgrade to Deneb if requested. if logUpgrade { sp.logDenebFork(timestamp) } case version.Deneb1(): // Do nothing to the state. NOTE: Deneb1 is the first hard fork of Berachain mainnet and // Bepolia testnet. In this fork, the Fork struct on BeaconState is NOT updated. In // future hard forks, the Fork struct should be updated. // Log the upgrade to Deneb1 if requested. if logUpgrade { sp.logDeneb1Fork(stateFork.PreviousVersion, timestamp, slot) } case version.Electra(): if err = sp.upgradeToElectra(st, stateFork, slot); err != nil { return err } // Log the upgrade to Electra if requested. if logUpgrade { sp.logElectraFork(stateFork.PreviousVersion, timestamp, slot) } case version.Electra1(): if err = sp.upgradeToElectra1(st, stateFork, slot); err != nil { return err } if err = sp.processElectra1Fixes(st); err != nil { return err } // Log the upgrade to Electra1 if requested. if logUpgrade { sp.logElectra1Fork(stateFork.PreviousVersion, timestamp, slot) } case version.Fulu(): if err = sp.upgradeToFulu(st, stateFork, slot); err != nil { return err } // Log the upgrade to Fulu if requested. if logUpgrade { sp.logFuluFork(stateFork.PreviousVersion, timestamp, slot) } default: panic(fmt.Sprintf("unsupported fork version: %s", forkVersion)) } return nil } // logDenebFork logs information about the Deneb fork. func (sp *StateProcessor) logDenebFork(timestamp math.U64) { // Since Deneb is the earliest fork version supported by beacon-kit, if we are // entering Deneb it must be at genesis, which means the fork time of Deneb is // the timestamp of the genesis block itself. denebForkTime := timestamp.Unwrap() sp.logger.Info(fmt.Sprintf(` ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ + ✅ welcome to the deneb (0x04000000) fork! 🎉 + ⏱️ deneb fork time: %d + 🍴 first slot / timestamp of deneb: %d / %d + ⛓️ current beacon epoch: %d ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ `, denebForkTime, constants.GenesisSlot.Unwrap(), denebForkTime, constants.GenesisEpoch.Unwrap(), )) } // logDeneb1Fork logs information about the Deneb1 fork. func (sp *StateProcessor) logDeneb1Fork( previousVersion common.Version, timestamp math.U64, slot math.Slot, ) { // Since state fork is not updating to Deneb1, every block observes Deneb1 as "new fork" during // Deneb1. Hence, we must wrap this in a OnceFunc to ensure it is logged only the first time // we process a Deneb1 block. sp.logDeneb1Once.Do(func() { sp.logger.Info(fmt.Sprintf(` ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ + ✅ welcome to the deneb1 (0x04010000) fork! 🎉 + 🚝 previous fork: %s (%s) + ⏱️ deneb1 fork time: %d + 🍴 first slot / timestamp of deneb1: %d / %d + ⛓️ current beacon epoch: %d ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ `, version.Name(previousVersion), previousVersion.String(), sp.cs.Deneb1ForkTime(), slot.Unwrap(), timestamp.Unwrap(), sp.cs.SlotToEpoch(slot).Unwrap(), )) }) } // upgradeToElectra upgrades the state to the Electra fork version. It is modified from the ETH 2.0 // spec (https://ethereum.github.io/consensus-specs/specs/electra/fork/#upgrading-the-state) to: // - update the Fork struct in the BeaconState // - initialize the pending partial withdrawals to an empty array func (sp *StateProcessor) upgradeToElectra( st *statedb.StateDB, fork *types.Fork, slot math.Slot, ) error { // Set the fork on BeaconState. fork.PreviousVersion = fork.CurrentVersion fork.CurrentVersion = version.Electra() fork.Epoch = sp.cs.SlotToEpoch(slot) if err := st.SetFork(fork); err != nil { return err } // Initialize the pending partial withdrawals to an empty array. sp.metrics.gaugePartialWithdrawalsEnqueued(0) return st.SetPendingPartialWithdrawals([]*types.PendingPartialWithdrawal{}) } // logElectraFork logs information about the Electra fork. func (sp *StateProcessor) logElectraFork( previousVersion common.Version, timestamp math.U64, slot math.Slot, ) { sp.logger.Info(fmt.Sprintf(` ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ + ✅ welcome to the electra (0x05000000) fork! 🎉 + 🚝 previous fork: %s (%s) + ⏱️ electra fork time: %d + 🍴 first slot / timestamp of electra: %d / %d + ⛓️ current beacon epoch: %d ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ `, version.Name(previousVersion), previousVersion.String(), sp.cs.ElectraForkTime(), slot.Unwrap(), timestamp.Unwrap(), sp.cs.SlotToEpoch(slot).Unwrap(), )) } // upgradeToElectra1 upgrades the state to the Electra1 fork version. It is modified from the ETH // 2.0 spec (https://ethereum.github.io/consensus-specs/specs/electra/fork/#upgrading-the-state) to: // - update the Fork struct in the BeaconState // - initialize the pending partial withdrawals to an empty array (if not already initialized) func (sp *StateProcessor) upgradeToElectra1( st *statedb.StateDB, fork *types.Fork, slot math.Slot, ) error { // Set the fork on BeaconState. fork.PreviousVersion = fork.CurrentVersion fork.CurrentVersion = version.Electra1() fork.Epoch = sp.cs.SlotToEpoch(slot) if err := st.SetFork(fork); err != nil { return err } // Initialize the pending partial withdrawals to an empty array if not already initialized. if _, err := st.GetPendingPartialWithdrawals(); errors.Is(err, collections.ErrNotFound) { sp.metrics.gaugePartialWithdrawalsEnqueued(0) return st.SetPendingPartialWithdrawals([]*types.PendingPartialWithdrawal{}) } return nil } // logElectra1Fork logs information about the Electra1 fork. func (sp *StateProcessor) logElectra1Fork( previousVersion common.Version, timestamp math.U64, slot math.Slot, ) { sp.logger.Info(fmt.Sprintf(` ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ + ✅ welcome to the electra1 (0x05010000) fork! 🎉 + 🚝 previous fork: %s (%s) + ⏱️ electra1 fork time: %d + 🍴 first slot / timestamp of electra1: %d / %d + ⛓️ current beacon epoch: %d ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ `, version.Name(previousVersion), previousVersion.String(), sp.cs.Electra1ForkTime(), slot.Unwrap(), timestamp.Unwrap(), sp.cs.SlotToEpoch(slot).Unwrap(), )) } // upgradeToFulu upgrades the state to the Fulu fork version. func (sp *StateProcessor) upgradeToFulu( st *statedb.StateDB, fork *types.Fork, slot math.Slot, ) error { // Set the fork on BeaconState. fork.PreviousVersion = fork.CurrentVersion fork.CurrentVersion = version.Fulu() fork.Epoch = sp.cs.SlotToEpoch(slot) if err := st.SetFork(fork); err != nil { return err } // Initialize the pending partial withdrawals to an empty array if not already initialized. // This handles the case where the chain starts directly on Fulu (e.g., devnet). if _, err := st.GetPendingPartialWithdrawals(); errors.Is(err, collections.ErrNotFound) { sp.metrics.gaugePartialWithdrawalsEnqueued(0) return st.SetPendingPartialWithdrawals([]*types.PendingPartialWithdrawal{}) } return nil } // logFuluFork logs information about the Fulu fork. func (sp *StateProcessor) logFuluFork( previousVersion common.Version, timestamp math.U64, slot math.Slot, ) { sp.logger.Info(fmt.Sprintf(` ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ + ✅ welcome to the fulu (0x06000000) fork! 🎉 + 🚝 previous fork: %s (%s) + ⏱️ fulu fork time: %d + 🍴 first slot / timestamp of fulu: %d / %d + ⛓️ current beacon epoch: %d ⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️⏭️ `, version.Name(previousVersion), previousVersion.String(), sp.cs.FuluForkTime(), slot.Unwrap(), timestamp.Unwrap(), sp.cs.SlotToEpoch(slot).Unwrap(), )) } ================================================ FILE: state-transition/core/state_processor_genesis.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" statedb "github.com/berachain/beacon-kit/state-transition/core/state" ) // InitializeBeaconStateFromEth1 initializes the beacon state. Modified from the ETH 2.0 spec: // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#genesis func (sp *StateProcessor) InitializeBeaconStateFromEth1( st *statedb.StateDB, deposits ctypes.Deposits, execPayloadHeader *ctypes.ExecutionPayloadHeader, genesisVersion common.Version, ) (transition.ValidatorUpdates, error) { if err := st.SetSlot(constants.GenesisSlot); err != nil { return nil, err } fork := ctypes.NewFork(genesisVersion, genesisVersion, constants.GenesisEpoch) if err := st.SetFork(fork); err != nil { return nil, err } if err := sp.ProcessFork(st, execPayloadHeader.GetTimestamp(), true); err != nil { return nil, err } eth1Data := &ctypes.Eth1Data{ DepositRoot: deposits.HashTreeRoot(), DepositCount: 0, BlockHash: execPayloadHeader.GetBlockHash(), } if err := st.SetEth1Data(eth1Data); err != nil { return nil, err } blkHeader := GenesisBlockHeader(genesisVersion) if err := st.SetLatestBlockHeader(blkHeader); err != nil { return nil, err } if err := sp.seedRandaoMix( st, execPayloadHeader.GetBlockHash(), ); err != nil { return nil, err } // ingest deposits & do genesis‐activation if err := sp.processGenesisDepositsAndActivations(st, deposits); err != nil { return nil, err } validators, err := st.GetValidators() if err != nil { return nil, err } if err = st.SetGenesisValidatorsRoot(validators.HashTreeRoot()); err != nil { return nil, err } if err = st.SetLatestExecutionPayloadHeader(execPayloadHeader); err != nil { return nil, err } // seed historical block‑ and state‑roots if err = sp.seedHistoricalRoots(st); err != nil { return nil, err } if err = st.SetNextWithdrawalIndex(0); err != nil { return nil, err } if err = st.SetNextWithdrawalValidatorIndex(0); err != nil { return nil, err } if err = st.SetTotalSlashing(0); err != nil { return nil, err } activeVals, err := getActiveVals(st, constants.GenesisEpoch) if err != nil { return nil, err } return validatorSetsDiffs(nil, activeVals), nil } // seedRandaoMix writes the initial RANDAO mixes. func (sp *StateProcessor) seedRandaoMix( st *statedb.StateDB, hash common.ExecutionHash, ) error { for i := range sp.cs.EpochsPerHistoricalVector() { if err := st.UpdateRandaoMixAtIndex( i, common.Bytes32(hash), ); err != nil { return err } } return nil } // seedHistoricalRoots zero‑primes the block and state‐roots. func (sp *StateProcessor) seedHistoricalRoots(st *statedb.StateDB) error { for i := range sp.cs.HistoricalRootsLimit() { if err := st.UpdateBlockRootAtIndex(i, common.Root{}); err != nil { return err } if err := st.UpdateStateRootAtIndex(i, common.Root{}); err != nil { return err } } return nil } // processGenesisDepositsAndActivations handles the eth1 deposit index, // validates and ingests each deposit, then does the genesis activation pass. func (sp *StateProcessor) processGenesisDepositsAndActivations( st *statedb.StateDB, deposits ctypes.Deposits, ) error { // Before processing deposits, set the eth1 deposit index to 0. if err := st.SetEth1DepositIndex(constants.FirstDepositIndex); err != nil { return err } if err := validateGenesisDeposits( st, deposits, sp.cs.ValidatorSetCap(), ); err != nil { return err } for _, dep := range deposits { if err := sp.processDeposit(st, dep); err != nil { return err } } return sp.processGenesisActivation(st) } func (sp *StateProcessor) processGenesisActivation(st *statedb.StateDB) error { vals, err := st.GetValidators() if err != nil { return fmt.Errorf("genesis activation, failed listing validators: %w", err) } minEffectiveBalance := sp.cs.MinActivationBalance() var idx math.ValidatorIndex for _, val := range vals { if val.GetEffectiveBalance() < minEffectiveBalance { continue } val.SetActivationEligibilityEpoch(constants.GenesisEpoch) val.SetActivationEpoch(constants.GenesisEpoch) idx, err = st.ValidatorIndexByPubkey(val.GetPubkey()) if err != nil { return err } if err = st.UpdateValidatorAtIndex(idx, val); err != nil { return err } } return nil } func GenesisBlockHeader(genesisVersion common.Version) *ctypes.BeaconBlockHeader { versionable := ctypes.NewVersionable(genesisVersion) blkBody := &ctypes.BeaconBlockBody{ Versionable: versionable, Eth1Data: &ctypes.Eth1Data{}, ExecutionPayload: &ctypes.ExecutionPayload{ Versionable: versionable, ExtraData: make([]byte, ctypes.ExtraDataSize), }, } blkHeader := &ctypes.BeaconBlockHeader{ Slot: constants.GenesisSlot, ProposerIndex: 0, ParentBlockRoot: common.Root{}, StateRoot: common.Root{}, BodyRoot: blkBody.HashTreeRoot(), } return blkHeader } ================================================ FILE: state-transition/core/state_processor_genesis_test.go ================================================ //go:build test // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core_test import ( "fmt" "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" statetransition "github.com/berachain/beacon-kit/testing/state-transition" "github.com/stretchr/testify/require" ) //nolint:paralleltest // uses envars func TestInitialize(t *testing.T) { csDevnet := setupChain(t) csTestnet, specErr := spec.TestnetChainSpec() require.NoError(t, specErr) csMainnet, specErr := spec.MainnetChainSpec() require.NoError(t, specErr) specs := []chain.Spec{csDevnet, csTestnet, csMainnet} for i, cs := range specs { t.Run(fmt.Sprintf("TestInitialize-%d", i), func(t *testing.T) { sp, st, _, _, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() increment = cs.EffectiveBalanceIncrement() minBalance = cs.MinActivationBalance() - increment ) // create test inputs var ( genDeposits = []*types.Deposit{ { Pubkey: [48]byte{0x01}, Amount: maxBalance, Credentials: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x01}, ), Index: uint64(0), }, { Pubkey: [48]byte{0x02}, Amount: minBalance + increment, Credentials: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x02}, ), Index: uint64(1), }, { Pubkey: [48]byte{0x03}, Amount: minBalance, Credentials: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x03}, ), Index: uint64(2), }, { Pubkey: [48]byte{0x04}, Amount: 2 * maxBalance, Credentials: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x04}, ), Index: uint64(3), }, { Pubkey: [48]byte{0x05}, Amount: minBalance - increment, Credentials: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x05}, ), Index: uint64(4), }, { Pubkey: [48]byte{0x06}, Amount: minBalance + increment*3/2, Credentials: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x06}, ), Index: uint64(5), }, { Pubkey: [48]byte{0x07}, Amount: maxBalance + increment/10, Credentials: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x07}, ), Index: uint64(6), }, { Pubkey: [48]byte{0x08}, Amount: minBalance + increment*99/100, Credentials: types.NewCredentialsFromExecutionAddress( common.ExecutionAddress{0x08}, ), Index: uint64(7), }, } goodDeposits = []*types.Deposit{ genDeposits[0], genDeposits[1], genDeposits[3], genDeposits[5], genDeposits[6], } executionPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } fork = &types.Fork{ PreviousVersion: cs.GenesisForkVersion(), CurrentVersion: cs.GenesisForkVersion(), Epoch: constants.GenesisEpoch, } ) // run test genVals, initErr := sp.InitializeBeaconStateFromEth1( st, genDeposits, executionPayloadHeader, fork.CurrentVersion, ) // check outputs require.NoError(t, initErr) require.Len(t, genVals, len(goodDeposits)) // check beacon state changes resSlot, err := st.GetSlot() require.NoError(t, err) require.Equal(t, constants.GenesisSlot, resSlot) resFork, err := st.GetFork() require.NoError(t, err) require.Equal(t, fork, resFork) for _, dep := range goodDeposits { checkValidator(t, cs, st, dep) } // check that deposit index is duly set. On devnet // deposit index is set to the last accepted deposit. latestValIdx, err := st.GetEth1DepositIndex() require.NoError(t, err) require.Equal(t, uint64(len(genDeposits)), latestValIdx) }) } } func checkValidator( t *testing.T, cs chain.Spec, bs *statetransition.TestBeaconStateT, dep *types.Deposit, ) { t.Helper() idx, err := bs.ValidatorIndexByPubkey(dep.Pubkey) require.NoError(t, err) val, err := bs.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, dep.Pubkey, val.Pubkey) var ( maxBalance = cs.MaxEffectiveBalance() increment = cs.EffectiveBalanceIncrement() minBalance = cs.MinActivationBalance() - increment ) switch { case dep.Amount >= maxBalance: require.Equal(t, maxBalance, val.EffectiveBalance) case dep.Amount > minBalance && dep.Amount < maxBalance: // Effective balance must be a multiple of increment. // If balance is not, effective balance is rounded down if dep.Amount%increment == 0 { require.Equal(t, dep.Amount, val.EffectiveBalance) } else { require.Less(t, val.EffectiveBalance, dep.Amount) require.Greater(t, val.EffectiveBalance, dep.Amount-increment) require.Zero(t, val.EffectiveBalance%increment) } case dep.Amount <= minBalance: require.Equal(t, math.Gwei(0), val.EffectiveBalance) } require.Equal(t, constants.GenesisEpoch, val.GetActivationEligibilityEpoch()) require.Equal(t, constants.GenesisEpoch, val.GetActivationEpoch()) valBal, err := bs.GetBalance(idx) require.NoError(t, err) require.Equal(t, dep.Amount, valBal) } ================================================ FILE: state-transition/core/state_processor_payload.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "context" payloadtime "github.com/berachain/beacon-kit/beacon/payload-time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "golang.org/x/sync/errgroup" ) // processExecutionPayload processes the execution payload and ensures it // matches the local state. func (sp *StateProcessor) processExecutionPayload( txCtx ReadOnlyContext, st *statedb.StateDB, blk *ctypes.BeaconBlock, parentProposerPubkey *crypto.BLSPubkey, ) error { var ( body = blk.GetBody() payload = body.GetExecutionPayload() header = &ctypes.ExecutionPayloadHeader{} // appeases nilaway g, ctx = errgroup.WithContext(txCtx.ConsensusCtx()) ) payloadTimestamp := payload.GetTimestamp().Unwrap() consensusTimestamp := txCtx.ConsensusTime().Unwrap() sp.metrics.gaugeTimestamps(payloadTimestamp, consensusTimestamp) sp.logger.Info("processExecutionPayload", "consensus height", blk.GetSlot().Unwrap(), "payload height", payload.GetNumber().Unwrap(), "payload timestamp", payloadTimestamp, "consensus timestamp", consensusTimestamp, "verify payload", txCtx.VerifyPayload(), ) if version.EqualsOrIsAfter(blk.GetForkVersion(), version.Electra()) { requests, getErr := blk.GetBody().GetExecutionRequests() if getErr != nil { return getErr } sp.logger.Info( "Processing execution requests", "deposits", len(requests.Deposits), "withdrawals", len(requests.Withdrawals), "consolidations", len(requests.Consolidations), ) } // Perform payload verification only if the context is configured as such. if txCtx.VerifyPayload() { g.Go(func() error { return sp.validateExecutionPayload(ctx, txCtx.ConsensusTime(), st, blk, parentProposerPubkey) }) } // Get the execution payload header. g.Go(func() error { var err error header, err = payload.ToHeader() return err }) if err := g.Wait(); err != nil { return err } if txCtx.MeterGas() { sp.metrics.gaugeBlockGasUsed( payload.GetNumber(), payload.GetGasUsed(), payload.GetBlobGasUsed(), ) } // Set the latest execution payload header. return st.SetLatestExecutionPayloadHeader(header) } // validateExecutionPayload validates the execution payload against both local // state and the execution engine. func (sp *StateProcessor) validateExecutionPayload( ctx context.Context, consensusTime math.U64, st ReadOnlyBeaconState, blk *ctypes.BeaconBlock, parentProposerPubkey *crypto.BLSPubkey, ) error { if err := sp.validateStatelessPayload(blk); err != nil { return err } return sp.validateStatefulPayload(ctx, consensusTime, st, blk, parentProposerPubkey) } // validateStatelessPayload performs stateless checks on the execution payload. func (sp *StateProcessor) validateStatelessPayload(blk *ctypes.BeaconBlock) error { body := blk.GetBody() payload := body.GetExecutionPayload() // Verify the number of withdrawals. withdrawals := payload.GetWithdrawals() if uint64(len(withdrawals)) > sp.cs.MaxWithdrawalsPerPayload() { return errors.Wrapf( ErrExceedMaximumWithdrawals, "too many withdrawals, expected: %d, got: %d", sp.cs.MaxWithdrawalsPerPayload(), len(withdrawals), ) } // No need to verify bounded number of commitments here, since it is // verified early on in ProcessProposal. return nil } // validateStatefulPayload performs stateful checks on the execution payload. func (sp *StateProcessor) validateStatefulPayload( ctx context.Context, consensusTime math.U64, st ReadOnlyBeaconState, blk *ctypes.BeaconBlock, parentProposerPubkey *crypto.BLSPubkey, ) error { body := blk.GetBody() payload := body.GetExecutionPayload() lph, err := st.GetLatestExecutionPayloadHeader() if err != nil { return err } // Check chain canonicity safeHash := lph.GetBlockHash() if safeHash != payload.GetParentHash() { return errors.Wrapf( ErrParentPayloadHashMismatch, "parent block with hash %x is not finalized, expected finalized hash %x", payload.GetParentHash(), safeHash, ) } // Verify that the payload stamp is within a reasonable bound if err = payloadtime.Verify( consensusTime, lph.GetTimestamp(), payload.GetTimestamp(), ); err != nil { return err } payloadReq, err := ctypes.BuildNewPayloadRequestFromFork(blk, parentProposerPubkey) if err != nil { return err } // First we verify the block hash and versioned hashes are valid. // TODO: is this required? Or will the EL handle this for us during // new payload? if err = payloadReq.HasValidVersionedAndBlockHashes(); err != nil { return err } // TODO: set retryOnSyncingStatus to false if we are in FinalizeBlock. // Otherwise leave as true. This is ok to leave this way for now. if err = sp.executionEngine.NotifyNewPayload(ctx, payloadReq, true); err != nil { return err } // Verify RANDAO epoch, err := st.GetEpoch() if err != nil { return err } expectedMix, err := st.GetRandaoMixAtIndex(epoch.Unwrap() % sp.cs.EpochsPerHistoricalVector()) if err != nil { return err } if payload.GetPrevRandao() != expectedMix { return errors.Wrapf( ErrRandaoMixMismatch, "prev randao does not match, expected: %x, got: %x", expectedMix, payload.GetPrevRandao(), ) } return nil } ================================================ FILE: state-transition/core/state_processor_payload_test.go ================================================ //go:build test // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core_test import ( "testing" "time" "cosmossdk.io/log" storetypes "cosmossdk.io/store/types" payloadtime "github.com/berachain/beacon-kit/beacon/payload-time" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" statedb "github.com/berachain/beacon-kit/state-transition/core/state" statetransition "github.com/berachain/beacon-kit/testing/state-transition" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) // TestPayloadTimestampVerification ensures that payload timestamp // is properly validated // //nolint:paralleltest // uses envars func TestPayloadTimestampVerification(t *testing.T) { // Create state processor to test cs := setupChain(t) sp, st, ds, ctx, cms, mockEngine := statetransition.SetupTestState(t, cs) // process genesis before any other block genesisTime := time.Now().Truncate(time.Second) genesisFork := cs.ActiveForkVersionForTimestamp(math.U64(genesisTime.Unix())) require.Equal(t, genesisFork, cs.GenesisForkVersion()) var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}), Amount: cs.MaxEffectiveBalance(), Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(genesisFork), } ) genPayloadHeader.Timestamp = math.U64(genesisTime.Unix()) _, err := sp.InitializeBeaconStateFromEth1(st, genDeposits, genPayloadHeader, genesisFork) require.NoError(t, err) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) // write genesis changes to make them available for next blocks //nolint:errcheck // false positive as this has no return value ctx.ConsensusCtx().(sdk.Context).MultiStore().(storetypes.CacheMultiStore).Write() // Test cases consensusBlkTime := genesisTime.Add(time.Second) tests := []struct { name string setupMocksF func() payloadTime time.Time expectedErr error }{ { name: "Payload timestamp < consensus timestamp", setupMocksF: func() { mockEngine.EXPECT().NotifyNewPayload(mock.Anything, mock.Anything, mock.Anything).Return(nil) }, payloadTime: consensusBlkTime.Add(-10 * time.Second), expectedErr: nil, }, { name: "Payload timestamp == consensus timestamp", setupMocksF: func() { mockEngine.EXPECT().NotifyNewPayload(mock.Anything, mock.Anything, mock.Anything).Return(nil) }, payloadTime: consensusBlkTime, expectedErr: nil, }, { name: "Payload timestamp > consensus timestamp", setupMocksF: func() { mockEngine.EXPECT().NotifyNewPayload(mock.Anything, mock.Anything, mock.Anything).Return(nil) }, payloadTime: consensusBlkTime.Add(time.Second), expectedErr: nil, }, { name: "Payload timestamp >> consensus timestamp", setupMocksF: func() { // no mock here, since timestamp validation fails }, payloadTime: consensusBlkTime.Add(2 * time.Second), expectedErr: payloadtime.ErrTooFarInTheFuture, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // these test cases should not be run in parallel // since state processors is shared by them tt.setupMocksF() // create independent states per each test sdkCtx := sdk.NewContext(cms.CacheMultiStore(), true, log.NewNopLogger()) testSt := statedb.NewBeaconStateFromDB( st.KVStore.WithContext(sdkCtx), cs, sdkCtx.Logger(), metrics.NewNoOpTelemetrySink(), ) tCtx := transition.NewTransitionCtx( sdkCtx, math.U64(consensusBlkTime.Unix()), statetransition.DummyProposerAddr, ). WithVerifyPayload(true). WithVerifyRandao(false). WithVerifyResult(false). WithMeterGas(false) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex( ctx.ConsensusCtx(), constants.FirstDepositIndex, uint64(len(genDeposits))+cs.MaxDepositsPerBlock(), ) require.NoError(t, err) blk := buildNextBlock( t, cs, testSt, types.NewEth1Data(depRoot), math.U64(tt.payloadTime.Unix()), nil, &types.ExecutionRequests{}, testSt.EVMInflationWithdrawal(math.U64(tt.payloadTime.Unix())), ) _, err = sp.Transition(tCtx, testSt, blk) if tt.expectedErr == nil { require.NoError(t, err) } else { require.ErrorIs(t, err, tt.expectedErr) } }) } } ================================================ FILE: state-transition/core/state_processor_randao.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/crypto/sha256" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/go-faster/xor" ) // processRandaoReveal processes the randao reveal and // ensures it matches the local state. func (sp *StateProcessor) processRandaoReveal( ctx ReadOnlyContext, st *statedb.StateDB, blk *ctypes.BeaconBlock, ) error { epoch, err := st.GetEpoch() if err != nil { return err } // Ensure the proposer index is valid. proposer, err := st.ValidatorByIndex(blk.GetProposerIndex()) if err != nil { return err } genesisValidatorsRoot, err := st.GetGenesisValidatorsRoot() if err != nil { return err } body := blk.GetBody() timestamp := blk.GetTimestamp() fd := ctypes.NewForkData(sp.cs.ActiveForkVersionForTimestamp(timestamp), genesisValidatorsRoot) if ctx.VerifyRandao() { signingRoot := fd.ComputeRandaoSigningRoot(sp.cs.DomainTypeRandao(), epoch) reveal := body.GetRandaoReveal() if err = sp.signer.VerifySignature( proposer.GetPubkey(), signingRoot[:], reveal, ); err != nil { return fmt.Errorf("state processor failed randao checks: %w", err) } } prevMix, err := st.GetRandaoMixAtIndex(epoch.Unwrap() % sp.cs.EpochsPerHistoricalVector()) if err != nil { return err } return st.UpdateRandaoMixAtIndex( epoch.Unwrap()%sp.cs.EpochsPerHistoricalVector(), sp.buildRandaoMix(prevMix, body.GetRandaoReveal()), ) } // processRandaoMixesReset as defined in the Ethereum 2.0 specification. // https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#randao-mixes-updates func (sp *StateProcessor) processRandaoMixesReset( st *statedb.StateDB, ) error { epoch, err := st.GetEpoch() if err != nil { return err } mix, err := st.GetRandaoMixAtIndex(epoch.Unwrap() % sp.cs.EpochsPerHistoricalVector()) if err != nil { return err } return st.UpdateRandaoMixAtIndex((epoch.Unwrap()+1)%sp.cs.EpochsPerHistoricalVector(), mix) } // buildRandaoMix as defined in the Ethereum 2.0 specification. func (sp *StateProcessor) buildRandaoMix( mix common.Bytes32, reveal crypto.BLSSignature, ) common.Bytes32 { newMix := make([]byte, constants.RootLength) revealHash := sha256.Hash(reveal[:]) // Apparently this library giga fast? Good project? lmeow. // It is safe to ignore this error, since it is guaranteed that // mix[:] and revealHash[:] are both Bytes32. _ = xor.Bytes( newMix, mix[:], revealHash[:], ) return common.Bytes32(newMix) } ================================================ FILE: state-transition/core/state_processor_signature.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/crypto" statedb "github.com/berachain/beacon-kit/state-transition/core/state" ) func (sp *StateProcessor) GetSignatureVerifierFn(st *statedb.StateDB) ( func(blk *ctypes.BeaconBlock, signature crypto.BLSSignature) error, error, ) { genesisValidatorsRoot, err := st.GetGenesisValidatorsRoot() if err != nil { return nil, err } return func(blk *ctypes.BeaconBlock, signature crypto.BLSSignature) error { fd := ctypes.NewForkData( sp.cs.ActiveForkVersionForTimestamp(blk.GetTimestamp()), genesisValidatorsRoot, ) domain := fd.ComputeDomain(sp.cs.DomainTypeProposer()) //nolint:govet // shadow proposer, err := st.ValidatorByIndex(blk.GetProposerIndex()) if err != nil { return err } signingRoot := ctypes.ComputeSigningRoot(blk, domain) return sp.signer.VerifySignature(proposer.GetPubkey(), signingRoot[:], signature) }, nil } ================================================ FILE: state-transition/core/state_processor_staking.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "fmt" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/ethereum/go-ethereum/params" ) // processOperations processes the operations and ensures they match the local state. func (sp *StateProcessor) processOperations( ctx ReadOnlyContext, st *state.StateDB, blk *ctypes.BeaconBlock, ) error { // Verify that outstanding deposits are processed up to the maximum number of deposits. // // Unlike Eth 2.0 specs we don't check that // `len(body.deposits) == min(MAX_DEPOSITS, state.eth1_data.deposit_count - state.eth1_deposit_index)` deposits := blk.GetBody().GetDeposits() if uint64(len(deposits)) > sp.cs.MaxDepositsPerBlock() { return errors.Wrapf( ErrExceedsBlockDepositLimit, "expected: %d, got: %d", sp.cs.MaxDepositsPerBlock(), len(deposits), ) } // Instead we directly compare block deposits with our local store ones. if err := ValidateNonGenesisDeposits( ctx.ConsensusCtx(), st, sp.ds, sp.cs.MaxDepositsPerBlock(), deposits, blk.GetBody().GetEth1Data().DepositRoot, ); err != nil { return err } for _, dep := range deposits { if err := sp.processDeposit(st, dep); err != nil { return err } } if version.EqualsOrIsAfter(blk.GetForkVersion(), version.Electra()) { // After Electra, validators can request withdrawals through execution requests which must be handled. requests, err := blk.GetBody().GetExecutionRequests() if err != nil { return err } for _, withdrawal := range requests.Withdrawals { if withdrawErr := sp.processWithdrawalRequest(st, withdrawal); withdrawErr != nil { return withdrawErr } } } return st.SetEth1Data(blk.GetBody().Eth1Data) } // processDeposit processes the deposit and ensures it matches the local state. func (sp *StateProcessor) processDeposit(st *state.StateDB, dep *ctypes.Deposit) error { eth1DepositIndex, err := st.GetEth1DepositIndex() if err != nil { return err } if err = st.SetEth1DepositIndex(eth1DepositIndex + 1); err != nil { return err } sp.logger.Info( "Processed deposit to set Eth 1 deposit index", "previous", eth1DepositIndex, "new", eth1DepositIndex+1, ) if err = sp.applyDeposit(st, dep); err != nil { return fmt.Errorf("failed to apply deposit: %w", err) } return nil } // applyDeposit processes the deposit and ensures it matches the local state. func (sp *StateProcessor) applyDeposit(st *state.StateDB, dep *ctypes.Deposit) error { idx, err := st.ValidatorIndexByPubkey(dep.GetPubkey()) if err != nil { sp.logger.Info("Validator does not exist so creating", "pubkey", dep.GetPubkey(), "index", dep.GetIndex(), "deposit_amount", dep.GetAmount()) // If the validator does not exist, we add the validator. // TODO: improve error handling by distinguishing // ErrNotFound from other kind of errors return sp.createValidator(st, dep) } // if validator exist, just update its balance if err = st.IncreaseBalance(idx, dep.GetAmount()); err != nil { return err } sp.logger.Info( "Processed deposit to increase balance", "deposit_amount", float64(dep.GetAmount().Unwrap())/params.GWei, "validator_index", idx, ) return nil } // createValidator creates a validator if the deposit is valid. func (sp *StateProcessor) createValidator(st *state.StateDB, dep *ctypes.Deposit) error { // Get the current slot. slot, err := st.GetSlot() if err != nil { return err } // At genesis, the validators sign over an empty root. genesisValidatorsRoot := common.Root{} if slot != 0 { // Get the genesis validators root to be used to find fork data later. genesisValidatorsRoot, err = st.GetGenesisValidatorsRoot() if err != nil { return err } } // Check that the deposit has the ETH1 withdrawal credentials. if !dep.HasEth1WithdrawalCredentials() { sp.logger.Warn( "adding validator with non-ETH1 withdrawal credentials -- NOT withdrawable", "pubkey", dep.GetPubkey().String(), "deposit_index", dep.GetIndex(), "amount_gwei", dep.GetAmount().Unwrap(), ) sp.metrics.incrementValidatorNotWithdrawable() } // Verify that the message was signed correctly. err = dep.VerifySignature( ctypes.NewForkData( // Deposits must be signed with GENESIS_FORK_VERSION. sp.cs.GenesisForkVersion(), genesisValidatorsRoot, ), sp.cs.DomainTypeDeposit(), sp.signer.VerifySignature, ) if err != nil { // Ignore deposits that fail the signature check. sp.logger.Warn( "failed deposit signature verification", "pubkey", dep.GetPubkey().String(), "deposit_index", dep.GetIndex(), "amount_gwei", dep.GetAmount().Unwrap(), "error", err, ) sp.metrics.incrementDepositStakeLost() return nil } // Add the validator to the registry. return sp.addValidatorToRegistry(st, dep) } // addValidatorToRegistry adds a validator to the registry. func (sp *StateProcessor) addValidatorToRegistry(st *state.StateDB, dep *ctypes.Deposit) error { val := ctypes.NewValidatorFromDeposit( dep.GetPubkey(), dep.GetWithdrawalCredentials(), dep.GetAmount(), sp.cs.EffectiveBalanceIncrement(), sp.cs.MaxEffectiveBalance(), ) if err := st.AddValidator(val); err != nil { return err } idx, err := st.ValidatorIndexByPubkey(val.GetPubkey()) if err != nil { return err } if err = st.IncreaseBalance(idx, dep.GetAmount()); err != nil { return err } sp.logger.Info( "Processed deposit to create new validator", "deposit_amount", float64(dep.GetAmount().Unwrap())/params.GWei, "validator_index", idx, "withdrawal_epoch", val.GetWithdrawableEpoch(), ) return nil } ================================================ FILE: state-transition/core/state_processor_staking_test.go ================================================ //go:build test // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core_test import ( "testing" "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" statetransition "github.com/berachain/beacon-kit/testing/state-transition" "github.com/stretchr/testify/require" ) // TestTransitionUpdateValidators shows that when validator is // updated (increasing amount), corresponding balance is updated. // //nolint:paralleltest // uses envars func TestTransitionUpdateValidators(t *testing.T) { cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() increment = cs.EffectiveBalanceIncrement() minBalance = cs.MinActivationBalance() emptyCredentials = types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}) ) // STEP 0: Setup initial state via genesis var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: emptyCredentials, Amount: minBalance + increment, Index: uint64(0), }, { Pubkey: [48]byte{0x01}, Credentials: emptyCredentials, Amount: maxBalance - 6*increment, Index: uint64(1), }, { Pubkey: [48]byte{0x03}, Credentials: emptyCredentials, Amount: maxBalance - 3*increment, Index: uint64(2), }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = uint64(len(genDeposits)) ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) valDiff, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) require.Len(t, valDiff, len(genDeposits)) // STEP 1: top up a genesis validator balance blkDeposit := &types.Deposit{ Pubkey: genDeposits[2].Pubkey, Credentials: emptyCredentials, Amount: 2 * increment, // twice to account for hysteresis Index: uint64(len(genDeposits)), } blkDeposits := []*types.Deposit{blkDeposit} totalDepositsCount++ // make sure included deposit is already available in deposit store require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), blkDeposits)) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) blk1 := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, blkDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // run the test valDiff, err = sp.Transition(ctx, st, blk1) require.NoError(t, err) require.Empty(t, valDiff) // validators set updates only at epoch turn // check validator balances are duly updated, that is: // - balance is updated immediately // - effective balance is updated only at the epoch turn expectedBalance := genDeposits[2].Amount + blkDeposit.Amount expectedEffectiveBalance := genDeposits[2].Amount idx, err := st.ValidatorIndexByPubkey(genDeposits[2].Pubkey) require.NoError(t, err) balance, err := st.GetBalance(idx) require.NoError(t, err) require.Equal(t, expectedBalance, balance) val, err := st.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, expectedEffectiveBalance, val.EffectiveBalance) // check that validator index is still correct latestValIdx, err := st.GetEth1DepositIndex() require.NoError(t, err) require.Equal(t, uint64(len(genDeposits)+1), latestValIdx) // STEP 2: check that effective balance is updated once next epoch arrives blk := moveToEndOfEpoch(t, blk1, cs, sp, st, ctx, depRoot) // finally the block turning epoch blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) valDiff, err = sp.Transition(ctx, st, blk) require.NoError(t, err) require.Len(t, valDiff, 1) // just topped up one validator require.Equal( t, &transition.ValidatorUpdate{ Pubkey: blkDeposit.Pubkey, EffectiveBalance: expectedBalance, }, valDiff[0], ) expectedEffectiveBalance = expectedBalance balance, err = st.GetBalance(idx) require.NoError(t, err) require.Equal(t, expectedBalance, balance) val, err = st.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, expectedEffectiveBalance, val.EffectiveBalance) } // TestTransitionCreateValidator shows the lifecycle // of a validator creation. // //nolint:paralleltest // uses envars func TestTransitionCreateValidator(t *testing.T) { // Create state processor to test cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() increment = cs.EffectiveBalanceIncrement() minBalance = cs.MinActivationBalance() emptyAddress = common.ExecutionAddress{} emptyCredentials = types.NewCredentialsFromExecutionAddress(emptyAddress) ) // STEP 0: Setup initial state via genesis var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x01}, Credentials: emptyCredentials, Amount: minBalance + increment, Index: uint64(0), }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = uint64(len(genDeposits)) ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) genVals, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) require.Len(t, genVals, len(genDeposits)) // STEP 1: create a new validator blkDeposit := &types.Deposit{ Pubkey: [48]byte{0xff}, // a new key for a new validator Credentials: emptyCredentials, Amount: maxBalance, Index: uint64(len(genDeposits)), } blkDeposits := []*types.Deposit{blkDeposit} totalDepositsCount++ // make sure included deposit is already available in deposit store require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), blkDeposits)) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) blk1 := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, blkDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // run the test valDiff, err := sp.Transition(ctx, st, blk1) require.NoError(t, err) require.Empty(t, valDiff) // validators set updates only at epoch turn // check validator balances are duly updated var ( expectedBalance = blkDeposit.Amount expectedEffectiveBalance = expectedBalance ) idx, err := st.ValidatorIndexByPubkey(blkDeposit.Pubkey) require.NoError(t, err) balance, err := st.GetBalance(idx) require.NoError(t, err) require.Equal(t, expectedBalance, balance) val, err := st.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, expectedEffectiveBalance, val.EffectiveBalance) // check that validator index is still correct latestValIdx, err := st.GetEth1DepositIndex() require.NoError(t, err) require.Equal(t, uint64(len(genDeposits)+1), latestValIdx) // STEP 2: move the chain to the next epoch and show that // the extra validator is eligible for activation blk := moveToEndOfEpoch(t, blk1, cs, sp, st, ctx, depRoot) // finally the block turning epoch blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) valDiff, err = sp.Transition(ctx, st, blk) require.NoError(t, err) require.Empty(t, valDiff) // new validator is only eligible for activation extraValIdx, err := st.ValidatorIndexByPubkey(blkDeposit.Pubkey) require.NoError(t, err) extraVal, err := st.ValidatorByIndex(extraValIdx) require.NoError(t, err) require.Equal(t, math.Epoch(1), extraVal.ActivationEligibilityEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.ActivationEpoch, ) require.Equal(t, constants.FarFutureEpoch, extraVal.ExitEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.WithdrawableEpoch, ) // STEP 3: move the chain to the next epoch and show that // the extra validator is activate _ = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // finally the block turning epoch blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) // run the test valDiff, err = sp.Transition(ctx, st, blk) require.NoError(t, err) require.Len(t, valDiff, 1) require.Equal( t, &transition.ValidatorUpdate{ Pubkey: blkDeposit.Pubkey, EffectiveBalance: expectedBalance, }, valDiff[0], ) extraVal, err = st.ValidatorByIndex(extraValIdx) require.NoError(t, err) require.Equal(t, math.Epoch(1), extraVal.ActivationEligibilityEpoch) require.Equal(t, math.Epoch(2), extraVal.ActivationEpoch) require.Equal(t, constants.FarFutureEpoch, extraVal.ExitEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.WithdrawableEpoch, ) expectedBalance = blkDeposit.Amount expectedEffectiveBalance = expectedBalance balance, err = st.GetBalance(idx) require.NoError(t, err) require.Equal(t, expectedBalance, balance) val, err = st.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, expectedEffectiveBalance, val.EffectiveBalance) } // TestTransitionHittingValidatorsCap shows that the extra // validator added when validators set is at cap gets never activated // and its deposit is returned at after next epoch starts. func TestTransitionHittingValidatorsCap_ExtraSmall(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() minBalance = cs.MinActivationBalance() rndSeed = 2024 // seed used to generate unique random value ) // STEP 0: Setup genesis with GetValidatorSetCap validators // TODO: consider instead setting state artificially var ( genDeposits = make(types.Deposits, 0, cs.ValidatorSetCap()) genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = cs.ValidatorSetCap() ) // let genesis define all available validators for idx := range cs.ValidatorSetCap() { var ( key bytes.B48 creds types.WithdrawalCredentials ) key, rndSeed = generateTestPK(t, rndSeed) creds, rndSeed = generateTestExecutionAddress(t, rndSeed) genDeposits = append( genDeposits, &types.Deposit{ Pubkey: key, Credentials: creds, Amount: maxBalance, Index: idx, }, ) } require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // STEP 1: Try and add an extra validator extraValKey, rndSeed := generateTestPK(t, rndSeed) extraValCreds, _ := generateTestExecutionAddress(t, rndSeed) var ( extraValDeposit = &types.Deposit{ Pubkey: extraValKey, Credentials: extraValCreds, Amount: minBalance, Index: uint64(len(genDeposits)), } blkDeposits = []*types.Deposit{extraValDeposit} ) totalDepositsCount++ // make sure included deposit is already available in deposit store require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), blkDeposits)) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) blk1 := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, blkDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // run the test valDiff, err := sp.Transition(ctx, st, blk1) require.NoError(t, err) require.Empty(t, valDiff) extraValIdx, err := st.ValidatorIndexByPubkey(extraValDeposit.Pubkey) require.NoError(t, err) extraVal, err := st.ValidatorByIndex(extraValIdx) require.NoError(t, err) require.Equal( t, constants.FarFutureEpoch, extraVal.ActivationEligibilityEpoch, ) require.Equal( t, constants.FarFutureEpoch, extraVal.ActivationEpoch, ) require.Equal(t, constants.FarFutureEpoch, extraVal.ExitEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.WithdrawableEpoch, ) // STEP 2: move the chain to the next epoch and show that // the extra validator is eligible for activation blk := moveToEndOfEpoch(t, blk1, cs, sp, st, ctx, depRoot) // finally the block turning epoch blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) // run the test valDiff, err = sp.Transition(ctx, st, blk) require.NoError(t, err) require.Empty(t, valDiff) // check extra validator is added with Withdraw epoch duly set extraVal, err = st.ValidatorByIndex(extraValIdx) require.NoError(t, err) require.Equal(t, math.Epoch(1), extraVal.ActivationEligibilityEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.ActivationEpoch, ) require.Equal(t, constants.FarFutureEpoch, extraVal.ExitEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.WithdrawableEpoch, ) // STEP 3: move the chain to the next epoch and show that the extra // validator is activate and immediately marked for exit blk = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // finally the block turning epoch blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) // run the test valDiff, err = sp.Transition(ctx, st, blk) require.NoError(t, err) require.Empty(t, valDiff) extraVal, err = st.ValidatorByIndex(extraValIdx) require.NoError(t, err) require.Equal(t, constants.GenesisEpoch+1, extraVal.ActivationEligibilityEpoch) require.Equal(t, constants.GenesisEpoch+2, extraVal.ActivationEpoch) require.Equal(t, constants.GenesisEpoch+2, extraVal.ExitEpoch) // After electra, the withdrawable epoch is exitEpoch + sp.cs.MinValidatorWithdrawabilityDelay()) require.Equal(t, cs.MinValidatorWithdrawabilityDelay()+extraVal.ExitEpoch, extraVal.WithdrawableEpoch) // STEP 4: move the chain to the MinValidatorWithdrawabilityDelay epoch and show withdrawals // for rejected validator are enqueued then epoch := cs.SlotToEpoch(blk.Slot) require.Equal(t, math.Epoch(2), epoch) for i := epoch; i < extraVal.WithdrawableEpoch; i++ { blk = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // Epoch turning block blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } epoch = cs.SlotToEpoch(blk.Slot) require.Equal(t, extraVal.ExitEpoch+cs.MinValidatorWithdrawabilityDelay(), epoch) // Extra validator deposits will be withdrawn within 3 blocks (#Validator / MaxValidatorsPerWithdrawalsSweep) extraValAddr, err := extraValCreds.ToExecutionAddress() require.NoError(t, err) extraValBalance, err := st.GetBalance(extraValIdx) require.NoError(t, err) require.Equal(t, extraValBalance, minBalance) withdrawals := []*engineprimitives.Withdrawal{ st.EVMInflationWithdrawal(blk.GetTimestamp() + 1), { Index: 0, Validator: extraValIdx, Address: extraValAddr, Amount: extraValDeposit.Amount, }, } blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, withdrawals..., ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) extraValBalance, err = st.GetBalance(extraValIdx) require.NoError(t, err) require.Equal(t, extraValBalance, math.Gwei(0)) } // TestTransitionHittingValidatorsCap shows that if an extra validator is added with a higher amount of stake than the lowest validator // when the validator set is at cap, the lowest validator is removed at the beginning of next epoch, i.e. replaced by the new validator. // //nolint:maintidx // this end‑to‑end staking‑cap scenario is inherently complex func TestTransitionHittingValidatorsCap_ExtraBig(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() minBalance = cs.MinActivationBalance() rndSeed = 2024 // seed used to generate unique random value ) // STEP 0: Setup genesis with GetValidatorSetCap validators // TODO: consider instead setting state artificially var ( genDeposits = make(types.Deposits, 0, cs.ValidatorSetCap()) genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = cs.ValidatorSetCap() ) // let genesis define all available validators for idx := range cs.ValidatorSetCap() { var ( key bytes.B48 creds types.WithdrawalCredentials ) key, rndSeed = generateTestPK(t, rndSeed) creds, rndSeed = generateTestExecutionAddress(t, rndSeed) genDeposits = append( genDeposits, &types.Deposit{ Pubkey: key, Credentials: creds, Amount: maxBalance, Index: idx, }, ) } // make a deposit small to be ready for eviction genDeposits[0].Amount = minBalance require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) genVals, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) require.Len(t, genVals, len(genDeposits)) // STEP 1: Add an extra validator extraValKey, rndSeed := generateTestPK(t, rndSeed) extraValCreds, _ := generateTestExecutionAddress(t, rndSeed) var ( extraValDeposit = &types.Deposit{ Pubkey: extraValKey, Credentials: extraValCreds, Amount: maxBalance, Index: uint64(len(genDeposits)), } blkDeposits = []*types.Deposit{extraValDeposit} ) totalDepositsCount++ // make sure included deposit is already available in deposit store require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), blkDeposits)) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) blk1 := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, []*types.Deposit{extraValDeposit}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // run the test valDiff, err := sp.Transition(ctx, st, blk1) require.NoError(t, err) require.Empty(t, valDiff) extraValIdx, err := st.ValidatorIndexByPubkey(extraValDeposit.Pubkey) require.NoError(t, err) extraVal, err := st.ValidatorByIndex(extraValIdx) require.NoError(t, err) require.Equal( t, constants.FarFutureEpoch, extraVal.ActivationEligibilityEpoch, ) require.Equal( t, constants.FarFutureEpoch, extraVal.ActivationEpoch, ) require.Equal(t, constants.FarFutureEpoch, extraVal.ExitEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.WithdrawableEpoch, ) smallestValIdx, err := st.ValidatorIndexByPubkey(genDeposits[0].Pubkey) require.NoError(t, err) smallestVal, err := st.ValidatorByIndex(smallestValIdx) require.NoError(t, err) require.Equal(t, constants.GenesisEpoch, smallestVal.ActivationEligibilityEpoch) require.Equal(t, constants.GenesisEpoch, smallestVal.ActivationEpoch) require.Equal( t, constants.FarFutureEpoch, smallestVal.ExitEpoch, ) require.Equal( t, constants.FarFutureEpoch, smallestVal.WithdrawableEpoch, ) // STEP 2: move the chain to the next epoch and show that // the extra validator is eligible for activation blk := moveToEndOfEpoch(t, blk1, cs, sp, st, ctx, depRoot) // finally the block turning epoch blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) // run the test valDiff, err = sp.Transition(ctx, st, blk) require.NoError(t, err) require.Empty(t, valDiff) // check extra validator is added with Withdraw epoch duly set extraVal, err = st.ValidatorByIndex(extraValIdx) require.NoError(t, err) require.Equal(t, math.Epoch(1), extraVal.ActivationEligibilityEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.ActivationEpoch, ) require.Equal(t, constants.FarFutureEpoch, extraVal.ExitEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.WithdrawableEpoch, ) smallestVal, err = st.ValidatorByIndex(smallestValIdx) require.NoError(t, err) require.Equal(t, constants.GenesisEpoch, smallestVal.ActivationEligibilityEpoch) require.Equal(t, constants.GenesisEpoch, smallestVal.ActivationEpoch) require.Equal( t, constants.FarFutureEpoch, smallestVal.ExitEpoch, ) require.Equal( t, constants.FarFutureEpoch, smallestVal.WithdrawableEpoch, ) // STEP 3: move the chain to the next epoch and show that the extra // validator is activated and genesis validator immediately marked for exit blk = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // finally the block turning epoch blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) // run the test valDiff, err = sp.Transition(ctx, st, blk) require.NoError(t, err) require.Len(t, valDiff, 2) require.Equal( t, &transition.ValidatorUpdate{ Pubkey: extraVal.Pubkey, EffectiveBalance: extraVal.EffectiveBalance, }, valDiff[0], ) require.Equal( t, &transition.ValidatorUpdate{ Pubkey: smallestVal.Pubkey, EffectiveBalance: 0, }, valDiff[1], ) extraVal, err = st.ValidatorByIndex(extraValIdx) require.NoError(t, err) require.Equal(t, constants.GenesisEpoch+1, extraVal.ActivationEligibilityEpoch) require.Equal(t, constants.GenesisEpoch+2, extraVal.ActivationEpoch) require.Equal(t, constants.FarFutureEpoch, extraVal.ExitEpoch) require.Equal( t, constants.FarFutureEpoch, extraVal.WithdrawableEpoch, ) smallestVal, err = st.ValidatorByIndex(smallestValIdx) require.NoError(t, err) require.Equal(t, constants.GenesisEpoch, smallestVal.ActivationEligibilityEpoch) require.Equal(t, constants.GenesisEpoch, smallestVal.ActivationEpoch) require.Equal(t, constants.GenesisEpoch+2, smallestVal.ExitEpoch) require.Equal(t, smallestVal.ExitEpoch+cs.MinValidatorWithdrawabilityDelay(), smallestVal.WithdrawableEpoch) epoch := cs.SlotToEpoch(blk.Slot) require.Equal(t, math.Epoch(2), epoch) // STEP 4: move the chain to the MinValidatorWithdrawabilityDelay epoch and show withdrawals // for rejected validator are enqueued within 3 blocks // (#Validator / MaxValidatorsPerWithdrawalsSweep)) for i := epoch; i < smallestVal.WithdrawableEpoch; i++ { blk = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // Epoch turning block blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } epoch = cs.SlotToEpoch(blk.Slot) require.Equal(t, smallestVal.ExitEpoch+cs.MinValidatorWithdrawabilityDelay(), epoch) valToEvict := genDeposits[0] valToEvictAddr, err := valToEvict.Credentials.ToExecutionAddress() require.NoError(t, err) withdrawals := []*engineprimitives.Withdrawal{ st.EVMInflationWithdrawal(blk.GetTimestamp() + 1), { Index: 0, Validator: smallestValIdx, Address: valToEvictAddr, Amount: valToEvict.Amount, }, } blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, withdrawals..., ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } ================================================ FILE: state-transition/core/state_processor_test.go ================================================ //go:build test // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core_test import ( "testing" "time" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" statetransition "github.com/berachain/beacon-kit/testing/state-transition" "github.com/stretchr/testify/require" ) func TestStateProcessor_ProcessSlots(t *testing.T) { t.Parallel() cs := setupChain(t) //nolint:dogsled // used for testing sp, st, _, _, _, _ := statetransition.SetupTestState(t, cs) // Initialize state with genesis. genesisTime := time.Now().Truncate(time.Second) var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}), Amount: cs.MaxEffectiveBalance(), Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } ) genPayloadHeader.Timestamp = math.U64(genesisTime.Unix()) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Grab slot that will result in epoch processing in ProcessSlots. epochSlot := math.Slot(cs.SlotsPerEpoch()) - 1 // Setup test cases tests := []struct { name string stateSlot math.Slot slot math.Slot wantErr bool }{ {"equal-slot", epochSlot, epochSlot, false}, {"correct-slot", epochSlot, epochSlot + 1, false}, {"too-large-slot", epochSlot, epochSlot + 2, true}, {"too-small-slot", epochSlot, epochSlot - 1, true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err = st.SetSlot(tt.stateSlot) require.NoError(t, err) _, err = sp.ProcessSlots(st, tt.slot) if (err != nil) != tt.wantErr { t.Errorf("ProcessSlots() error = %v, wantErr %v", err, tt.wantErr) return } }) } } ================================================ FILE: state-transition/core/state_processor_validators.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( stdbytes "bytes" "fmt" "slices" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/sourcegraph/conc/iter" ) func (sp *StateProcessor) processRegistryUpdates(st *statedb.StateDB) error { currEpoch, err := st.GetEpoch() if err != nil { return fmt.Errorf("registry update, failed loading slot: %w", err) } activationEpoch := currEpoch + 1 minActivationBalance := sp.cs.MinActivationBalance() vals, err := st.GetValidators() if err != nil { return fmt.Errorf("registry update, failed listing validators: %w", err) } // We do not currently have a cap on validator churn, // so we can process validators activations in a single loop var idx math.ValidatorIndex for si, val := range vals { valModified := false if val.IsEligibleForActivationQueue(minActivationBalance) { val.SetActivationEligibilityEpoch(activationEpoch) valModified = true } // Note: without slashing and voluntary withdrawals, there is no way // for an active validator to have its balance less or equal to EjectionBalance. // Even Partial Withdrawals through EIP7002 can only reduce a validator's balance to `MinActivationBalance`, // which is not enough to trigger a validator exit. // A Full Withdrawal through EIP7002 would initiate a validator exit directly and does not rely on `processRegistryUpdates`. // As such, we do not include the logic, but rather log an error if it is observed: /* elif is_active_validator(validator, current_epoch) and validator.effective_balance <= config.EJECTION_BALANCE: initiate_validator_exit(state, ValidatorIndex(index)) # [Modified in Electra:EIP7251] */ if val.IsActive(currEpoch) && val.GetEffectiveBalance() <= minActivationBalance-sp.cs.EffectiveBalanceIncrement() { sp.logger.Error( "registry update, validator is active but effective balance is too low", "validator_pub_key", val.Pubkey.String(), "effective_balance", val.GetEffectiveBalance().Base10(), "epoch", currEpoch.Base10(), ) } if val.IsEligibleForActivation(currEpoch) { val.SetActivationEpoch(activationEpoch) valModified = true } if valModified { idx, err = st.ValidatorIndexByPubkey(val.GetPubkey()) if err != nil { return fmt.Errorf( "registry update, failed loading validator index, state index %d: %w", si, err, ) } if err = st.UpdateValidatorAtIndex(idx, val); err != nil { return fmt.Errorf( "registry update, failed updating validator idx %d: %w", idx, err, ) } } } // validators registry will be possibly further modified in order to enforce // validators set cap. We will do that at the end of processEpoch, once all // Eth 2.0 like transitions has been done (notable EffectiveBalances // handling). return nil } func (sp *StateProcessor) processValidatorSetCap(st *statedb.StateDB) error { // Enforce the validator set cap by: // 1- retrieving validators active next epoch // 2- sorting them by stake // 3- dropping enough validators to fulfill the cap currentEpoch, err := st.GetEpoch() if err != nil { return err } nextEpochVals, err := getActiveVals(st, currentEpoch+1) if err != nil { return fmt.Errorf( "registry update, failed retrieving next epoch vals: %w", err, ) } validatorSetCap := sp.cs.ValidatorSetCap() if uint64(len(nextEpochVals)) <= validatorSetCap { // nothing to eject return nil } slices.SortFunc(nextEpochVals, func(lhs, rhs *ctypes.Validator) int { var ( val1Stake = lhs.GetEffectiveBalance() val2Stake = rhs.GetEffectiveBalance() ) switch { case val1Stake < val2Stake: return -1 case val1Stake > val2Stake: return 1 default: // validators pks are guaranteed to be different var ( val1Pk = lhs.GetPubkey() val2Pk = rhs.GetPubkey() ) return stdbytes.Compare(val1Pk[:], val2Pk[:]) } }) // We do not currently have a cap on validators churn, so we exit // validators in the next epoch, and we withdraw them after a delay depending on the fork. var idx math.ValidatorIndex for li := range uint64(len(nextEpochVals)) - validatorSetCap { valToEject := nextEpochVals[li] idx, err = st.ValidatorIndexByPubkey(valToEject.GetPubkey()) if err != nil { return fmt.Errorf( "validators cap, failed loading validator index: %w", err, ) } if exitErr := sp.InitiateValidatorExit(st, idx); exitErr != nil { return fmt.Errorf( "validator cap, failed ejecting validator idx %d: %w", li, exitErr, ) } } return nil } // Note: validatorSetsDiffs does not need to be a StateProcessor method // but it helps simplifying generic instantiation. func validatorSetsDiffs( prevEpochValidators []*ctypes.Validator, currEpochValidator []*ctypes.Validator, ) transition.ValidatorUpdates { currentValSet := iter.Map( currEpochValidator, func(val **ctypes.Validator) *transition.ValidatorUpdate { v := (*val) return &transition.ValidatorUpdate{ Pubkey: v.GetPubkey(), EffectiveBalance: v.GetEffectiveBalance(), } }, ) res := make([]*transition.ValidatorUpdate, 0) prevValsSet := make(map[string]math.Gwei, len(prevEpochValidators)) for _, v := range prevEpochValidators { pk := v.GetPubkey() prevValsSet[string(pk[:])] = v.GetEffectiveBalance() } for _, newVal := range currentValSet { key := string(newVal.Pubkey[:]) oldBal, found := prevValsSet[key] if !found { // new validator, we add it with its weight res = append(res, newVal) continue } if oldBal != newVal.EffectiveBalance { // validator updated, we add it with new weight res = append(res, newVal) } // consume pre-existing validators delete(prevValsSet, key) } // prevValsSet now contains all evicted validators (and only those) for pkBytes := range prevValsSet { //#nosec:G703 // bytes comes from a pk pk, _ := bytes.ToBytes48([]byte(pkBytes)) res = append(res, &transition.ValidatorUpdate{ Pubkey: pk, EffectiveBalance: 0, // signal val eviction to consensus }) } return res } // nextEpochValidatorSet returns the current estimation of what next epoch // validator set would be. func getActiveVals(st *statedb.StateDB, epoch math.Epoch) ([]*ctypes.Validator, error) { vals, err := st.GetValidators() if err != nil { return nil, err } activeVals := make([]*ctypes.Validator, 0, len(vals)) for _, val := range vals { if val.IsActive(epoch) { activeVals = append(activeVals, val) } } return activeVals, nil } ================================================ FILE: state-transition/core/state_processor_withdrawals.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/davecgh/go-spew/spew" "github.com/ethereum/go-ethereum/params" ) // processWithdrawals as per the Ethereum 2.0 specification. // https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#new-process_withdrawals // // NOTE: Modified from the Ethereum 2.0 specification to support EVM inflation: // 1. The first withdrawal MUST be a fixed EVM inflation withdrawal // 2. Subsequent withdrawals (if any) are processed as validator withdrawals // 3. This modification reduces the maximum validator withdrawals per block by one. // //nolint:gocognit,funlen // TODO: Consider refactoring func (sp *StateProcessor) processWithdrawals( st *state.StateDB, blk *ctypes.BeaconBlock, ) error { // Dequeue and verify the logs. var ( body = blk.GetBody() payload = body.GetExecutionPayload() payloadWithdrawals = payload.GetWithdrawals() ) // Get the expected withdrawals. expectedWithdrawals, processedPartialWithdrawalsCount, err := st.ExpectedWithdrawals(blk.GetTimestamp()) if err != nil { return err } // Common validations if len(expectedWithdrawals) != len(payloadWithdrawals) { return errors.Wrapf( ErrNumWithdrawalsMismatch, "withdrawals do not match expected length %d, got %d", len(expectedWithdrawals), len(payloadWithdrawals), ) } // Enforce that first withdrawal is EVM inflation if len(payloadWithdrawals) == 0 { return ErrZeroWithdrawals } if !payloadWithdrawals[0].Equals(st.EVMInflationWithdrawal(blk.GetTimestamp())) { return ErrFirstWithdrawalNotEVMInflation } numWithdrawals := len(expectedWithdrawals) // Process all subsequent validator withdrawals. for i := 1; i < numWithdrawals; i++ { // Ensure the withdrawals match the local state. if !expectedWithdrawals[i].Equals(payloadWithdrawals[i]) { return errors.Wrapf( ErrWithdrawalMismatch, "withdrawal at index %d does not match expected %s, got %s", i, spew.Sdump(expectedWithdrawals[i]), spew.Sdump(payloadWithdrawals[i]), ) } if err = st.DecreaseBalance( expectedWithdrawals[i].GetValidatorIndex(), expectedWithdrawals[i].GetAmount(), ); err != nil { return err } } // Update pending partial withdrawals [Introduced in Electra:EIP7251] // This case can only be hit after electra. if processedPartialWithdrawalsCount > 0 { ppWithdrawals, getErr := st.GetPendingPartialWithdrawals() if getErr != nil { return getErr } updatedWithdrawals := ppWithdrawals[processedPartialWithdrawalsCount:] sp.metrics.gaugePartialWithdrawalsEnqueued(len(updatedWithdrawals)) if setErr := st.SetPendingPartialWithdrawals(updatedWithdrawals); setErr != nil { return setErr } sp.logger.Info( "pending partial withdrawals found", "original_count", processedPartialWithdrawalsCount, "updated_count", len(updatedWithdrawals), ) } if numWithdrawals > 1 { if err = st.SetNextWithdrawalIndex( (expectedWithdrawals[numWithdrawals-1].GetIndex() + 1).Unwrap(), ); err != nil { return err } } totalValidators, err := st.GetTotalValidators() if err != nil { return err } // Update the next validator index to start the next withdrawal sweep. var nextValidatorIndex math.ValidatorIndex if uint64(numWithdrawals) == sp.cs.MaxWithdrawalsPerPayload() { // Next sweep starts after the latest withdrawal's validator index. nextValidatorIndex = (expectedWithdrawals[numWithdrawals-1].GetValidatorIndex() + 1) % totalValidators } else { // Advance sweep by the max length of the sweep if there was not a full set of withdrawals. nextValidatorIndex, err = st.GetNextWithdrawalValidatorIndex() if err != nil { return err } nextValidatorIndex += sp.cs.MaxValidatorsPerWithdrawalsSweep() nextValidatorIndex %= totalValidators } if err = st.SetNextWithdrawalValidatorIndex(nextValidatorIndex); err != nil { return err } sp.logger.Debug( "Processed withdrawals", "num_withdrawals", numWithdrawals, "evm_inflation", float64(payloadWithdrawals[0].GetAmount().Unwrap())/params.GWei, ) return nil } // processWithdrawalRequest is the equivalent of process_withdrawal_request as defined in the spec. // It should only be called after the electra hard fork. // For invalid withdrawal requests, we return nil, and only return error for system errors. func (sp *StateProcessor) processWithdrawalRequest( st *state.StateDB, withdrawalRequest *ctypes.WithdrawalRequest, ) error { // If the amount is 0, it's a full exit. isFullExitRequest := withdrawalRequest.Amount == constants.FullExitRequestAmount pendingPartialWithdrawals, err := st.GetPendingPartialWithdrawals() if err != nil { return err } // If partial withdrawal queue is full, only full exits are processed if len(pendingPartialWithdrawals) == constants.PendingPartialWithdrawalsLimit && !isFullExitRequest { sp.logger.Warn( "skipping processing of withdrawal request as partial withdrawal queue is full", withdrawalFields(withdrawalRequest, nil)..., ) sp.metrics.incrementPartialWithdrawalRequestDropped() return nil } index, validator, err := validateWithdrawal(st, withdrawalRequest) if err != nil { sp.logger.Info("Failed to validate withdrawal", withdrawalFields(withdrawalRequest, err)...) // Note that we do not return error on invalid requests as it's a user error and invalid withdrawal requests are simply skipped. return nil } if validator == nil { // This should never occur as we check in validateWithdrawal for nil, but this is needed to appease nilaway. sp.logger.Warn("processWithdrawalRequest: nil validator", withdrawalFields(withdrawalRequest, nil)...) return errors.New("processWithdrawalRequest: unexpected nil validator") } if err = verifyWithdrawalConditions(st, validator); err != nil { // Note that we do not return error on invalid requests as it's a user error and invalid withdrawal requests are simply skipped. sp.logger.Info("Failed to verify withdrawal conditions", withdrawalFields(withdrawalRequest, err)...) return nil } // Process full exit or partial withdrawal. if isFullExitRequest { sp.logger.Info("Processing full exit request", withdrawalFields(withdrawalRequest, nil)...) return sp.processFullExit(st, index, pendingPartialWithdrawals) } sp.logger.Info("Processing partial withdrawal request", withdrawalFields(withdrawalRequest, nil)...) return sp.processPartialWithdrawal(st, withdrawalRequest, validator, index, pendingPartialWithdrawals) } // processFullExit processes the full exit request is not a pending partial withdrawal // and has passed validation of `processWithdrawalRequest`. func (sp *StateProcessor) processFullExit( st *state.StateDB, index math.ValidatorIndex, pendingPartialWithdrawals ctypes.PendingPartialWithdrawals, ) error { pendingBalance := pendingPartialWithdrawals.PendingBalanceToWithdraw(index) if pendingBalance == 0 { // Only exit validator if it has no pending withdrawals in the queue return sp.InitiateValidatorExit(st, index) } sp.logger.Info("validator has pending balance and cannot full exit", "validator_index", index, "pending_balance", pendingBalance, ) return nil } // processPartialWithdrawal handles the partial withdrawal processing and called after // request has passed validation of `processWithdrawalRequest` func (sp *StateProcessor) processPartialWithdrawal( st *state.StateDB, req *ctypes.WithdrawalRequest, validator *ctypes.Validator, index math.ValidatorIndex, pendingWithdrawals ctypes.PendingPartialWithdrawals, ) error { minActivationBalance := sp.cs.MinActivationBalance() hasSufficient := validator.GetEffectiveBalance() >= minActivationBalance balance, err := st.GetBalance(index) if err != nil { return err } pendingBalanceToWithdraw := pendingWithdrawals.PendingBalanceToWithdraw(index) hasExcess := balance > minActivationBalance+pendingBalanceToWithdraw isWithdrawable := validator.HasCompoundingWithdrawalCredential() && hasSufficient && hasExcess if !isWithdrawable { sp.logger.Info("validator cannot withdraw partial balance", "validator_index", index, "validator_pubkey", validator.GetPubkey().String(), "balance", balance, "pending_balance_to_withdraw", pendingBalanceToWithdraw, "has_sufficient", hasSufficient, "has_excess", hasExcess, ) sp.metrics.incrementPartialWithdrawalRequestInvalid() return nil } toWithdraw := min(balance-minActivationBalance-pendingBalanceToWithdraw, req.Amount) // As long as `processPartialWithdrawal` is called after `processSlots`, this will always // return the correct epoch. currentEpoch, getErr := st.GetEpoch() if getErr != nil { return getErr } // Note that we do not need to set the ExitEpoch anywhere here as Partial withdrawals do not // exit the validator as we enforce that the `toWithdraw` amount is always above the // `minActivationBalance`. For example, if a validator's balance is already at // `minActivationBalance` (250K BERA on mainnet) and they request a partial withdrawal, the // `toWithdraw` amount will always be zero. nextEpoch := currentEpoch + 1 withdrawableEpoch := nextEpoch + sp.cs.MinValidatorWithdrawabilityDelay() ppWithdrawal := &ctypes.PendingPartialWithdrawal{ ValidatorIndex: index, Amount: toWithdraw, WithdrawableEpoch: withdrawableEpoch, } pendingWithdrawals = append(pendingWithdrawals, ppWithdrawal) sp.metrics.gaugePartialWithdrawalsEnqueued(len(pendingWithdrawals)) return st.SetPendingPartialWithdrawals(pendingWithdrawals) } // validateWithdrawal checks that the validator exists and that the withdrawal credentials match. func validateWithdrawal( st *state.StateDB, withdrawalRequest *ctypes.WithdrawalRequest, ) (math.ValidatorIndex, *ctypes.Validator, error) { // Verify pubkey exists index, err := st.ValidatorIndexByPubkey(withdrawalRequest.ValidatorPubKey) if err != nil { return 0, nil, err } validator, err := st.ValidatorByIndex(index) if err != nil { return 0, nil, err } if validator == nil { // This should never occur as we expect ErrNotFound if the validator is not found. return 0, nil, errors.New("validateWithdrawal: validator does not exist") } // Verify withdrawal credentials if !validator.HasExecutionWithdrawalCredential() { return 0, nil, errors.New("validator does not have execution withdrawal credentials") } correctCred, err := validator.WithdrawalCredentials.ToExecutionAddress() if err != nil { return 0, nil, err } if !withdrawalRequest.SourceAddress.Equals(correctCred) { return 0, nil, errors.New("source address does not match execution withdrawal credential") } return index, validator, nil } // verifyWithdrawalConditions checks additional conditions like active status, exit not initiated, // and minimal activation period. func verifyWithdrawalConditions(st *state.StateDB, validator *ctypes.Validator) error { currentEpoch, err := st.GetEpoch() if err != nil { return err } // Verify the validator is active if !validator.IsActive(currentEpoch) { return errors.New("validator is not active") } // Verify exit has not been initiated if validator.GetExitEpoch() != constants.FarFutureEpoch { return errors.New("withdrawal already initiated") } // In Ethereum specs here it's checked that // currentEpoch < validator.ActivationEpoch + config.SHARD_COMMITTEE_PERIOD // We ignore config.SHARD_COMMITTEE_PERIOD, since data shards are not relevant for us. // Moreover here validator is active so currentEpoch >= validator.ActivationEpoch return nil } // withdrawalFields returns the structured fields for logging any WithdrawalRequest. // error is optional func withdrawalFields(req *ctypes.WithdrawalRequest, err error) []interface{} { logFields := []interface{}{ "source_address", req.SourceAddress.String(), "validator_pubkey", req.ValidatorPubKey.String(), "amount", req.Amount, } if err != nil { logFields = append(logFields, "error", err) } return logFields } ================================================ FILE: state-transition/core/state_processor_withdrawals_test.go ================================================ //go:build test // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core_test import ( "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/primitives/version" statetransition "github.com/berachain/beacon-kit/testing/state-transition" "github.com/stretchr/testify/require" ) func TestPartialWithdrawalRequestGenesisValidators(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) // make sure Electra is active require.True(t, version.EqualsOrIsAfter(cs.GenesisForkVersion(), version.Electra())) var ( maxBalance = cs.MaxEffectiveBalance() minBalance = cs.MinActivationBalance() addr = common.ExecutionAddress{0x01} creds = types.NewCredentialsFromExecutionAddress(addr) badAddr = common.ExecutionAddress{0x20} ) // Add a single validator to which we will target withdrawal requests var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: creds, Amount: maxBalance, Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } ) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) // Send withdrawal requests and see the valid ones being carried out vals, err := st.GetValidators() require.NoError(t, err) require.Len(t, vals, 1) genVal := vals[0] genValIdx, err := st.ValidatorIndexByPubkey(genVal.GetPubkey()) require.NoError(t, err) genValPubKey := genVal.GetPubkey() wrs := []*types.WithdrawalRequest{ { // valid request SourceAddress: addr, ValidatorPubKey: genValPubKey, Amount: 1, }, { // valid request SourceAddress: addr, ValidatorPubKey: genValPubKey, Amount: 10, }, { // invalid request, invalid address SourceAddress: badAddr, ValidatorPubKey: genValPubKey, Amount: 10, }, { // invalid request, invalid pub key SourceAddress: addr, ValidatorPubKey: crypto.BLSPubkey(append([]byte{0xff}, genValPubKey[1:]...)), Amount: 10, }, { // valid request, largest withdrawable amount SourceAddress: addr, ValidatorPubKey: genValPubKey, Amount: maxBalance - 1 - 10 - minBalance, // remaining amount to minBalance }, { // invalid request (can't go below min activation balance even by 1 bera) SourceAddress: addr, ValidatorPubKey: genValPubKey, Amount: 1, }, { // invalid request (full withdraw ignored when partial withdraws are ongoing) SourceAddress: addr, ValidatorPubKey: genValPubKey, Amount: 0, }, } var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), 0, uint64(len(genDeposits))) require.NoError(t, err) blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(10), ) // Run the test. _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) // check withdrawal request is enqueued expectedWithdrawalEpoch := 1 + cs.MinValidatorWithdrawabilityDelay() pr, err := st.GetPendingPartialWithdrawals() require.NoError(t, err) require.Len(t, pr, 3) require.Equal(t, []*types.PendingPartialWithdrawal{ { ValidatorIndex: 0, Amount: wrs[0].Amount, WithdrawableEpoch: expectedWithdrawalEpoch, }, { ValidatorIndex: 0, Amount: wrs[1].Amount, WithdrawableEpoch: expectedWithdrawalEpoch, }, { ValidatorIndex: 0, Amount: wrs[4].Amount, WithdrawableEpoch: expectedWithdrawalEpoch, }, }, pr, ) // check that the request is eventually fulfilled for range expectedWithdrawalEpoch - 1 { _ = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // This is just because we cannot chain moveToEndOfEpoch // back to back. TODO: fix timestamp := blk.Body.ExecutionPayload.Timestamp + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(timestamp), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } for range cs.SlotsPerEpoch() - 1 { timestamp := blk.Body.ExecutionPayload.Timestamp + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(timestamp), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } // finally the withdrawal timestamp := blk.Body.ExecutionPayload.Timestamp + 1 withdrawals := []*engineprimitives.Withdrawal{ // The first withdrawal is always for EVM inflation. st.EVMInflationWithdrawal(10), { Index: 0, Validator: genValIdx, Amount: wrs[0].Amount, Address: wrs[0].SourceAddress, }, { Index: 1, Validator: genValIdx, Amount: wrs[1].Amount, Address: wrs[1].SourceAddress, }, { Index: 2, Validator: genValIdx, Amount: wrs[4].Amount, Address: wrs[4].SourceAddress, }, } blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), timestamp, []*types.Deposit{}, &types.ExecutionRequests{}, withdrawals..., ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) // no more pending withdrawals pr, err = st.GetPendingPartialWithdrawals() require.NoError(t, err) require.Empty(t, pr) } func TestFullWithdrawalRequestGenesisValidators(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) // make sure Electra is active require.True(t, version.EqualsOrIsAfter(cs.GenesisForkVersion(), version.Electra())) var ( maxBalance = cs.MaxEffectiveBalance() addr1 = common.ExecutionAddress{0x01} creds1 = types.NewCredentialsFromExecutionAddress(addr1) addr2 = common.ExecutionAddress{0x01} creds2 = types.NewCredentialsFromExecutionAddress(addr2) ) // Add a couple of validators and fully withdraw one of them var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: creds1, Amount: maxBalance, Index: 0, }, { Pubkey: [48]byte{0x01}, Credentials: creds2, Amount: maxBalance, Index: 1, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } ) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) vals, err := st.GetValidators() require.NoError(t, err) require.Len(t, vals, 2) valToRm := vals[0] wrs := []*types.WithdrawalRequest{ { SourceAddress: addr1, ValidatorPubKey: valToRm.GetPubkey(), Amount: 0, }, } var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), 0, uint64(len(genDeposits))) require.NoError(t, err) blkTimestamp := math.U64(10) blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) // Run the test. valDiff, err := sp.Transition(ctx, st, blk) require.NoError(t, err) require.Empty(t, valDiff) // check that valToRm has initiated exit expectedExitEpoch := math.Epoch(1) expectedWithdrawalEpoch := expectedExitEpoch + cs.MinValidatorWithdrawabilityDelay() valToRmIdx, err := st.ValidatorIndexByPubkey(valToRm.GetPubkey()) require.NoError(t, err) valToRm, err = st.ValidatorByIndex(valToRmIdx) require.NoError(t, err) require.Equal(t, expectedExitEpoch, valToRm.ExitEpoch) require.Equal(t, expectedWithdrawalEpoch, valToRm.WithdrawableEpoch) // no pending withdrawals, full withdrawals are executed right away pr, err := st.GetPendingPartialWithdrawals() require.NoError(t, err) require.Empty(t, pr) // check the validator duly exits validator set blk = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blkTimestamp), ) valDiff, err = sp.Transition(ctx, st, blk) require.NoError(t, err) require.Equal(t, transition.ValidatorUpdates{ { Pubkey: valToRm.Pubkey, EffectiveBalance: 0, }, }, valDiff, ) // no more partial withdrawals are possible for an exited validator wrs = []*types.WithdrawalRequest{ { SourceAddress: addr1, ValidatorPubKey: valToRm.GetPubkey(), Amount: 1, }, } blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) // Run the test. _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) pr, err = st.GetPendingPartialWithdrawals() require.NoError(t, err) require.Empty(t, pr) // check that balance is still locked and it will be // returned after MinValidatorWithdrawabilityDelay epochs // check that the request is eventually fulfilled for range expectedWithdrawalEpoch - 2 { _ = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // This is just because we cannot chain moveToEndOfEpoch // back to back. TODO: fix blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blkTimestamp), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } for range cs.SlotsPerEpoch() - 1 { blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blkTimestamp), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } // finally the withdrawal timestamp := blk.Body.ExecutionPayload.Timestamp + 1 withdrawals := []*engineprimitives.Withdrawal{ // The first withdrawal is always for EVM inflation. st.EVMInflationWithdrawal(10), { Index: 0, Validator: valToRmIdx, Amount: valToRm.EffectiveBalance, // wrs request has zero to signal full withdrawal Address: wrs[0].SourceAddress, }, } blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), timestamp, []*types.Deposit{}, &types.ExecutionRequests{}, withdrawals..., ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) // Check that validator balance is 0 valBalance, err := st.GetBalance(valToRmIdx) require.NoError(t, err) require.Equal(t, math.U64(0), valBalance) // Check that effective balance has not updated yet. It will update next epoch // as part of processEffectiveBalanceUpdates valToRm, err = st.ValidatorByIndex(valToRmIdx) require.NoError(t, err) require.Equal(t, maxBalance, valToRm.GetEffectiveBalance()) // Move forward one more epoch to trigger the effective balance update { _ = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // This is just because we cannot chain moveToEndOfEpoch // back to back. TODO: fix blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blkTimestamp), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } // Check that effective balance is now 0 valToRm, err = st.ValidatorByIndex(valToRmIdx) require.NoError(t, err) require.Equal(t, math.Gwei(0), valToRm.GetEffectiveBalance()) } func TestWithdrawalRequestsNonGenesisValidators(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) // make sure Electra is active require.True(t, version.EqualsOrIsAfter(cs.GenesisForkVersion(), version.Electra())) var ( maxBalance = cs.MaxEffectiveBalance() genAddr = common.ExecutionAddress{0x01} genCreds = types.NewCredentialsFromExecutionAddress(genAddr) valAddr = common.ExecutionAddress{0x01} valCreds = types.NewCredentialsFromExecutionAddress(valAddr) ) var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: genCreds, Amount: maxBalance, Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = uint64(len(genDeposits)) ) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) // add a validator and test withdrawals through its lifetime blkDeposit := &types.Deposit{ Pubkey: [48]byte{0xff}, Credentials: valCreds, Amount: maxBalance, Index: uint64(len(genDeposits)), } blkDeposits := []*types.Deposit{blkDeposit} totalDepositsCount++ require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), blkDeposits)) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, blkDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // run the test _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) // assert that validator is not even eligible for activation yet idx, err := st.ValidatorIndexByPubkey(blkDeposit.Pubkey) require.NoError(t, err) val, err := st.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, constants.FarFutureEpoch, val.ActivationEligibilityEpoch) // validator is not even in activation queue, any withdrawal request is dropped wrs := []*types.WithdrawalRequest{ { SourceAddress: valAddr, ValidatorPubKey: val.GetPubkey(), Amount: 1, }, } blkTimestamp := blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) // Show that no withdrawal is enqueued _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) pr, err := st.GetPendingPartialWithdrawals() require.NoError(t, err) require.Empty(t, pr) // try again with full withdrawal wrs = []*types.WithdrawalRequest{ { SourceAddress: valAddr, ValidatorPubKey: val.GetPubkey(), Amount: 0, }, } blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) // Show that validator is not marked for exit _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) val, err = st.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, constants.FarFutureEpoch, val.ActivationEligibilityEpoch) require.Equal(t, constants.FarFutureEpoch, val.ExitEpoch) // make validator eligible for activation and show that withdrawals are not yet allowed blk = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blkTimestamp), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) val, err = st.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, math.Epoch(1), val.ActivationEligibilityEpoch) require.Equal(t, constants.FarFutureEpoch, val.ActivationEpoch) // validator eligible for activation but not active yet. Requests dropped wrs = []*types.WithdrawalRequest{ { SourceAddress: valAddr, ValidatorPubKey: val.GetPubkey(), Amount: 1, }, } blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) // Show that no withdrawal is enqueued _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) pr, err = st.GetPendingPartialWithdrawals() require.NoError(t, err) require.Empty(t, pr) // try again with full withdrawal wrs = []*types.WithdrawalRequest{ { SourceAddress: valAddr, ValidatorPubKey: val.GetPubkey(), Amount: 0, }, } blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) // Show that validator is not marked for exit _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) val, err = st.ValidatorByIndex(idx) require.NoError(t, err) require.Equal(t, constants.FarFutureEpoch, val.ActivationEpoch) require.Equal(t, constants.FarFutureEpoch, val.ExitEpoch) // finally when validator is active withdrawals will work blk = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) wrs = []*types.WithdrawalRequest{ { SourceAddress: valAddr, ValidatorPubKey: val.GetPubkey(), Amount: 1, }, } blkTimestamp = blk.GetTimestamp() + 1 blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) // Run the test. _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) pr, err = st.GetPendingPartialWithdrawals() require.NoError(t, err) require.Len(t, pr, 1) require.Equal(t, []*types.PendingPartialWithdrawal{ { ValidatorIndex: 1, Amount: wrs[0].Amount, WithdrawableEpoch: 3 + cs.MinValidatorWithdrawabilityDelay(), }, }, pr, ) } // Check that if the withdrawal request comes for a validator about to // be evicted, this double eviction is duly handled func TestConcurrentAutomaticAndVoluntaryWithdrawalRequests(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) // make sure Electra is active require.True(t, version.EqualsOrIsAfter(cs.GenesisForkVersion(), version.Electra())) // Make sure we have as many validators as the cap allows var ( maxBalance = cs.MaxEffectiveBalance() rndSeed = 2024 // seed used to generate unique random value ) var ( genDeposits = make(types.Deposits, 0, cs.ValidatorSetCap()) genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = cs.ValidatorSetCap() ) // Step1: let blockchain have as many validators as cap allows for idx := range cs.ValidatorSetCap() { var ( key bytes.B48 creds types.WithdrawalCredentials ) key, rndSeed = generateTestPK(t, rndSeed) creds, rndSeed = generateTestExecutionAddress(t, rndSeed) genDeposits = append( genDeposits, &types.Deposit{ Pubkey: key, Credentials: creds, Amount: maxBalance, Index: idx, }, ) } require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Step 2: add a deposit which will evict one of the existing validators newValKey, rndSeed := generateTestPK(t, rndSeed) newValCreds, _ := generateTestExecutionAddress(t, rndSeed) var ( newValDeposit = &types.Deposit{ Pubkey: newValKey, Credentials: newValCreds, Amount: maxBalance, Index: uint64(len(genDeposits)), } blkDeposits = []*types.Deposit{newValDeposit} ) totalDepositsCount++ require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), blkDeposits)) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) blkTimestamp := math.U64(10) blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, blkDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blkTimestamp), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) // check the deposit has been accepted _, err = st.ValidatorIndexByPubkey(newValDeposit.Pubkey) require.NoError(t, err) // move chain on till the new validator is about to be activated _ = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) _ = moveToEndOfEpoch(t, blk, cs, sp, st, ctx, depRoot) // right at the block where we a validator will be evicted // we add a full withdrawal request for it. We expect this request // to be simply dropped since the validator is evicted upon ProcessEpoch evictedValAddr, err := genDeposits[0].Credentials.ToExecutionAddress() require.NoError(t, err) blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: []*types.WithdrawalRequest{ { SourceAddress: evictedValAddr, ValidatorPubKey: genDeposits[0].Pubkey, Amount: 0, }, }, }, st.EVMInflationWithdrawal(blk.GetTimestamp()+1), ) valDiff, err := sp.Transition(ctx, st, blk) require.NoError(t, err) require.Len(t, valDiff, 2) require.Equal( t, &transition.ValidatorUpdate{ Pubkey: newValDeposit.Pubkey, EffectiveBalance: newValDeposit.Amount, }, valDiff[0], ) require.Equal( t, &transition.ValidatorUpdate{ Pubkey: genDeposits[0].Pubkey, EffectiveBalance: 0, }, valDiff[1], ) evictedValIdx, err := st.ValidatorIndexByPubkey(genDeposits[0].Pubkey) require.NoError(t, err) evictedVal, err := st.ValidatorByIndex(evictedValIdx) require.NoError(t, err) expectedExitEpoch := math.Epoch(2) expectedWithdrawalEpoch := math.Epoch(2) + cs.MinValidatorWithdrawabilityDelay() require.Equal(t, expectedExitEpoch, evictedVal.ExitEpoch) require.Equal(t, expectedWithdrawalEpoch, evictedVal.WithdrawableEpoch) } // Check that two full withdrawals requests issued back to back // are idempotent. The second request simply dropped func TestDoubleFullWithdrawalRequests(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) // make sure Electra is active require.True(t, version.EqualsOrIsAfter(cs.GenesisForkVersion(), version.Electra())) var ( maxBalance = cs.MaxEffectiveBalance() addr1 = common.ExecutionAddress{0x01} creds1 = types.NewCredentialsFromExecutionAddress(addr1) addr2 = common.ExecutionAddress{0x01} creds2 = types.NewCredentialsFromExecutionAddress(addr2) ) // Add a couple of validators and fully withdraw one of them var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: creds1, Amount: maxBalance, Index: 0, }, { Pubkey: [48]byte{0x01}, Credentials: creds2, Amount: maxBalance, Index: 1, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } ) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) vals, err := st.GetValidators() require.NoError(t, err) require.Len(t, vals, 2) valToRm := vals[0] wrs := []*types.WithdrawalRequest{ { SourceAddress: addr1, ValidatorPubKey: valToRm.GetPubkey(), Amount: 0, }, } var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), 0, uint64(len(genDeposits))) require.NoError(t, err) blkTimestamp := math.U64(10) blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) // Run the test. _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) // check that valToRm has initiated exit expectedExitEpoch := math.Epoch(1) expectedWithdrawalEpoch := expectedExitEpoch + cs.MinValidatorWithdrawabilityDelay() valToRmIdx, err := st.ValidatorIndexByPubkey(valToRm.GetPubkey()) require.NoError(t, err) valToRm, err = st.ValidatorByIndex(valToRmIdx) require.NoError(t, err) require.Equal(t, expectedExitEpoch, valToRm.ExitEpoch) require.Equal(t, expectedWithdrawalEpoch, valToRm.WithdrawableEpoch) // issue another full withdrawal request, which should be // processed without errors and simply dropped blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blkTimestamp, []*types.Deposit{}, &types.ExecutionRequests{ Withdrawals: wrs, }, st.EVMInflationWithdrawal(blkTimestamp), ) _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } func TestPartialWithdrawalsOfBalanceAboveMaxEffectiveBalance(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() minBalance = cs.EffectiveBalanceIncrement() credentials0 = types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}) address1 = common.ExecutionAddress{0x01} credentials1 = types.NewCredentialsFromExecutionAddress(address1) ) // Setup initial state so that validator 1 is partially withdrawable. var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: credentials0, Amount: maxBalance - 3*minBalance, Index: 0, }, { Pubkey: [48]byte{0x01}, Credentials: credentials1, Amount: maxBalance + minBalance, Index: 1, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Assert validator 1 balance before withdrawal. val1Bal, err := st.GetBalance(math.U64(1)) require.NoError(t, err) require.Equal(t, maxBalance+minBalance, val1Bal) // Create test inputs. withdrawals := []*engineprimitives.Withdrawal{ // The first withdrawal is always for EVM inflation. st.EVMInflationWithdrawal(10), // Partially withdraw validator 1 by minBalance. { Index: 0, Validator: 1, Amount: minBalance, Address: address1, }, } var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), 0, uint64(len(genDeposits))) require.NoError(t, err) blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, []*types.Deposit{}, &types.ExecutionRequests{}, withdrawals..., ) // Run the test. _, err = sp.Transition(ctx, st, blk) // Check outputs and ensure withdrawals in payload is consistent with // statedb expected withdrawals. require.NoError(t, err) // Assert validator 1 balance after withdrawal. val1BalAfter, err := st.GetBalance(math.U64(1)) require.NoError(t, err) require.Equal(t, maxBalance, val1BalAfter) } func TestTransitionMaxWithdrawals(t *testing.T) { t.Parallel() // Use custom chain spec with max withdrawals set to 2. csData := spec.DevnetChainSpecData() csData.MaxWithdrawalsPerPayload = 2 csData.MaxValidatorsPerWithdrawalsSweep = 2 cs, err := chain.NewSpec(csData) require.NoError(t, err) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() minBalance = cs.EffectiveBalanceIncrement() address0 = common.ExecutionAddress{} credentials0 = types.NewCredentialsFromExecutionAddress(address0) address1 = common.ExecutionAddress{0x01} credentials1 = types.NewCredentialsFromExecutionAddress(address1) ) // Setup initial state so that both validators are partially withdrawable. var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: credentials0, Amount: maxBalance + minBalance, Index: 0, }, { Pubkey: [48]byte{0x01}, Credentials: credentials1, Amount: maxBalance + minBalance, Index: 1, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err = sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Assert validator balances before withdrawal. val0Bal, err := st.GetBalance(math.U64(0)) require.NoError(t, err) require.Equal(t, maxBalance+minBalance, val0Bal) val1Bal, err := st.GetBalance(math.U64(1)) require.NoError(t, err) require.Equal(t, maxBalance+minBalance, val1Bal) // Create test inputs. withdrawals := []*engineprimitives.Withdrawal{ // The first withdrawal is always for EVM inflation. st.EVMInflationWithdrawal(10), // Partially withdraw validator 0 by minBalance. { Index: 0, Validator: 0, Amount: minBalance, Address: address0, }, } var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), 0, uint64(len(genDeposits))) require.NoError(t, err) blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, []*types.Deposit{}, &types.ExecutionRequests{}, withdrawals..., ) // Run the test. _, err = sp.Transition(ctx, st, blk) // Check outputs and ensure withdrawals in payload is consistent with // statedb expected withdrawals. require.NoError(t, err) // Assert validator balances after withdrawal, ensuring only validator 0 is // withdrawn from. val0BalAfter, err := st.GetBalance(math.U64(0)) require.NoError(t, err) require.Equal(t, maxBalance, val0BalAfter) val1BalAfter, err := st.GetBalance(math.U64(1)) require.NoError(t, err) require.Equal(t, maxBalance+minBalance, val1BalAfter) // Process the next block, ensuring that validator 1 is also withdrawn from, // also ensuring that the state's next withdrawal (validator) index is // appropriately incremented. withdrawals = []*engineprimitives.Withdrawal{ // The first withdrawal is always for EVM inflation. st.EVMInflationWithdrawal(blk.GetTimestamp() + 1), // Partially withdraw validator 1 by minBalance. { Index: 1, Validator: 1, Amount: minBalance, Address: address1, }, } blk = buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), blk.GetTimestamp()+1, []*types.Deposit{}, &types.ExecutionRequests{}, withdrawals..., ) // Run the test. vals, err := sp.Transition(ctx, st, blk) // Check outputs and ensure withdrawals in payload is consistent with // statedb expected withdrawals. require.NoError(t, err) require.Zero(t, vals) // Validator 1 is now withdrawn from. val1BalAfter, err = st.GetBalance(math.U64(1)) require.NoError(t, err) require.Equal(t, maxBalance, val1BalAfter) } func TestValidatorNotWithdrawable(t *testing.T) { t.Parallel() cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( belowActiveBalance = cs.MinActivationBalance() - cs.EffectiveBalanceIncrement() maxBalance = cs.MaxEffectiveBalance() validCredentials = types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}) ) // Setup initial state with one validator var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: validCredentials, Amount: maxBalance, Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = uint64(len(genDeposits)) ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Create the block deposit with a non-ETH1 withdrawal credentials. This stake should not // be lost. invalidCredentials := types.WithdrawalCredentials(validCredentials[:]) invalidCredentials[1] = 0x01 blkDeposit := &types.Deposit{ Pubkey: [48]byte{0x01}, Credentials: invalidCredentials, Amount: belowActiveBalance, Index: 1, } blkDeposits := []*types.Deposit{blkDeposit} totalDepositsCount++ require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), blkDeposits)) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, blkDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // Run transition. _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) // Check that validator 0x01 is part of beacon state with below active balance. validator, err := st.ValidatorByIndex(1) require.NoError(t, err) require.Equal(t, belowActiveBalance, validator.EffectiveBalance) } ================================================ FILE: state-transition/core/validation_deposits.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core import ( "context" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage/deposit" ) func validateGenesisDeposits( st *statedb.StateDB, deposits []*ctypes.Deposit, validatorSetCap uint64, ) error { eth1DepositIndex, err := st.GetEth1DepositIndex() if err != nil { return err } if eth1DepositIndex != constants.FirstDepositIndex { return errors.New("Eth1DepositIndex should be 0 at genesis") } if len(deposits) == 0 { // there should be at least a validator in genesis return errors.Wrap(ErrDepositsLengthMismatch, "at least one validator should be in genesis") } for i, deposit := range deposits { // deposit indices should be contiguous // #nosec G115 if deposit.GetIndex() != math.U64(i) { return errors.Wrapf(ErrDepositIndexOutOfOrder, "genesis deposit index: %d, expected index: %d", deposit.GetIndex().Unwrap(), i, ) } } // BeaconKit enforces a cap on the validator set size. // If genesis deposits breaches the cap we return an error. //#nosec:G701 // can't overflow. if uint64(len(deposits)) > validatorSetCap { return errors.Wrapf( ErrValSetCapExceeded, "validator set cap %d, deposits count %d", validatorSetCap, len(deposits), ) } return nil } func ValidateNonGenesisDeposits( ctx context.Context, st *statedb.StateDB, depositStore deposit.StoreManager, maxDepositsPerBlock uint64, blkDeposits []*ctypes.Deposit, blkDepositRoot common.Root, ) error { depositIndex, err := st.GetEth1DepositIndex() if err != nil { return err } // Grab all previous deposits from genesis up to the current index + max deposits per block. localDeposits, localDepositRoot, err := depositStore.GetDepositsByIndex( ctx, constants.FirstDepositIndex, depositIndex+maxDepositsPerBlock, ) if err != nil { return err } // First verify that the number of block deposits matches the number of local deposits. totalBlockDeposits := depositIndex + uint64(len(blkDeposits)) if uint64(len(localDeposits)) != totalBlockDeposits { return errors.Wrapf(ErrDepositsLengthMismatch, "block deposit count: %d, expected deposit count: %d", totalBlockDeposits, len(localDeposits), ) } // Then check that the block's deposits 1) have contiguous indices and 2) match the local // view of the block's deposits. for i, blkDeposit := range blkDeposits { blkDepositIndex := blkDeposit.GetIndex().Unwrap() //#nosec:G115 // won't overflow in practice. if blkDepositIndex != depositIndex+uint64(i) { return errors.Wrapf(ErrDepositIndexOutOfOrder, "deposit index: %d, expected index: %d", blkDepositIndex, i, ) } if !localDeposits[blkDepositIndex].Equals(blkDeposit) { return errors.Wrapf(ErrDepositMismatch, "deposit index: %d, expected deposit: %+v, actual deposit: %+v", blkDepositIndex, *localDeposits[blkDepositIndex], *blkDeposit, ) } } // Finally check that the historical deposits root matches locally what's on the beacon block. if !localDepositRoot.Equals(blkDepositRoot) { return ErrDepositsRootMismatch } return nil } ================================================ FILE: state-transition/core/validation_deposits_test.go ================================================ //go:build test // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package core_test import ( "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" statetransition "github.com/berachain/beacon-kit/testing/state-transition" "github.com/stretchr/testify/require" ) //nolint:paralleltest // uses envars func TestInvalidDeposits(t *testing.T) { cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( minBalance = cs.MinActivationBalance() maxBalance = cs.MaxEffectiveBalance() credentials0 = types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}) ) // Setup initial state with one validator var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: credentials0, Amount: maxBalance, Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = uint64(len(genDeposits)) ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Create the correct deposit for pubkey 1. correctDeposit := &types.Deposit{ Pubkey: [48]byte{0x01}, Credentials: credentials0, Amount: minBalance, Index: 1, } totalDepositsCount++ // Create an invalid deposit with extra balance going to pubkey 1 invalidDeposit := &types.Deposit{ Pubkey: [48]byte{0x01}, Credentials: credentials0, Amount: maxBalance, // Invalid - should be minBalance Index: 1, } blkDeposits := []*types.Deposit{invalidDeposit} // make sure included deposit is already available in deposit store require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), []*types.Deposit{correctDeposit})) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) // Create test block with invalid deposit, BUT the correct deposit for pubkey 1. blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, blkDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // Run transition - should fail due to invalid deposit amount. _, err = sp.Transition(ctx, st, blk) require.Error(t, err) require.ErrorContains(t, err, "deposit mismatched") } //nolint:paralleltest // uses envars func TestInvalidDepositsCount(t *testing.T) { cs := setupChain(t) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() credentials0 = types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}) ) // Setup initial state with one validator var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: credentials0, Amount: maxBalance, Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = uint64(len(genDeposits)) ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err := sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Create the correct deposits. correctDeposits := types.Deposits{ { Pubkey: [48]byte{0x01}, Credentials: credentials0, Amount: maxBalance, Index: 1, }, { Pubkey: [48]byte{0x02}, Credentials: credentials0, Amount: maxBalance, Index: 2, }, } totalDepositsCount += uint64(len(correctDeposits)) // Add JUST 1 correct deposit to local store. This node SHOULD fail to verify. require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), []*types.Deposit{correctDeposits[0]})) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount) require.NoError(t, err) // Create test block with the correct deposits. blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, correctDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // Run transition. _, err = sp.Transition(ctx, st, blk) require.Error(t, err) require.ErrorContains(t, err, "deposits lengths mismatched") } func TestLocalDepositsExceedBlockDeposits(t *testing.T) { t.Parallel() csData := spec.DevnetChainSpecData() csData.MaxDepositsPerBlock = 1 // Set only 1 deposit allowed per block. cs, err := chain.NewSpec(csData) require.NoError(t, err) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() credentials0 = types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}) ) // Setup initial state with one validator var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: credentials0, Amount: maxBalance, Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } totalDepositsCount = uint64(len(genDeposits)) ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err = sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Create the block deposits. blockDeposit := types.Deposit{ Pubkey: [48]byte{0x01}, Credentials: credentials0, Amount: maxBalance, Index: 1, } blkDeposits := []*types.Deposit{&blockDeposit} extraLocalDeposit := &types.Deposit{ Pubkey: [48]byte{0x01}, Credentials: credentials0, Amount: maxBalance, Index: 2, } totalDepositsCount += 2 // make sure included deposit is already available in deposit store require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), []*types.Deposit{&blockDeposit, extraLocalDeposit})) var depRoot common.Root _, depRoot, err = ds.GetDepositsByIndex(ctx.ConsensusCtx(), constants.FirstDepositIndex, totalDepositsCount-1) require.NoError(t, err) // Create test block with the correct deposits. blk := buildNextBlock( t, cs, st, types.NewEth1Data(depRoot), 10, blkDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // Run transition. _, err = sp.Transition(ctx, st, blk) require.NoError(t, err) } func TestLocalDepositsExceedBlockDepositsBadRoot(t *testing.T) { t.Parallel() csData := spec.DevnetChainSpecData() csData.MaxDepositsPerBlock = 1 // Set only 1 deposit allowed per block. cs, err := chain.NewSpec(csData) require.NoError(t, err) sp, st, ds, ctx, _, _ := statetransition.SetupTestState(t, cs) var ( maxBalance = cs.MaxEffectiveBalance() credentials0 = types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{}) ) // Setup initial state with one validator var ( genDeposits = types.Deposits{ { Pubkey: [48]byte{0x00}, Credentials: credentials0, Amount: maxBalance, Index: 0, }, } genPayloadHeader = &types.ExecutionPayloadHeader{ Versionable: types.NewVersionable(cs.GenesisForkVersion()), } ) require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), genDeposits)) _, err = sp.InitializeBeaconStateFromEth1( st, genDeposits, genPayloadHeader, cs.GenesisForkVersion(), ) require.NoError(t, err) // Create the block deposits. blockDeposits := types.Deposits{ { Pubkey: [48]byte{0x01}, Credentials: credentials0, Amount: maxBalance, Index: 1, }, } extraLocalDeposit := &types.Deposit{ Pubkey: [48]byte{0x01}, Credentials: credentials0, Amount: maxBalance, Index: 2, } // Now, the block proposer ends up adding the correct 1 deposit per block, BUT spoofs the // deposits root to use the entire deposits list. badDepRoot := append(genDeposits, append(blockDeposits, extraLocalDeposit)...).HashTreeRoot() blk := buildNextBlock( t, cs, st, types.NewEth1Data(badDepRoot), 10, blockDeposits, &types.ExecutionRequests{}, st.EVMInflationWithdrawal(10), ) // Add both deposits to local store (which includes more than what's in the block). require.NoError(t, ds.EnqueueDeposits(ctx.ConsensusCtx(), append(blockDeposits, extraLocalDeposit))) // Run transition. _, err = sp.Transition(ctx, st, blk) require.Error(t, err) require.ErrorContains(t, err, "deposits root mismatch") } ================================================ FILE: storage/beacondb/eth1.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/bytes" ) // GetLatestExecutionPayloadHeader retrieves the latest execution payload // header from the BeaconStore. func (kv *KVStore) GetLatestExecutionPayloadHeader() ( *ctypes.ExecutionPayloadHeader, error, ) { // NOTE: unmarshalling this struct is NOT affected by it's own fork version. The versioned // codec is left in for backwards compatibility. forkVersion, err := kv.latestExecutionPayloadVersion.Get(kv.ctx) if err != nil { return nil, err } kv.latestExecutionPayloadCodec.SetActiveForkVersion(bytes.FromUint32(forkVersion)) return kv.latestExecutionPayloadHeader.Get(kv.ctx) } // SetLatestExecutionPayloadHeader sets the latest execution payload header in // the BeaconStore. func (kv *KVStore) SetLatestExecutionPayloadHeader( payloadHeader *ctypes.ExecutionPayloadHeader, ) error { // NOTE: marshalling this struct is NOT affected by it's own fork version. The versioned // codec is left in for backwards compatibility. version := payloadHeader.GetForkVersion() if err := kv.latestExecutionPayloadVersion.Set( kv.ctx, version.ToUint32(), ); err != nil { return err } kv.latestExecutionPayloadCodec.SetActiveForkVersion(version) return kv.latestExecutionPayloadHeader.Set(kv.ctx, payloadHeader) } // GetEth1DepositIndex retrieves the eth1 deposit index from the beacon state. func (kv *KVStore) GetEth1DepositIndex() (uint64, error) { return kv.eth1DepositIndex.Get(kv.ctx) } // SetEth1DepositIndex sets the eth1 deposit index in the beacon state. func (kv *KVStore) SetEth1DepositIndex(index uint64) error { return kv.eth1DepositIndex.Set(kv.ctx, index) } // GetEth1Data retrieves the eth1 data from the beacon state. func (kv *KVStore) GetEth1Data() (*ctypes.Eth1Data, error) { return kv.eth1Data.Get(kv.ctx) } // SetEth1Data sets the eth1 data in the beacon state. func (kv *KVStore) SetEth1Data(data *ctypes.Eth1Data) error { return kv.eth1Data.Set(kv.ctx, data) } ================================================ FILE: storage/beacondb/fork.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import ctypes "github.com/berachain/beacon-kit/consensus-types/types" // SetFork sets the fork version for the given epoch. func (kv *KVStore) SetFork(fork *ctypes.Fork) error { return kv.fork.Set(kv.ctx, fork) } // GetFork gets the fork version for the given epoch. func (kv *KVStore) GetFork() (*ctypes.Fork, error) { return kv.fork.Get(kv.ctx) } ================================================ FILE: storage/beacondb/history.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import ( ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" ) // UpdateBlockRootAtIndex sets a block root in the BeaconStore. func (kv *KVStore) UpdateBlockRootAtIndex( index uint64, root common.Root, ) error { return kv.blockRoots.Set(kv.ctx, index, root[:]) } // GetBlockRootAtIndex retrieves the block root from the BeaconStore. func (kv *KVStore) GetBlockRootAtIndex( index uint64, ) (common.Root, error) { bz, err := kv.blockRoots.Get(kv.ctx, index) if err != nil { return common.Root{}, err } return common.Root(bz), nil } // SetLatestBlockHeader sets the latest block header in the BeaconStore. func (kv *KVStore) SetLatestBlockHeader( header *ctypes.BeaconBlockHeader, ) error { return kv.latestBlockHeader.Set(kv.ctx, header) } // GetLatestBlockHeader retrieves the latest block header from the BeaconStore. func (kv *KVStore) GetLatestBlockHeader() ( *ctypes.BeaconBlockHeader, error, ) { return kv.latestBlockHeader.Get(kv.ctx) } // UpdateStateRootAtIndex updates the state root at the given slot. func (kv *KVStore) UpdateStateRootAtIndex( idx uint64, stateRoot common.Root, ) error { return kv.stateRoots.Set(kv.ctx, idx, stateRoot[:]) } // StateRootAtIndex returns the state root at the given slot. func (kv *KVStore) StateRootAtIndex( idx uint64, ) (common.Root, error) { bz, err := kv.stateRoots.Get(kv.ctx, idx) if err != nil { return common.Root{}, err } return common.Root(bz), nil } ================================================ FILE: storage/beacondb/index/validator.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package index import ( sdkcollections "cosmossdk.io/collections" "cosmossdk.io/collections/indexes" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" cmtcrypto "github.com/cometbft/cometbft/crypto" ) // Collection prefixes. const ( validatorByIndexPrefix = "val_idx_to_pk" validatorPubkeyToIndexPrefix = "val_pk_to_idx" validatorConsAddrToIndexPrefix = "val_cons_addr_to_idx" validatorEffectiveBalanceToIndexPrefix = "val_eff_bal_to_idx" ) // Validator is an interface that combines the ssz.Marshaler and // ssz.Unmarshaler interfaces. type Validator interface { constraints.SSZMarshallable // GetPubkey returns the public key of the validator. GetPubkey() crypto.BLSPubkey // GetEffectiveBalance returns the effective balance of the validator. GetEffectiveBalance() math.Gwei } // ValidatorsIndex is a struct that holds a unique index for validators based // on their public key. type ValidatorsIndex[ValidatorT Validator] struct { // Pubkey is a unique index mapping a validator's public key to their // numeric ID and vice versa. Pubkey *indexes.Unique[[]byte, uint64, ValidatorT] // EffectiveBalance is a multi-index mapping a validator's effective balance // to their numeric ID. EffectiveBalance *indexes.Multi[uint64, uint64, ValidatorT] // CometBFTAddress is a unique index mapping a validator's Comet BFT address // to their numeric ID. CometBFTAddress *indexes.Unique[[]byte, uint64, ValidatorT] } // IndexesList returns a list of all indexes associated with the // validatorsIndex. func (a ValidatorsIndex[ValidatorT]) IndexesList() []sdkcollections.Index[ uint64, ValidatorT, ] { return []sdkcollections.Index[uint64, ValidatorT]{ a.Pubkey, a.EffectiveBalance, a.CometBFTAddress, } } // NewValidatorsIndex creates a new validatorsIndex with a unique index for // validator public keys. func NewValidatorsIndex[ValidatorT Validator]( sb *sdkcollections.SchemaBuilder, ) ValidatorsIndex[ValidatorT] { return ValidatorsIndex[ValidatorT]{ Pubkey: indexes.NewUnique( sb, sdkcollections.NewPrefix(validatorPubkeyToIndexPrefix), validatorPubkeyToIndexPrefix, sdkcollections.BytesKey, sdkcollections.Uint64Key, func(_ uint64, validator ValidatorT) ([]byte, error) { pk := validator.GetPubkey() return pk[:], nil }, ), EffectiveBalance: indexes.NewMulti( sb, sdkcollections.NewPrefix(validatorEffectiveBalanceToIndexPrefix), validatorEffectiveBalanceToIndexPrefix, sdkcollections.Uint64Key, sdkcollections.Uint64Key, func(_ uint64, validator ValidatorT) (uint64, error) { return validator.GetEffectiveBalance().Unwrap(), nil }, ), CometBFTAddress: indexes.NewUnique( sb, sdkcollections.NewPrefix(validatorConsAddrToIndexPrefix), validatorConsAddrToIndexPrefix, sdkcollections.BytesKey, sdkcollections.Uint64Key, func(_ uint64, validator ValidatorT) ([]byte, error) { pk := validator.GetPubkey() return cmtcrypto.AddressHash(pk[:]).Bytes(), nil }, ), } } ================================================ FILE: storage/beacondb/index/validator_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package index_test import ( "testing" ) func TestValidatorIndexes(t *testing.T) { t.Parallel() // testName := "test" // logger := log.NewTestLogger(t) // keys := storetypes.NewKVStoreKeys(testName) // cms := integration.CreateMultiStore(keys, logger) // ctx := sdk.NewContext(cms, true, logger) // storeKey := keys[testName] // kvs := sdkruntime.NewKVStoreService(storeKey) // env := sdkruntime.NewEnvironment(kvs, logger) // beaconStore := beaconstore.NewStore(env) // // beaconStore = beaconStore.WithContext(ctx) // t.Run("add validator and replace its pubkey", func(t *testing.T) { // err := beaconStore.AddValidator(ctx, []byte("pubkey")) // require.NoError(t, err) // err = beaconStore.AddValidator(ctx, []byte("pubkey2")) // require.NoError(t, err) // // get the index // index, err := beaconStore.ValidatorIndexByPubkey([]byte("pubkey2")) // require.NoError(t, err) // require.Equal(t, uint64(1), index) // err = beaconStore.UpdateValidator( // ctx, // []byte("pubkey2"), // []byte("newpubkey"), // ) // require.NoError(t, err) // // get the index again, it should be the same as before // index, err = beaconStore.ValidatorIndexByPubkey( // []byte("newpubkey"), // ) // require.NoError(t, err) // require.Equal(t, uint64(1), index) // }) // t.Run("add the same validator twice", func(t *testing.T) { // err := beaconStore.AddValidator(ctx, []byte("pubkeyA")) // require.NoError(t, err) // err = beaconStore.AddValidator(ctx, []byte("pubkeyA")) // require.Error(t, err) // }) } ================================================ FILE: storage/beacondb/keys/keys.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package keys const ( WithdrawalQueuePrefix byte = iota RandaoMixPrefix SlashingsPrefix TotalSlashingPrefix ValidatorIndexPrefix BlockRootsPrefix StateRootsPrefix ValidatorByIndexPrefix ValidatorPubkeyToIndexPrefix ValidatorConsAddrToIndexPrefix ValidatorEffectiveBalanceToIndexPrefix LatestBeaconBlockHeaderPrefix SlotPrefix BalancesPrefix Eth1BlockHashPrefix Eth1DataPrefix Eth1DepositIndexPrefix LatestExecutionPayloadHeaderPrefix LatestExecutionPayloadVersionPrefix GenesisValidatorsRootPrefix NextWithdrawalIndexPrefix NextWithdrawalValidatorIndexPrefix ForkPrefix PendingPartialWithdrawalsPrefix ) const ( WithdrawalQueuePrefixHumanReadable = "WithdrawalQueuePrefix" RandaoMixPrefixHumanReadable = "RandaoMixPrefix" SlashingsPrefixHumanReadable = "SlashingsPrefix" TotalSlashingPrefixHumanReadable = "TotalSlashingPrefix" ValidatorIndexPrefixHumanReadable = "ValidatorIndexPrefix" BlockRootsPrefixHumanReadable = "BlockRootsPrefix" StateRootsPrefixHumanReadable = "StateRootsPrefix" ValidatorByIndexPrefixHumanReadable = "ValidatorByIndexPrefix" ValidatorPubkeyToIndexPrefixHumanReadable = "ValidatorPubkeyToIndexPrefix" ValidatorConsAddrToIndexPrefixHumanReadable = "ValidatorConsAddrToIndexPrefix" ValidatorEffectiveBalanceToIndexPrefixHumanReadable = "ValidatorEffectiveBalanceToIndexPrefix" LatestBeaconBlockHeaderPrefixHumanReadable = "LatestBeaconBlockHeaderPrefix" SlotPrefixHumanReadable = "SlotPrefix" BalancesPrefixHumanReadable = "BalancesPrefix" Eth1BlockHashPrefixHumanReadable = "Eth1BlockHashPrefix" Eth1DataPrefixHumanReadable = "Eth1DataPrefix" Eth1DepositIndexPrefixHumanReadable = "Eth1DepositIndexPrefix" LatestExecutionPayloadHeaderPrefixHumanReadable = "LatestExecutionPayloadHeaderPrefix" LatestExecutionPayloadVersionPrefixHumanReadable = "LatestExecutionPayloadVersionPrefix" GenesisValidatorsRootPrefixHumanReadable = "GenesisValidatorsRootPrefix" NextWithdrawalIndexPrefixHumanReadable = "NextWithdrawalIndexPrefix" NextWithdrawalValidatorIndexPrefixHumanReadable = "NextWithdrawalValidatorIndexPrefix" ForkPrefixHumanReadable = "ForkPrefix" PendingPartialWithdrawalsPrefixHumanReadable = "PendingPartialWithdrawalsPrefix" ) ================================================ FILE: storage/beacondb/kvstore.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import ( "context" "fmt" sdkcollections "cosmossdk.io/collections" "cosmossdk.io/core/store" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/storage/beacondb/index" "github.com/berachain/beacon-kit/storage/beacondb/keys" "github.com/berachain/beacon-kit/storage/encoding" sdk "github.com/cosmos/cosmos-sdk/types" ) // KVStore is a wrapper around an sdk.Context // that provides access to all beacon related data. type KVStore struct { ctx context.Context // Versioning // genesisValidatorsRoot is the root of the genesis validators. genesisValidatorsRoot sdkcollections.Item[[]byte] // slot is the current slot. slot sdkcollections.Item[uint64] // fork is the current fork fork sdkcollections.Item[*ctypes.Fork] // History // latestBlockHeader stores the latest beacon block header. latestBlockHeader sdkcollections.Item[*ctypes.BeaconBlockHeader] // blockRoots stores the block roots for the current epoch. blockRoots sdkcollections.Map[uint64, []byte] // stateRoots stores the state roots for the current epoch. stateRoots sdkcollections.Map[uint64, []byte] // Eth1 // eth1Data stores the latest eth1 data. eth1Data sdkcollections.Item[*ctypes.Eth1Data] // eth1DepositIndex is the index of the latest eth1 deposit. eth1DepositIndex sdkcollections.Item[uint64] // latestExecutionPayloadVersion stores the latest execution payload // version. latestExecutionPayloadVersion sdkcollections.Item[uint32] // latestExecutionPayloadCodec is the codec for the latest execution // payload, it allows us to update the codec with the latest version. latestExecutionPayloadCodec *encoding.SSZVersionedValueCodec[*ctypes.ExecutionPayloadHeader] // latestExecutionPayloadHeader stores the latest execution payload header. latestExecutionPayloadHeader sdkcollections.Item[*ctypes.ExecutionPayloadHeader] // Registry // validatorIndex provides the next available index for a new validator. validatorIndex sdkcollections.Sequence // validators stores the list of validators. validators *sdkcollections.IndexedMap[ uint64, *ctypes.Validator, index.ValidatorsIndex[*ctypes.Validator], ] // balances stores the list of balances. balances sdkcollections.Map[uint64, uint64] // nextWithdrawalIndex stores the next global withdrawal index. nextWithdrawalIndex sdkcollections.Item[uint64] // nextWithdrawalValidatorIndex stores the next withdrawal validator index // for each validator. nextWithdrawalValidatorIndex sdkcollections.Item[uint64] // Randomness // randaoMix stores the randao mix for the current epoch. randaoMix sdkcollections.Map[uint64, []byte] // Slashings // slashings stores the slashings for the current epoch. slashings sdkcollections.Map[uint64, uint64] // totalSlashing stores the total slashing in the vector range. totalSlashing sdkcollections.Item[uint64] // pendingPartialWithdrawals stores the PendingPartialWithdrawals introduced in Electra. // These are the operations done on this collection: // 1. get_pending_balance_to_withdraw -> requires iteration // 2. get_expected_withdrawals -> requires iterations // 3. process_withdrawal_request -> requires number of entries in the collection and adding new entries // 4. process_withdrawals -> requires removing entries from the collection // It is easiest to have these operations be done on an `Item` that is a list under the hood rather than // `sdkcollection` native types due to lack of support for lists. // We must use `*ctypes.PendingPartialWithdrawals` instead of `ctypes.PendingPartialWithdrawals` as marshalling // methods require a pointer receiver. pendingPartialWithdrawals sdkcollections.Item[*ctypes.PendingPartialWithdrawals] } // New creates a new instance of Store. // //nolint:funlen // its not overly complex. func New(kss store.KVStoreService) *KVStore { var ( schemaBuilder = sdkcollections.NewSchemaBuilder(kss) payloadCodec = &encoding.SSZVersionedValueCodec[*ctypes.ExecutionPayloadHeader]{ NewEmptyF: ctypes.NewEmptyExecutionPayloadHeaderWithVersion, } ) res := &KVStore{ ctx: nil, // set by WithContext or Copy genesisValidatorsRoot: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.GenesisValidatorsRootPrefix}), keys.GenesisValidatorsRootPrefixHumanReadable, sdkcollections.BytesValue, ), slot: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.SlotPrefix}), keys.SlotPrefixHumanReadable, sdkcollections.Uint64Value, ), fork: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.ForkPrefix}), keys.ForkPrefixHumanReadable, encoding.SSZValueCodec[*ctypes.Fork]{ NewEmptyF: ctypes.NewEmptyFork, }, ), blockRoots: sdkcollections.NewMap( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.BlockRootsPrefix}), keys.BlockRootsPrefixHumanReadable, sdkcollections.Uint64Key, sdkcollections.BytesValue, ), stateRoots: sdkcollections.NewMap( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.StateRootsPrefix}), keys.StateRootsPrefixHumanReadable, sdkcollections.Uint64Key, sdkcollections.BytesValue, ), eth1Data: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.Eth1DataPrefix}), keys.Eth1DataPrefixHumanReadable, encoding.SSZValueCodec[*ctypes.Eth1Data]{ NewEmptyF: ctypes.NewEmptyEth1Data, }, ), eth1DepositIndex: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.Eth1DepositIndexPrefix}), keys.Eth1DepositIndexPrefixHumanReadable, sdkcollections.Uint64Value, ), latestExecutionPayloadVersion: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix( []byte{keys.LatestExecutionPayloadVersionPrefix}, ), keys.LatestExecutionPayloadVersionPrefixHumanReadable, sdkcollections.Uint32Value, ), latestExecutionPayloadCodec: payloadCodec, latestExecutionPayloadHeader: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix( []byte{keys.LatestExecutionPayloadHeaderPrefix}, ), keys.LatestExecutionPayloadHeaderPrefixHumanReadable, payloadCodec, ), validatorIndex: sdkcollections.NewSequence( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.ValidatorIndexPrefix}), keys.ValidatorIndexPrefixHumanReadable, ), validators: sdkcollections.NewIndexedMap( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.ValidatorByIndexPrefix}), keys.ValidatorByIndexPrefixHumanReadable, sdkcollections.Uint64Key, encoding.SSZValueCodec[*ctypes.Validator]{ NewEmptyF: ctypes.NewEmptyValidator, }, index.NewValidatorsIndex[*ctypes.Validator](schemaBuilder), ), balances: sdkcollections.NewMap( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.BalancesPrefix}), keys.BalancesPrefixHumanReadable, sdkcollections.Uint64Key, sdkcollections.Uint64Value, ), randaoMix: sdkcollections.NewMap( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.RandaoMixPrefix}), keys.RandaoMixPrefixHumanReadable, sdkcollections.Uint64Key, sdkcollections.BytesValue, ), slashings: sdkcollections.NewMap( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.SlashingsPrefix}), keys.SlashingsPrefixHumanReadable, sdkcollections.Uint64Key, sdkcollections.Uint64Value, ), nextWithdrawalIndex: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.NextWithdrawalIndexPrefix}), keys.NextWithdrawalIndexPrefixHumanReadable, sdkcollections.Uint64Value, ), nextWithdrawalValidatorIndex: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix( []byte{keys.NextWithdrawalValidatorIndexPrefix}, ), keys.NextWithdrawalValidatorIndexPrefixHumanReadable, sdkcollections.Uint64Value, ), totalSlashing: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.TotalSlashingPrefix}), keys.TotalSlashingPrefixHumanReadable, sdkcollections.Uint64Value, ), latestBlockHeader: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix( []byte{keys.LatestBeaconBlockHeaderPrefix}, ), keys.LatestBeaconBlockHeaderPrefixHumanReadable, encoding.SSZValueCodec[*ctypes.BeaconBlockHeader]{ NewEmptyF: ctypes.NewEmptyBeaconBlockHeader, }, ), pendingPartialWithdrawals: sdkcollections.NewItem( schemaBuilder, sdkcollections.NewPrefix([]byte{keys.PendingPartialWithdrawalsPrefix}), keys.PendingPartialWithdrawalsPrefixHumanReadable, encoding.SSZValueCodec[*ctypes.PendingPartialWithdrawals]{ NewEmptyF: ctypes.NewEmptyPendingPartialWithdrawals, }, ), } if _, err := schemaBuilder.Build(); err != nil { panic(fmt.Errorf("failed building KVStore schema: %w", err)) } return res } // Copy returns a copy of the Store. func (kv *KVStore) Copy(ctx context.Context) *KVStore { // TODO: Decouple the KVStore type from the Cosmos-SDK. cctx, _ := sdk.UnwrapSDKContext(ctx).CacheContext() //nolint:contextcheck // `cctx` is inherited from the parent context `ctx`. ss := kv.WithContext(cctx) return ss } // Context returns the context of the Store. func (kv *KVStore) Context() context.Context { return kv.ctx } // WithContext returns a copy of the Store with the given context. func (kv *KVStore) WithContext(ctx context.Context) *KVStore { cpy := *kv cpy.ctx = ctx return &cpy } ================================================ FILE: storage/beacondb/randao.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import "github.com/berachain/beacon-kit/primitives/common" // UpdateRandaoMixAtIndex sets the current RANDAO mix in the store. func (kv *KVStore) UpdateRandaoMixAtIndex( index uint64, mix common.Bytes32, ) error { return kv.randaoMix.Set(kv.ctx, index, mix[:]) } // GetRandaoMixAtIndex retrieves the current RANDAO mix from the store. func (kv *KVStore) GetRandaoMixAtIndex( index uint64, ) (common.Bytes32, error) { bz, err := kv.randaoMix.Get(kv.ctx, index) if err != nil { return common.Bytes32{}, err } return common.Bytes32(bz), nil } ================================================ FILE: storage/beacondb/registry.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import ( "errors" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/math" ) // AddValidator registers a new validator in the beacon state. func (kv *KVStore) AddValidator(val *ctypes.Validator) error { // Get the next validator index from the sequence. idx, err := kv.validatorIndex.Next(kv.ctx) if err != nil { return err } // Push onto the validators list. if err = kv.validators.Set(kv.ctx, idx, val); err != nil { return err } return kv.balances.Set(kv.ctx, idx, 0) } // UpdateValidatorAtIndex updates a validator at a specific index. func (kv *KVStore) UpdateValidatorAtIndex( index math.ValidatorIndex, val *ctypes.Validator, ) error { return kv.validators.Set(kv.ctx, index.Unwrap(), val) } // ValidatorIndexByPubkey returns the validator address by index. func (kv *KVStore) ValidatorIndexByPubkey( pubkey crypto.BLSPubkey, ) (math.ValidatorIndex, error) { idx, err := kv.validators.Indexes.Pubkey.MatchExact( kv.ctx, pubkey[:], ) if err != nil { return 0, err } return math.ValidatorIndex(idx), nil } // ValidatorIndexByCometBFTAddress returns the validator address by index. func (kv *KVStore) ValidatorIndexByCometBFTAddress( cometBFTAddress []byte, ) (math.ValidatorIndex, error) { idx, err := kv.validators.Indexes.CometBFTAddress.MatchExact( kv.ctx, cometBFTAddress, ) if err != nil { return 0, err } return math.ValidatorIndex(idx), nil } // ValidatorByIndex returns the validator address by index. func (kv *KVStore) ValidatorByIndex( index math.ValidatorIndex, ) (*ctypes.Validator, error) { val, err := kv.validators.Get(kv.ctx, index.Unwrap()) if err != nil { var t *ctypes.Validator return t, err } return val, err } // GetValidators retrieves all validators from the beacon state. func (kv *KVStore) GetValidators() ( ctypes.Validators, error, ) { registrySize, err := kv.validatorIndex.Peek(kv.ctx) if err != nil { return nil, err } var ( vals = make([]*ctypes.Validator, 0, registrySize) val *ctypes.Validator ) iter, err := kv.validators.Iterate(kv.ctx, nil) if err != nil { return nil, err } defer func() { err = errors.Join(err, iter.Close()) }() for ; iter.Valid(); iter.Next() { val, err = iter.Value() if err != nil { return nil, err } vals = append(vals, val) } return vals, err } // GetTotalValidators returns the total number of validators. func (kv *KVStore) GetTotalValidators() (math.U64, error) { validators, err := kv.GetValidators() if err != nil { return 0, err } return math.U64(len(validators)), nil } // GetBalance returns the balance of a validator. func (kv *KVStore) GetBalance( idx math.ValidatorIndex, ) (math.Gwei, error) { balance, err := kv.balances.Get(kv.ctx, idx.Unwrap()) return math.Gwei(balance), err } // SetBalance sets the balance of a validator. func (kv *KVStore) SetBalance( idx math.ValidatorIndex, balance math.Gwei, ) error { return kv.balances.Set(kv.ctx, idx.Unwrap(), balance.Unwrap()) } // GetBalances returns the balancse of all validator. func (kv *KVStore) GetBalances() ([]uint64, error) { var balances []uint64 iter, err := kv.balances.Iterate(kv.ctx, nil) if err != nil { return nil, err } defer func() { err = errors.Join(err, iter.Close()) }() var balance uint64 for ; iter.Valid(); iter.Next() { balance, err = iter.Value() if err != nil { return nil, err } balances = append(balances, balance) } return balances, err } // GetPendingPartialWithdrawals is equivalent to `pending_partial_withdrawals` // If called before electra, will return an error. func (kv *KVStore) GetPendingPartialWithdrawals() ([]*ctypes.PendingPartialWithdrawal, error) { pendingPartialWithdrawals, err := kv.pendingPartialWithdrawals.Get(kv.ctx) if err != nil { return nil, err } if pendingPartialWithdrawals == nil { return nil, errors.New("unexpected nil pending partial withdrawals") } return *pendingPartialWithdrawals, err } // SetPendingPartialWithdrawals sets the pending partial withdrawals func (kv *KVStore) SetPendingPartialWithdrawals(pendingPartialWithdrawals []*ctypes.PendingPartialWithdrawal) error { ppw := ctypes.PendingPartialWithdrawals(pendingPartialWithdrawals) return kv.pendingPartialWithdrawals.Set(kv.ctx, &ppw) } ================================================ FILE: storage/beacondb/registry_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb_test import ( "context" "fmt" "testing" corestore "cosmossdk.io/core/store" "cosmossdk.io/log" "cosmossdk.io/store" "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/storage" "github.com/berachain/beacon-kit/storage/beacondb" "github.com/berachain/beacon-kit/storage/db" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" ) type testKVStoreService struct { ctx sdk.Context } func (kvs *testKVStoreService) OpenKVStore(context.Context) corestore.KVStore { //nolint:contextcheck // fine with tests store := sdk.UnwrapSDKContext(kvs.ctx).KVStore(testStoreKey) return storage.NewKVStore(store) } var testStoreKey = storetypes.NewKVStoreKey("storage-tests") func TestBalances(t *testing.T) { t.Parallel() store, err := initTestStore() require.NoError(t, err) // no balance to start res, err := store.GetBalances() require.NoError(t, err) require.Empty(t, res) // add balances var ( idx1, idx2 = math.U64(1_987), math.U64(1_989) inBal1, inBal2 = math.U64(8_992), math.U64(10_000) ) require.NoError(t, store.SetBalance(idx1, inBal1)) require.NoError(t, store.SetBalance(idx2, inBal2)) // check we can query added balances outBal, err := store.GetBalance(idx1) require.NoError(t, err) require.Equal(t, inBal1, outBal) outBal, err = store.GetBalance(idx2) require.NoError(t, err) require.Equal(t, inBal2, outBal) res, err = store.GetBalances() require.NoError(t, err) require.Len(t, res, 2) require.Equal(t, inBal1.Unwrap(), res[0]) require.Equal(t, inBal2.Unwrap(), res[1]) // update existing balances newInBal1, newInBal2 := math.U64(0), inBal2*2 require.NoError(t, store.SetBalance(idx1, newInBal1)) require.NoError(t, store.SetBalance(idx2, newInBal2)) // check we can query updated balances outBal, err = store.GetBalance(idx1) require.NoError(t, err) require.Equal(t, newInBal1, outBal) outBal, err = store.GetBalance(idx2) require.NoError(t, err) require.Equal(t, newInBal2, outBal) res, err = store.GetBalances() require.NoError(t, err) require.Len(t, res, 2) require.Equal(t, newInBal1.Unwrap(), res[0]) require.Equal(t, newInBal2.Unwrap(), res[1]) } func TestValidators(t *testing.T) { t.Parallel() store, err := initTestStore() require.NoError(t, err) // no validators to start res, err := store.GetValidators() require.NoError(t, err) require.Empty(t, res) // add validators var ( inVal1 = &types.Validator{ Pubkey: bytes.B48{0x01}, EffectiveBalance: 31e9, } inVal2 = &types.Validator{ Pubkey: bytes.B48{0x02}, EffectiveBalance: 32e9, } ) require.NoError(t, store.AddValidator(inVal1)) require.NoError(t, store.AddValidator(inVal2)) // check we can query added validators valIdx1, err := store.ValidatorIndexByPubkey(inVal1.GetPubkey()) require.NoError(t, err) outVal, err := store.ValidatorByIndex(valIdx1) require.NoError(t, err) require.Equal(t, inVal1, outVal) valIdx2, err := store.ValidatorIndexByPubkey(inVal2.GetPubkey()) require.NoError(t, err) outVal, err = store.ValidatorByIndex(valIdx2) require.NoError(t, err) require.Equal(t, inVal2, outVal) valCount, err := store.GetTotalValidators() require.NoError(t, err) require.Equal(t, math.U64(2), valCount) res, err = store.GetValidators() require.NoError(t, err) require.Len(t, res, int(valCount)) require.Equal(t, inVal1, res[0]) require.Equal(t, inVal2, res[1]) // update existing validators balances var ( inUpdatedVal1 = &types.Validator{ Pubkey: inVal1.GetPubkey(), EffectiveBalance: inVal1.EffectiveBalance * 2, } inUpdatedVal2 = &types.Validator{ Pubkey: inVal2.GetPubkey(), EffectiveBalance: inVal1.EffectiveBalance / 2, } ) require.NoError(t, store.UpdateValidatorAtIndex(valIdx1, inUpdatedVal1)) require.NoError(t, store.UpdateValidatorAtIndex(valIdx2, inUpdatedVal2)) // check we can query updated validators upValIdx1, err := store.ValidatorIndexByPubkey(inVal1.GetPubkey()) require.NoError(t, err) require.Equal(t, valIdx1, upValIdx1) outVal, err = store.ValidatorByIndex(upValIdx1) require.NoError(t, err) require.Equal(t, inUpdatedVal1, outVal) upValIdx2, err := store.ValidatorIndexByPubkey(inVal2.GetPubkey()) require.NoError(t, err) require.Equal(t, valIdx2, upValIdx2) outVal, err = store.ValidatorByIndex(upValIdx2) require.NoError(t, err) require.Equal(t, inUpdatedVal2, outVal) upValCount, err := store.GetTotalValidators() require.NoError(t, err) require.Equal(t, valCount, upValCount) res, err = store.GetValidators() require.NoError(t, err) require.Len(t, res, int(valCount)) require.Equal(t, inUpdatedVal1, res[0]) require.Equal(t, inUpdatedVal2, res[1]) } // TestPendingPartialWithdrawals_Nil verifies that if no pending partial withdrawals // have been set, then GetPendingPartialWithdrawals returns an error. func TestPendingPartialWithdrawals_Nil(t *testing.T) { t.Parallel() store, err := initTestStore() require.NoError(t, err) ppw, err := store.GetPendingPartialWithdrawals() require.ErrorContains(t, err, "collections: not found: key 'no_key' of type SSZMarshallable") require.Nil(t, ppw) } // TestPendingPartialWithdrawals_EmptySlice verifies that when setting an empty slice, the Set and Get operations succeed. func TestPendingPartialWithdrawals_EmptySlice(t *testing.T) { t.Parallel() store, err := initTestStore() require.NoError(t, err) // Attempt to set an empty slice. err = store.SetPendingPartialWithdrawals([]*types.PendingPartialWithdrawal{}) var ppw []*types.PendingPartialWithdrawal require.NoError(t, err) ppw, err = store.GetPendingPartialWithdrawals() require.NoError(t, err) require.Empty(t, ppw) } // TestPendingPartialWithdrawals_SetAndGetNonEmpty verifies that setting a non-empty list of pending partial withdrawals succeeds. func TestPendingPartialWithdrawals_SetAndGetNonEmpty(t *testing.T) { t.Parallel() store, err := initTestStore() require.NoError(t, err) // Create sample pending partial withdrawal entries. entry1 := &types.PendingPartialWithdrawal{ ValidatorIndex: math.U64(1), Amount: math.U64(100), WithdrawableEpoch: math.U64(15), } entry2 := &types.PendingPartialWithdrawal{ ValidatorIndex: math.U64(2), Amount: math.U64(200), WithdrawableEpoch: math.U64(20), } sampleWithdrawals := []*types.PendingPartialWithdrawal{entry1, entry2} var ppw []*types.PendingPartialWithdrawal // Attempt to set the non-empty slice. err = store.SetPendingPartialWithdrawals(sampleWithdrawals) require.NoError(t, err) ppw, err = store.GetPendingPartialWithdrawals() require.NoError(t, err) require.Equal(t, sampleWithdrawals, ppw) } // TestPendingPartialWithdrawals_Update verifies that updating the pending partial withdrawals works correctly. func TestPendingPartialWithdrawals_Update(t *testing.T) { t.Parallel() store, err := initTestStore() require.NoError(t, err) require.NoError(t, err) // Create initial pending partial withdrawal entries. entry1 := &types.PendingPartialWithdrawal{ ValidatorIndex: math.U64(1), Amount: math.U64(100), WithdrawableEpoch: math.U64(15), } entry2 := &types.PendingPartialWithdrawal{ ValidatorIndex: math.U64(2), Amount: math.U64(200), WithdrawableEpoch: math.U64(20), } initialWithdrawals := []*types.PendingPartialWithdrawal{entry1, entry2} var ppw []*types.PendingPartialWithdrawal // Set the initial list. err = store.SetPendingPartialWithdrawals(initialWithdrawals) require.NoError(t, err) // Now update by modifying entry1's amount and dropping entry2. updatedEntry := &types.PendingPartialWithdrawal{ ValidatorIndex: math.U64(1), Amount: math.U64(150), // Updated amount. WithdrawableEpoch: math.U64(15), } updatedWithdrawals := []*types.PendingPartialWithdrawal{updatedEntry} err = store.SetPendingPartialWithdrawals(updatedWithdrawals) require.NoError(t, err) ppw, err = store.GetPendingPartialWithdrawals() require.NoError(t, err) require.Equal(t, updatedWithdrawals, ppw) } func initTestStore() (*beacondb.KVStore, error) { db, err := db.OpenDB("", dbm.MemDBBackend) if err != nil { return nil, fmt.Errorf("failed opening mem db: %w", err) } var ( nopLog = log.NewNopLogger() nopMetrics = metrics.NewNoOpMetrics() ) cms := store.NewCommitMultiStore( db, nopLog, nopMetrics, ) cms.MountStoreWithDB(testStoreKey, storetypes.StoreTypeIAVL, nil) if err = cms.LoadLatestVersion(); err != nil { return nil, fmt.Errorf("failed to load latest version: %w", err) } ctx := sdk.NewContext(cms, true, nopLog) testStoreService := &testKVStoreService{ ctx: ctx, } return beacondb.New(testStoreService), nil } ================================================ FILE: storage/beacondb/slashing.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import ( "cosmossdk.io/collections" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/math" ) func (kv *KVStore) GetSlashings() ([]math.Gwei, error) { var slashings []math.Gwei iter, err := kv.slashings.Iterate(kv.ctx, nil) if err != nil { return nil, err } defer func() { err = errors.Join(err, iter.Close()) }() for ; iter.Valid(); iter.Next() { var slashing uint64 slashing, err = iter.Value() if err != nil { return nil, err } slashings = append(slashings, math.Gwei(slashing)) } return slashings, err } // GetSlashingAtIndex retrieves the slashing amount by index from the store. func (kv *KVStore) GetSlashingAtIndex( index uint64, ) (math.Gwei, error) { amount, err := kv.slashings.Get(kv.ctx, index) if errors.Is(err, collections.ErrNotFound) { return 0, nil } else if err != nil { return 0, err } return math.Gwei(amount), nil } // SetSlashingAtIndex sets the slashing amount in the store. func (kv *KVStore) SetSlashingAtIndex( index uint64, amount math.Gwei, ) error { return kv.slashings.Set(kv.ctx, index, amount.Unwrap()) } // GetTotalSlashing retrieves the total slashing amount from the store. func (kv *KVStore) GetTotalSlashing() (math.Gwei, error) { total, err := kv.totalSlashing.Get(kv.ctx) if errors.Is(err, collections.ErrNotFound) { return 0, nil } else if err != nil { return 0, err } return math.Gwei(total), nil } // SetTotalSlashing sets the total slashing amount in the store. func (kv *KVStore) SetTotalSlashing( amount math.Gwei, ) error { return kv.totalSlashing.Set(kv.ctx, amount.Unwrap()) } ================================================ FILE: storage/beacondb/staking_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb_test // type mockValidator struct { // *math.U64 // } // func (m *mockValidator) IsActive(_ math.Epoch) bool { // // Assuming a simple active status check based on a condition // // This is a mock implementation and should be replaced with actual logic // return true // } // func (m *mockValidator) GetPubkey() crypto.BLSPubkey { // // Return a mock BLS public key // // This is a mock implementation and should be replaced with actual logic // return crypto.BLSPubkey{} // } // func (m *mockValidator) GetEffectiveBalance() math.Gwei { // // Return a mock effective balance // // This is a mock implementation and should be replaced with actual logic // return 1000000 // 1 million Gwei as a placeholder // } // func testFactory() *math.U64 { // return (*math.U64)(nil) // } // func TestDeposits(t *testing.T) { // testName := "test" // logger := log.NewTestLogger(t) // keys := storetypes.NewKVStoreKeys(testName) // cms := integration.CreateMultiStore(keys, logger) // ctx := sdk.NewContext(cms, true, logger) // storeKey := keys[testName] // sdb := beacondb.New[ // *math.U64, *math.U64, *math.U64, *math.U64, *mockValidator, // ]( // sdkruntime.NewKVStoreService(storeKey), // testFactory, // ) // _ = sdb.WithContext(ctx) // t.Run("should work with deposit", func(t *testing.T) { // fakeDeposit := primitives.U64(69420) // err := sdb.EnqueueDeposits([]*primitives.U64{&fakeDeposit}) // require.NoError(t, err) // deposits, err := sdb.DequeueDeposits(1) // require.NoError(t, err) // require.Equal(t, fakeDeposit, *deposits[0]) // }) // } ================================================ FILE: storage/beacondb/versioning.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) // SetGenesisValidatorsRoot sets the genesis validators root in the beacon // state. func (kv *KVStore) SetGenesisValidatorsRoot( root common.Root, ) error { return kv.genesisValidatorsRoot.Set(kv.ctx, root[:]) } // GetGenesisValidatorsRoot retrieves the genesis validators root from the // beacon state. func (kv *KVStore) GetGenesisValidatorsRoot() (common.Root, error) { bz, err := kv.genesisValidatorsRoot.Get(kv.ctx) if err != nil { return common.Root{}, err } return common.Root(bz), nil } // GetSlot returns the current slot. func (kv *KVStore) GetSlot() (math.Slot, error) { slot, err := kv.slot.Get(kv.ctx) return math.Slot(slot), err } // SetSlot sets the current slot. func (kv *KVStore) SetSlot( slot math.Slot, ) error { return kv.slot.Set(kv.ctx, slot.Unwrap()) } ================================================ FILE: storage/beacondb/withdrawals.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package beacondb import "github.com/berachain/beacon-kit/primitives/math" // GetNextWithdrawalIndex returns the next withdrawal index. func (kv *KVStore) GetNextWithdrawalIndex() (uint64, error) { return kv.nextWithdrawalIndex.Get(kv.ctx) } // SetNextWithdrawalIndex sets the next withdrawal index. func (kv *KVStore) SetNextWithdrawalIndex( index uint64, ) error { return kv.nextWithdrawalIndex.Set(kv.ctx, index) } // GetNextWithdrawalValidatorIndex returns the next withdrawal validator index. func (kv *KVStore) GetNextWithdrawalValidatorIndex() ( math.ValidatorIndex, error, ) { idx, err := kv.nextWithdrawalValidatorIndex.Get(kv.ctx) return math.ValidatorIndex(idx), err } // SetNextWithdrawalValidatorIndex sets the next withdrawal validator index. func (kv *KVStore) SetNextWithdrawalValidatorIndex( index math.ValidatorIndex, ) error { return kv.nextWithdrawalValidatorIndex.Set(kv.ctx, index.Unwrap()) } ================================================ FILE: storage/block/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package block const defaultAvailabilityWindow = 8192 // Config is the configuration for the block service. type Config struct { // AvailabilityWindow is the number of slots to keep in the store. AvailabilityWindow int `mapstructure:"availability-window"` } // DefaultConfig returns the default configuration for the block service. func DefaultConfig() Config { return Config{ AvailabilityWindow: defaultAvailabilityWindow, } } ================================================ FILE: storage/block/interfaces.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package block import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" ) // BeaconBlock is a block in the beacon chain that has a slot, block root (hash // tree root), timestamp, and state root. type BeaconBlock interface { GetSlot() math.U64 HashTreeRoot() common.Root GetTimestamp() math.U64 GetStateRoot() common.Root } ================================================ FILE: storage/block/store.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package block import ( "fmt" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" lru "github.com/hashicorp/golang-lru/v2" ) var ErrBlockStoreNotEnabled = errors.New("block store not enabled") // KVStore is a simple memory store based implementation that stores metadata of // beacon blocks. type KVStore[BeaconBlockT BeaconBlock] struct { // Setting availabilityWindow to zero upon construction // causes caches to not be instantiated. Setter will fail // silently while Getters will err. enabled bool // Beacon block root to slot mapping is injective for finalized blocks. blockRoots *lru.Cache[common.Root, math.Slot] // Timestamp to slot mapping is injective for finalized blocks. This is // guaranteed by CometBFT consensus. So each slot will be associated with a // different timestamp (no overwriting) as we store only finalized blocks. timestamps *lru.Cache[math.U64, math.Slot] // Beacon state root to slot mapping is injective for finalized blocks. stateRoots *lru.Cache[common.Root, math.Slot] // Logger for the store. logger log.Logger } // NewStore creates a new block store. func NewStore[BeaconBlockT BeaconBlock]( logger log.Logger, availabilityWindow int, ) *KVStore[BeaconBlockT] { kvStore := &KVStore[BeaconBlockT]{ enabled: availabilityWindow != 0, logger: logger, } if !kvStore.enabled { // caches instantiations would fail with zero size // so we return early return kvStore } var err error kvStore.blockRoots, err = lru.New[common.Root, math.Slot](availabilityWindow) if err != nil { panic(fmt.Errorf("failed instantiating kvStore blockRoots: %w", err)) } kvStore.timestamps, err = lru.New[math.U64, math.Slot](availabilityWindow) if err != nil { panic(fmt.Errorf("failed instantiating kvStore timestamps: %w", err)) } kvStore.stateRoots, err = lru.New[common.Root, math.Slot](availabilityWindow) if err != nil { panic(fmt.Errorf("failed instantiating kvStore stateRoots: %w", err)) } return kvStore } // Set sets the block in the store, storing the block root, timestamp, and state root. // Only this function may potentially evict entries from the store if the availability // window is reached. func (kv *KVStore[BeaconBlockT]) Set(blk BeaconBlockT) error { if !kv.enabled { // nothing to do if store is disabled kv.logger.Debug("skipping set because block store is not enabled") return nil } slot := blk.GetSlot() kv.blockRoots.Add(blk.HashTreeRoot(), slot) kv.timestamps.Add(blk.GetTimestamp(), slot) kv.stateRoots.Add(blk.GetStateRoot(), slot) return nil } // GetSlotByBlockRoot retrieves the slot by a given block root from the store. func (kv *KVStore[BeaconBlockT]) GetSlotByBlockRoot(blockRoot common.Root) (math.Slot, error) { if !kv.enabled { return math.Slot(0), ErrBlockStoreNotEnabled } slot, ok := kv.blockRoots.Peek(blockRoot) if !ok { return 0, fmt.Errorf("slot not found at block root: %s", blockRoot) } return slot, nil } // GetParentSlotByTimestamp retrieves the parent slot by a given timestamp from // the store. func (kv *KVStore[BeaconBlockT]) GetParentSlotByTimestamp(timestamp math.U64) (math.Slot, error) { if !kv.enabled { return math.Slot(0), ErrBlockStoreNotEnabled } slot, ok := kv.timestamps.Peek(timestamp) if !ok { return slot, fmt.Errorf("slot not found at timestamp: %d", timestamp) } if slot == 0 { return slot, errors.New("parent slot not supported for genesis slot 0") } return slot - 1, nil } // GetSlotByStateRoot retrieves the slot by a given state root from the store. func (kv *KVStore[BeaconBlockT]) GetSlotByStateRoot(stateRoot common.Root) (math.Slot, error) { if !kv.enabled { return math.Slot(0), ErrBlockStoreNotEnabled } slot, ok := kv.stateRoots.Peek(stateRoot) if !ok { return 0, fmt.Errorf("slot not found at state root: %s", stateRoot) } return slot, nil } ================================================ FILE: storage/block/store_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package block_test import ( "testing" "github.com/berachain/beacon-kit/log/noop" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/storage/block" "github.com/stretchr/testify/require" ) type MockBeaconBlock struct { slot math.Slot } func (m MockBeaconBlock) GetSlot() math.Slot { return m.slot } func (m MockBeaconBlock) HashTreeRoot() common.Root { return [32]byte{byte(m.slot)} } func (m MockBeaconBlock) GetTimestamp() math.U64 { return m.slot } func (m MockBeaconBlock) GetStateRoot() common.Root { return [32]byte{byte(m.slot)} } func TestBlockStore(t *testing.T) { t.Parallel() blockStore := block.NewStore[*MockBeaconBlock](noop.NewLogger[any](), 5) var ( slot math.Slot err error ) // Set 7 blocks. // The latest block is 7 and should hold the last 5 blocks in the window. for i := 1; i <= 7; i++ { err = blockStore.Set(&MockBeaconBlock{slot: math.Slot(i)}) require.NoError(t, err) } // Get the slots by roots & timestamps. for i := math.Slot(3); i <= 7; i++ { slot, err = blockStore.GetSlotByBlockRoot([32]byte{byte(i)}) require.NoError(t, err) require.Equal(t, i, slot) slot, err = blockStore.GetParentSlotByTimestamp(i) require.NoError(t, err) require.Equal(t, i-1, slot) slot, err = blockStore.GetSlotByStateRoot([32]byte{byte(i)}) require.NoError(t, err) require.Equal(t, i, slot) } // Try getting a slot that doesn't exist. _, err = blockStore.GetSlotByBlockRoot([32]byte{byte(8)}) require.ErrorContains(t, err, "not found") _, err = blockStore.GetParentSlotByTimestamp(2) require.ErrorContains(t, err, "not found") } func TestBlockStoreZeroSize(t *testing.T) { t.Parallel() blockStore := block.NewStore[*MockBeaconBlock](noop.NewLogger[any](), 0) // If kvStore is disabled, setting any block would fail silently // Any get should fail instead. for i := 1; i <= 7; i++ { err := blockStore.Set(&MockBeaconBlock{slot: math.Slot(i)}) require.NoError(t, err) } // Get the slots by roots & timestamps. for i := math.Slot(3); i <= 7; i++ { _, err := blockStore.GetSlotByBlockRoot([32]byte{byte(i)}) require.ErrorIs(t, err, block.ErrBlockStoreNotEnabled) _, err = blockStore.GetParentSlotByTimestamp(i) require.ErrorIs(t, err, block.ErrBlockStoreNotEnabled) _, err = blockStore.GetSlotByStateRoot([32]byte{byte(i)}) require.ErrorIs(t, err, block.ErrBlockStoreNotEnabled) } // Try getting a slot that doesn't exist. _, err := blockStore.GetSlotByBlockRoot([32]byte{byte(8)}) require.ErrorIs(t, err, block.ErrBlockStoreNotEnabled) _, err = blockStore.GetParentSlotByTimestamp(2) require.ErrorIs(t, err, block.ErrBlockStoreNotEnabled) } ================================================ FILE: storage/db/db.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package db import ( "path/filepath" dbm "github.com/cosmos/cosmos-db" ) // OpenDB opens the application database using the appropriate driver. func OpenDB(rootDir string, backendType dbm.BackendType) (dbm.DB, error) { dataDir := filepath.Join(rootDir, "data") return dbm.NewDB("application", backendType, dataDir) } ================================================ FILE: storage/deposit/common/synced_db.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "cosmossdk.io/core/store" dbm "github.com/cosmos/cosmos-db" ) var _ store.KVStoreWithBatch = &syncedDB{} // We have verified experimentally that deposits are often *not* flushed // as soon as they are enqueue when pebbleDB is chosed as backend. This may // cause an issue with ungraceful restarts, which may lead to loss of deposits, // resulting in the node being unable to verify any incoming deposit. // SyncedDB solves the issues since it maps the Set call to a SetSync call // which ensure that every single deposit is flushed when enqueued. type syncedDB struct { db dbm.DB } func NewSynced(db dbm.DB) dbm.DB { return syncedDB{db: db} } func (s syncedDB) Get(key []byte) ([]byte, error) { return s.db.Get(key) } func (s syncedDB) Has(key []byte) (bool, error) { return s.db.Has(key) } func (s syncedDB) Set(key, value []byte) error { return s.db.SetSync(key, value) } func (s syncedDB) SetSync(key, value []byte) error { return s.db.SetSync(key, value) } func (s syncedDB) Delete(key []byte) error { return s.db.Delete(key) } func (s syncedDB) DeleteSync(key []byte) error { return s.db.DeleteSync(key) } func (s syncedDB) Iterator(start, end []byte) (store.Iterator, error) { return s.db.Iterator(start, end) } func (s syncedDB) ReverseIterator(start, end []byte) (store.Iterator, error) { return s.db.ReverseIterator(start, end) } func (s syncedDB) NewBatch() store.Batch { return s.db.NewBatch() } func (s syncedDB) NewBatchWithSize(i int) store.Batch { return s.db.NewBatchWithSize(i) } func (s syncedDB) Close() error { return s.db.Close() } func (s syncedDB) Print() error { return s.db.Print() } func (s syncedDB) Stats() map[string]string { return s.db.Stats() } ================================================ FILE: storage/deposit/store.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "context" "errors" "fmt" "sync" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" depositstorev1 "github.com/berachain/beacon-kit/storage/deposit/v1" dbm "github.com/cosmos/cosmos-db" ) const ( unset uint8 = 0 v1 uint8 = 1 ) type Store interface { GetDepositsByIndex(ctx context.Context, startIndex uint64, depRange uint64) (ctypes.Deposits, common.Root, error) EnqueueDeposits(ctx context.Context, deposits []*ctypes.Deposit) error Prune(ctx context.Context, start, end uint64) error Close() error } type StoreManager interface { Store } var ( _ Store = (*depositstorev1.KVStore)(nil) _ StoreManager = (*generalStore)(nil) ErrUnknownStoreVersion = errors.New("unknown deposit store version") ) // We have changed in time the way we stored deposits. generalStore is meant to offer // a single way to access deposits and to handle the data migration among versions when needed type generalStore struct { // mu protects storex for concurrent access mu sync.RWMutex currentVersion uint8 storeV1 *depositstorev1.KVStore logger log.Logger } func NewStore(dbV1 dbm.DB, logger log.Logger) StoreManager { storeV1 := depositstorev1.NewStore(dbV1, logger) currentVersion := v1 return &generalStore{ currentVersion: currentVersion, storeV1: storeV1, logger: logger, } } func (gs *generalStore) GetDepositsByIndex( ctx context.Context, startIndex uint64, depRange uint64, ) (ctypes.Deposits, common.Root, error) { gs.mu.RLock() defer gs.mu.RUnlock() switch gs.currentVersion { case v1: return gs.storeV1.GetDepositsByIndex(ctx, startIndex, depRange) default: return nil, common.Root{}, fmt.Errorf("%w, version %d", ErrUnknownStoreVersion, gs.currentVersion) } } func (gs *generalStore) EnqueueDeposits(ctx context.Context, deposits []*ctypes.Deposit) error { gs.mu.Lock() defer gs.mu.Unlock() switch gs.currentVersion { case v1: return gs.storeV1.EnqueueDeposits(ctx, deposits) default: return fmt.Errorf("%w, version %d", ErrUnknownStoreVersion, gs.currentVersion) } } func (gs *generalStore) Close() error { gs.mu.Lock() defer gs.mu.Unlock() return gs.storeV1.Close() } func (gs *generalStore) Prune(ctx context.Context, start, end uint64) error { gs.mu.Lock() defer gs.mu.Unlock() switch gs.currentVersion { case v1: return gs.storeV1.Prune(ctx, start, end) default: return fmt.Errorf("%w, version %d", ErrUnknownStoreVersion, gs.currentVersion) } } ================================================ FILE: storage/deposit/v1/provider.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "context" "cosmossdk.io/core/store" ) var _ store.KVStoreService = (*KVStoreProvider)(nil) // KVStoreProvider is a provider for a KV store. type KVStoreProvider struct { store.KVStoreWithBatch } // NewKVStoreProvider creates a new KV store provider. func NewKVStoreProvider(kvsb store.KVStoreWithBatch) *KVStoreProvider { return &KVStoreProvider{ KVStoreWithBatch: kvsb, } } // OpenKVStore opens a new KV store. func (p *KVStoreProvider) OpenKVStore(context.Context) store.KVStore { return p.KVStoreWithBatch } ================================================ FILE: storage/deposit/v1/store.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit import ( "context" "sync" sdkcollections "cosmossdk.io/collections" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/storage" depositstorecommon "github.com/berachain/beacon-kit/storage/deposit/common" "github.com/berachain/beacon-kit/storage/encoding" dbm "github.com/cosmos/cosmos-db" ) const KeyDepositPrefix = "deposit" // KVStore is a simple KV store based implementation that assumes // the deposit indexes are tracked outside of the kv store. type KVStore struct { store sdkcollections.Map[uint64, *ctypes.Deposit] // closeFunc is a closure that closes the underlying database // used by store to ensure that all writes are flushed to disk. // We guarantee that closeFunc is called at maximum only once. closeFunc CloseFunc once sync.Once // logger is used for logging information and errors. logger log.Logger } // closure type for closing the store. type CloseFunc func() error // NewStore creates a new deposit store. func NewStore( baseDB dbm.DB, logger log.Logger, ) *KVStore { spdbV1 := depositstorecommon.NewSynced(baseDB) kvsp := NewKVStoreProvider(spdbV1) closeFunc := spdbV1.Close schemaBuilder := sdkcollections.NewSchemaBuilder(kvsp) res := &KVStore{ store: sdkcollections.NewMap( schemaBuilder, sdkcollections.NewPrefix([]byte(KeyDepositPrefix)), KeyDepositPrefix, sdkcollections.Uint64Key, encoding.SSZValueCodec[*ctypes.Deposit]{ NewEmptyF: ctypes.NewEmptyDeposit, }, ), closeFunc: closeFunc, logger: logger, } if _, err := schemaBuilder.Build(); err != nil { panic(errors.Wrap(err, "failed building KVStore schema")) } return res } // Close closes the store by calling the closeFunc. It ensures that the // closeFunc is called at most once. func (kv *KVStore) Close() error { var err error kv.once.Do(func() { err = kv.closeFunc() }) return err } // GetDepositsByIndex returns the first N deposits starting from the given // index. If N is greater than the number of deposits, it returns up to the // last deposit. // Note: we return the hash root of the selected deposits to simplify block // building pre migration to deposit store V2. func (kv *KVStore) GetDepositsByIndex( ctx context.Context, startIndex uint64, depRange uint64, ) (ctypes.Deposits, common.Root, error) { var ( deposits = make(ctypes.Deposits, 0, depRange) endIdx = startIndex + depRange ) done := false for i := startIndex; i < endIdx && !done; i++ { deposit, err := kv.store.Get(ctx, i) switch { case err == nil: deposits = append(deposits, deposit) case errors.Is(err, sdkcollections.ErrNotFound): done = true // normal happy path, there are less than max allowed deposits default: return deposits, common.Root{}, errors.Wrapf( err, "failed to get deposit %d, start: %d, end: %d", i, startIndex, endIdx, ) } } kv.logger.Debug("GetDepositsByIndex", "start", startIndex, "end", endIdx) return deposits, deposits.HashTreeRoot(), nil } // EnqueueDeposits pushes multiple deposits to the queue. func (kv *KVStore) EnqueueDeposits(ctx context.Context, deposits []*ctypes.Deposit) error { for _, deposit := range deposits { idx := deposit.GetIndex().Unwrap() if err := kv.store.Set(ctx, idx, deposit); err != nil { return errors.Wrapf(err, "failed to enqueue deposit %d", idx) } } if len(deposits) > 0 { kv.logger.Debug( "EnqueueDeposit", "enqueued", len(deposits), "start", deposits[0].GetIndex(), "end", deposits[len(deposits)-1].GetIndex(), ) } return nil } // Prune removes the [start, end) deposits from the store. func (kv *KVStore) Prune(ctx context.Context, start, end uint64) error { if start > end { return errors.Wrapf( storage.ErrInvalidRange, "DepositKVStore Prune start: %d, end: %d", start, end) } for i := range end { // This only errors if the key passed in cannot be encoded. if err := kv.store.Remove(ctx, start+i); err != nil { return errors.Wrapf(err, "failed to prune deposit %d", start+i) } } kv.logger.Debug("Pruned deposits", "start", start, "end", end) return nil } ================================================ FILE: storage/deposit/v1/store_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package deposit_test import ( "testing" "cosmossdk.io/log" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/storage/db" "github.com/berachain/beacon-kit/storage/deposit/v1" dbm "github.com/cosmos/cosmos-db" "github.com/stretchr/testify/require" ) func BenchmarkDepositsInsertion(b *testing.B) { baseDB, err := db.OpenDB("", dbm.MemDBBackend) require.NoError(b, err) nopLog := log.NewNopLogger() dummyCtx := b.Context() var store *deposit.KVStore require.NotPanics(b, func() { store = deposit.NewStore(baseDB, nopLog) }) inputSize := 5_000 inputs := make([][]*types.Deposit, 0, inputSize) for i := range inputSize { b := uint8(i % 255) d := []*types.Deposit{ { // typing just to ease up insertions Pubkey: [48]byte{b}, Credentials: types.NewCredentialsFromExecutionAddress(common.ExecutionAddress{b}), Amount: 10_000, Signature: crypto.BLSSignature{b}, Index: uint64(i), }, } inputs = append(inputs, d) } var root common.Root b.ResetTimer() for range b.N { for i, d := range inputs { require.NoError(b, store.EnqueueDeposits(dummyCtx, d)) // this is why v1 is less efficient than v2. To get the historical root we need to // load all depoisits from genesis and hash them together. Here I allocate up to i+1 // so as least as possible. _, root, err = store.GetDepositsByIndex(dummyCtx, constants.FirstDepositIndex, uint64(i+1)) require.NoError(b, err) _ = root // an attempt to avoid compiler optimizations } } } ================================================ FILE: storage/encoding/ssz.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package encoding import ( "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constraints" "github.com/berachain/beacon-kit/primitives/encoding/ssz" "github.com/davecgh/go-spew/spew" ) // SSZValueCodec provides methods to encode and decode SSZ values. type SSZValueCodec[T constraints.SSZMarshallable] struct { NewEmptyF func() T // constructor } // Encode marshals the provided value into its SSZ encoding. func (SSZValueCodec[T]) Encode(value T) ([]byte, error) { return value.MarshalSSZ() } // Decode unmarshals the provided bytes into a value of type T. func (sc SSZValueCodec[T]) Decode(bz []byte) (T, error) { dest := sc.NewEmptyF() return dest, ssz.Unmarshal(bz, dest) } // EncodeJSON is not implemented and will panic if called. func (SSZValueCodec[T]) EncodeJSON(_ T) ([]byte, error) { panic("not implemented") } // DecodeJSON is not implemented and will panic if called. func (SSZValueCodec[T]) DecodeJSON(_ []byte) (T, error) { panic("not implemented") } // Stringify returns the string representation of the provided value. func (SSZValueCodec[T]) Stringify(value T) string { return spew.Sdump(value) } // ValueType returns the name of the interface that this codec is intended for. func (SSZValueCodec[T]) ValueType() string { return "SSZMarshallable" } // SSZVersionedValueCodec provides methods to encode and decode SSZ values for a specific version. type SSZVersionedValueCodec[T constraints.SSZMarshallable] struct { NewEmptyF func(common.Version) T // constructor latestVersion common.Version } // SetActiveForkVersion sets the fork version for the codec. func (cdc *SSZVersionedValueCodec[T]) SetActiveForkVersion(version common.Version) { cdc.latestVersion = version } // Encode marshals the provided value into its SSZ encoding. func (cdc *SSZVersionedValueCodec[T]) Encode(value T) ([]byte, error) { return value.MarshalSSZ() } // Decode unmarshals the provided bytes into a value of type T. func (cdc *SSZVersionedValueCodec[T]) Decode(b []byte) (T, error) { dest := cdc.NewEmptyF(cdc.latestVersion) return dest, ssz.Unmarshal(b, dest) } // EncodeJSON is not implemented and will panic if called. func (cdc *SSZVersionedValueCodec[T]) EncodeJSON(_ T) ([]byte, error) { panic("not implemented") } // DecodeJSON is not implemented and will panic if called. func (cdc *SSZVersionedValueCodec[T]) DecodeJSON(_ []byte) (T, error) { panic("not implemented") } // Stringify returns the string representation of the provided value. func (cdc *SSZVersionedValueCodec[T]) Stringify(value T) string { return spew.Sdump(value) } // ValueType returns the name of the interface that this codec is intended for. func (cdc *SSZVersionedValueCodec[T]) ValueType() string { return "SSZVersionedMarshallable" } ================================================ FILE: storage/encoding/u64.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package encoding import ( "cosmossdk.io/collections/codec" "github.com/berachain/beacon-kit/primitives/math" ) var ( // U64Key can be used to encode math.U64 keys. Encoding is big endian to // retain ordering. // //nolint:gochecknoglobals // stateless so can be reused. U64Key = codec.NewUint64Key[math.U64]() // U64Value implements a ValueCodec for uint64. // //nolint:gochecknoglobals // stateless so can be reused. U64Value = codec.KeyToValueCodec(U64Key) ) ================================================ FILE: storage/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package storage import "github.com/berachain/beacon-kit/errors" var ErrInvalidRange = errors.New("range start greater than end") ================================================ FILE: storage/filedb/db.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package filedb import ( "os" "path/filepath" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/log" "github.com/spf13/afero" ) // DB represents a filesystem backed key-value store. // It is useful for storing amounts of data that exceed what is // performant to store in a traditional key-value database. type DB struct { fs afero.Fs logger log.Logger rootDir string extension string dirPerms os.FileMode } // NewDB creates a new instance of the DB. func NewDB(opts ...Option) *DB { db := &DB{} for _, opt := range opts { if err := opt(db); err != nil { panic(errors.Wrap(err, "failed to apply option")) } } db.fs = afero.NewBasePathFs(afero.NewOsFs(), db.rootDir) return db } // Get retrieves the value for a key. func (db *DB) Get(key []byte) ([]byte, error) { return afero.ReadFile(db.fs, db.pathForKey(key)) } // Has returns true if the key exists in the database. func (db *DB) Has(key []byte) (bool, error) { exists, err := afero.Exists(db.fs, db.pathForKey(key)) if err != nil { return false, err } return exists, nil } // Set stores the value for a key. func (db *DB) Set(key []byte, value []byte) error { if exists, err := afero.Exists(db.fs, db.pathForKey(key)); err != nil { return err } else if exists { db.logger.Warn("Overriding existing key", "key", key) } if err := db.fs.MkdirAll( filepath.Dir(db.pathForKey(key)), db.dirPerms, ); err != nil { return err } file, err := db.fs.Create(db.pathForKey(key)) if err != nil { return errors.Wrap(err, "failed to create file") } defer file.Close() n, err := file.Write(value) if err != nil { return errors.Wrap(err, "failed to write to file") } db.logger.Debug("wrote %d bytes to %s", n, db.pathForKey(key)) return nil } // Delete removes the value for a key. func (db *DB) Delete(key []byte) error { return db.fs.RemoveAll(db.pathForKey(key)) } // pathForKey returns the path for a key. // TODO: for efficient storage we should expand this path. func (db *DB) pathForKey(key []byte) string { return string(key) + "." + db.extension } ================================================ FILE: storage/filedb/db_options.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package filedb import ( "os" "github.com/berachain/beacon-kit/log" "github.com/spf13/afero" ) type Option func(*DB) error // WithAferoFS sets the filesystem for the database. // NOTE: Should only be used for testing. func WithAferoFS(fs afero.Fs) Option { return func(db *DB) error { db.fs = fs return nil } } // WithDirectoryPermissions sets the permissions for the directory. func WithDirectoryPermissions(permissions os.FileMode) Option { return func(db *DB) error { db.dirPerms = permissions return nil } } // WithFileExtension sets the file extension for the database. func WithFileExtension(extension string) Option { return func(db *DB) error { db.extension = extension return nil } } // WithLogger sets the logger for the database. func WithLogger(logger log.Logger) Option { return func(db *DB) error { db.logger = logger return nil } } // WithRootDirectory sets the root directory for the database. func WithRootDirectory(rootDir string) Option { return func(db *DB) error { db.rootDir = rootDir return nil } } ================================================ FILE: storage/filedb/db_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package filedb_test import ( "testing" "cosmossdk.io/log" "github.com/berachain/beacon-kit/errors" file "github.com/berachain/beacon-kit/storage/filedb" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) func TestDB(t *testing.T) { t.Parallel() tests := []struct { name string setupFunc func(db *file.DB) error testFunc func(t *testing.T, db *file.DB) expectedError bool }{ { name: "NewDB", testFunc: func(t *testing.T, db *file.DB) { t.Helper() require.NotNil(t, db) }, }, { name: "SetAndGet", setupFunc: func(db *file.DB) error { return db.Set([]byte("key"), []byte("value")) }, testFunc: func(t *testing.T, db *file.DB) { t.Helper() retrievedValue, err := db.Get([]byte("key")) require.NoError(t, err) require.Equal(t, []byte("value"), retrievedValue) }, }, { name: "Has", setupFunc: func(db *file.DB) error { return db.Set([]byte("key"), []byte("value")) }, testFunc: func(t *testing.T, db *file.DB) { t.Helper() exists, err := db.Has([]byte("key")) require.NoError(t, err) require.True(t, exists) }, }, { name: "Delete", setupFunc: func(db *file.DB) error { return db.Set([]byte("key"), []byte("value")) }, testFunc: func(t *testing.T, db *file.DB) { t.Helper() exists, err := db.Has([]byte("key")) require.NoError(t, err) require.True(t, exists) err = db.Delete([]byte("key")) require.NoError(t, err) exists, err = db.Has([]byte("key")) require.NoError(t, err) require.False(t, exists) }, }, { name: "SetExistingKey", setupFunc: func(db *file.DB) error { if err := db.Set([]byte("key"), []byte("value1")); err != nil { return err } return db.Set([]byte("key"), []byte("value2")) }, testFunc: func(t *testing.T, db *file.DB) { t.Helper() retrievedValue, err := db.Get([]byte("key")) require.NoError(t, err) require.Equal(t, []byte("value2"), retrievedValue) }, }, { name: "GetNonExistingKey", testFunc: func(t *testing.T, db *file.DB) { t.Helper() _, err := db.Get([]byte("non-existing")) require.Error(t, err) }, expectedError: true, }, // If the key does not exist, `Has` will return false with error as nil { name: "HasNonExistingKey", testFunc: func(t *testing.T, db *file.DB) { t.Helper() exists, err := db.Has([]byte("non-existing")) require.NoError(t, err) require.False(t, exists) }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fs := afero.NewMemMapFs() db := file.NewDB( file.WithRootDirectory("/tmp/testdb"), file.WithFileExtension("txt"), file.WithDirectoryPermissions(0700), file.WithLogger(log.NewNopLogger()), file.WithAferoFS(fs), ) if tt.setupFunc != nil { if err := tt.setupFunc(db); (err != nil) != tt.expectedError { t.Fatalf( "setupFunc() error = %v, expectedError %v", err, tt.expectedError, ) } } if tt.testFunc != nil { tt.testFunc(t, db) } }) } t.Run("NewDBWithInvalidOption", func(t *testing.T) { invalidOption := func(_ *file.DB) error { return errors.New("invalid option") } require.Panics(t, func() { file.NewDB(invalidOption) }) }) } // Test with `etc` as root directory to cause creation failure // due to permission denied. func TestDB_SetExistingKey_CreateError(t *testing.T) { t.Parallel() test := struct { name string setupFunc func(db *file.DB) error testFunc func(t *testing.T, db *file.DB) expectedError bool }{ name: "SetExistingKeyWithCreateError", testFunc: func(t *testing.T, db *file.DB) { t.Helper() err := db.Set([]byte("key"), []byte("value")) require.Error(t, err) require.ErrorContains(t, err, "failed to create file") }, expectedError: true, } t.Run(test.name, func(t *testing.T) { t.Parallel() fs := afero.NewMemMapFs() db := file.NewDB( file.WithRootDirectory("/etc"), file.WithFileExtension("txt"), file.WithDirectoryPermissions(0700), file.WithLogger(log.NewNopLogger()), file.WithAferoFS(fs), ) if test.setupFunc != nil { if err := test.setupFunc(db); (err != nil) != test.expectedError { require.Error(t, err, "setupFunc() error = %v", err) } } if test.testFunc != nil { test.testFunc(t, db) } }) } // Test with root directory as a file. func TestDB_SetHas_NotDirError(t *testing.T) { t.Parallel() tests := []struct { name string setupFunc func(db *file.DB) error testFunc func(t *testing.T, db *file.DB) expectedError bool }{ { name: "HasWithError", testFunc: func(t *testing.T, db *file.DB) { t.Helper() value, err := db.Has([]byte("key")) require.Error(t, err) require.False(t, value) require.ErrorContains(t, err, "not a directory") }, expectedError: true, }, { name: "SetWithError", testFunc: func(t *testing.T, db *file.DB) { t.Helper() err := db.Set([]byte("key"), []byte("value")) require.Error(t, err) require.ErrorContains(t, err, "not a directory") }, expectedError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() fs := afero.NewMemMapFs() db := file.NewDB( file.WithRootDirectory("/etc/passwd"), file.WithFileExtension("txt"), file.WithDirectoryPermissions(0700), file.WithLogger(log.NewNopLogger()), file.WithAferoFS(fs), ) if tt.setupFunc != nil { if err := tt.setupFunc(db); (err != nil) != tt.expectedError { require.Error(t, err, "setupFunc() error = %v", err) } } if tt.testFunc != nil { tt.testFunc(t, db) } }) } } // Test with root directory to be created in `etc` // which will result in permission denied. func TestDB_Set_MkDirError(t *testing.T) { t.Parallel() test := struct { name string setupFunc func(db *file.DB) error testFunc func(t *testing.T, db *file.DB) expectedError bool }{ name: "SetWithMkdirAllError", testFunc: func(t *testing.T, db *file.DB) { t.Helper() err := db.Set([]byte("key"), []byte("value")) require.Error(t, err) }, expectedError: true, } t.Run(test.name, func(t *testing.T) { t.Parallel() fs := afero.NewMemMapFs() db := file.NewDB( file.WithRootDirectory("/etc/test"), file.WithFileExtension("txt"), file.WithDirectoryPermissions(0700), file.WithLogger(log.NewNopLogger()), file.WithAferoFS(fs), ) if test.setupFunc != nil { if err := test.setupFunc(db); (err != nil) != test.expectedError { require.Error(t, err, "setupFunc() error = %v", err) } } if test.testFunc != nil { test.testFunc(t, db) } }) } ================================================ FILE: storage/filedb/range_db.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package filedb import ( "bytes" "fmt" "os" "path/filepath" "strings" "sync" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/storage" db "github.com/berachain/beacon-kit/storage/interfaces" "github.com/spf13/afero" ) const ( keyFormat = "%d/%s" pathFormat = "%d/" keyParts = 2 ) var ( ErrRangeNotSupported = errors.New("RangeDB DeleteRange: delete range not supported for this db") ) // RangeDB is a database that stores versioned data. // It prefixes keys with an index. // Invariant: No index below firstNonNilIndex should be populated. type RangeDB struct { coreDB *DB rwMu sync.RWMutex // lowerBoundIndex is used as a loose check for stored indexes // monotonicity. The goal is to make sure we do not overwrite // indexes which have been or will be deleted eventually via pruning. lowerBoundIndex uint64 } // NewRangeDB creates a new RangeDB. func NewRangeDB(coreDB db.DB) *RangeDB { cDB, ok := coreDB.(*DB) if !ok { panic(ErrRangeNotSupported) } return &RangeDB{ coreDB: cDB, lowerBoundIndex: 0, } } // Get retrieves the value associated with the given index and key. // It prefixes the key with the index and a slash before querying the underlying // database. func (db *RangeDB) Get(index uint64, key []byte) ([]byte, error) { db.rwMu.RLock() defer db.rwMu.RUnlock() return db.coreDB.Get(prefix(index, key)) } // Has checks if the given index and key exist in the database. // It prefixes the key with the index and a slash before querying the underlying // database. func (db *RangeDB) Has(index uint64, key []byte) (bool, error) { db.rwMu.RLock() defer db.rwMu.RUnlock() return db.coreDB.Has(prefix(index, key)) } // Set stores the value with the given index and key in the database. // It prefixes the key with the index and a slash before storing it in the // underlying database. func (db *RangeDB) Set(index uint64, key []byte, value []byte) error { db.rwMu.Lock() defer db.rwMu.Unlock() index = max(index, db.lowerBoundIndex) // enforce invariant return db.coreDB.Set(prefix(index, key), value) } // Delete removes the value associated with the given index and key from the // database. It prefixes the key with the index and a slash before deleting it // from the underlying database. func (db *RangeDB) Delete(index uint64, key []byte) error { db.rwMu.Lock() defer db.rwMu.Unlock() return db.coreDB.Delete(prefix(index, key)) } // deleteRange removes all values associated with the given index from the // filesystem. It is INCLUSIVE of the `from` index and EXCLUSIVE of // the `to“ index. func (db *RangeDB) deleteRange(from, to uint64) error { if from > to { return fmt.Errorf( "RangeDB deleteRange start: %d, end: %d: %w", from, to, storage.ErrInvalidRange, ) } for i := from; i < to; i++ { path := fmt.Sprintf(pathFormat, i) if err := db.coreDB.fs.RemoveAll(path); err != nil { return fmt.Errorf( "RangeDB DeleteRange failed RemoveAll index %d: %w", i, err, ) } } return nil } // Prune removes all values in the given range [start, end) from the db. func (db *RangeDB) Prune(start, end uint64) error { db.rwMu.Lock() defer db.rwMu.Unlock() start = max(start, db.lowerBoundIndex) if start > end { return fmt.Errorf( "RangeDB Prune start: %d, end: %d: %w", start, end, storage.ErrInvalidRange, ) } // DeleteRange may fail and so some files to be pruned may have not // been removed. We *do not* retry to prune those files to avoid getting // stuck with them. Instead we update lowerBoundIndex as if deletion // was successful and we return an error. err := db.deleteRange(start, end) db.lowerBoundIndex = end return err } // DeleteByIndex removes all entries at the specified index. func (db *RangeDB) DeleteByIndex(index uint64) error { db.rwMu.Lock() defer db.rwMu.Unlock() path := fmt.Sprintf(pathFormat, index) if err := db.coreDB.fs.RemoveAll(path); err != nil && !os.IsNotExist(err) { return fmt.Errorf("RangeDB DeleteByIndex failed to remove index %d: %w", index, err) } // Note: We intentionally do not update lowerBoundIndex here. return nil } // GetByIndex takes the database index and returns all associated entries, // expecting database keys to follow the prefix() format. If index does not // exist in the DB for any reason (pruned, invalid index), an empty list is // returned with no error. func (db *RangeDB) GetByIndex(index uint64) ([][]byte, error) { db.rwMu.RLock() defer db.rwMu.RUnlock() indexDir := fmt.Sprintf(pathFormat, index) entries, err := afero.ReadDir(db.coreDB.fs, indexDir) if err != nil { if os.IsNotExist(err) { return [][]byte{}, nil } return nil, err } keys := make([][]byte, 0, len(entries)) for _, entry := range entries { if entry.IsDir() { continue } filename := entry.Name() if !strings.HasSuffix(filename, db.coreDB.extension) { continue } var sidecarBz []byte sidecarBz, err = afero.ReadFile(db.coreDB.fs, filepath.Join(indexDir, filename)) if err != nil { return keys, err } keys = append(keys, sidecarBz) } return keys, nil } // prefix prefixes the given key with the index and a slash. func prefix(index uint64, key []byte) []byte { return []byte(fmt.Sprintf(keyFormat, index, hex.EncodeBytes(key))) } // ExtractIndex extracts the index from a prefixed key. func ExtractIndex(prefixedKey []byte) (uint64, error) { parts := bytes.SplitN(prefixedKey, []byte("/"), keyParts) if len(parts) < keyParts { return 0, errors.New("invalid key format") } indexStr := string(parts[0]) index, err := math.U64FromString(indexStr) if err != nil { return 0, err } return index.Unwrap(), nil } ================================================ FILE: storage/filedb/range_db_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package filedb_test import ( "reflect" "testing" "cosmossdk.io/log" "github.com/berachain/beacon-kit/errors" file "github.com/berachain/beacon-kit/storage/filedb" "github.com/berachain/beacon-kit/storage/interfaces/mocks" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) // =========================== BASIC OPERATIONS ============================ func TestRangeDB(t *testing.T) { t.Parallel() tests := []struct { name string setupFunc func(rdb *file.RangeDB) error testFunc func(t *testing.T, rdb *file.RangeDB) expectedError bool }{ { name: "Get", setupFunc: func(rdb *file.RangeDB) error { return rdb.Set(1, []byte("testKey"), []byte("testValue")) }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() gotValue, err := rdb.Get(1, []byte("testKey")) require.NoError(t, err) require.Equal(t, []byte("testValue"), gotValue) }, }, { name: "Has", setupFunc: func(rdb *file.RangeDB) error { return rdb.Set(1, []byte("testKey"), []byte("testValue")) }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() exists, err := rdb.Has(1, []byte("testKey")) require.NoError(t, err) require.True(t, exists) }, }, { name: "Set", setupFunc: func(_ *file.RangeDB) error { return nil // No setup required }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() err := rdb.Set(1, []byte("testKey"), []byte("testValue")) require.NoError(t, err) exists, err := rdb.Has(1, []byte("testKey")) require.NoError(t, err) require.True(t, exists) }, }, { name: "Delete", setupFunc: func(rdb *file.RangeDB) error { return rdb.Set(1, []byte("testKey"), []byte("testValue")) }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() exists, err := rdb.Has(1, []byte("testKey")) require.NoError(t, err) require.True(t, exists) err = rdb.Delete(1, []byte("testKey")) require.NoError(t, err) exists, err = rdb.Has(1, []byte("testKey")) require.NoError(t, err) require.False(t, exists) }, }, { name: "Prune", setupFunc: func(rdb *file.RangeDB) error { for index := uint64(1); index <= 5; index++ { if err := rdb.Set( index, []byte("testKey"), []byte("testValue"), ); err != nil { return err } } return nil }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() err := rdb.Prune(1, 4) require.NoError(t, err) for index := uint64(1); index <= 3; index++ { var exists bool exists, err = rdb.Has(index, []byte("testKey")) require.NoError(t, err, "index %d", index) require.False(t, exists, "index %d", index) } for index := uint64(4); index <= 5; index++ { var exists bool exists, err = rdb.Has(index, []byte("testKey")) require.NoError(t, err, "index %d", index) require.True(t, exists, "index %d", index) } }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { rdb := file.NewRangeDB(newTestFDB("/tmp/testdb-1")) if tt.setupFunc != nil { require.NoError(t, tt.setupFunc(rdb)) } tt.testFunc(t, rdb) }) } } func TestExtractIndex(t *testing.T) { t.Parallel() tests := []struct { name string prefixedKey []byte expectedIdx uint64 expectedErr error }{ { name: "ValidKey", prefixedKey: []byte("12345/testKey"), expectedIdx: 12345, expectedErr: nil, }, { name: "InvalidKeyFormat", prefixedKey: []byte("testKey"), expectedIdx: 0, expectedErr: errors.New("invalid key format"), }, { name: "InvalidIndex", prefixedKey: []byte("abc/testKey"), expectedIdx: 0, expectedErr: errors.New( "strconv.ParseUint: parsing \"abc\": invalid syntax", ), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() idx, err := file.ExtractIndex(tt.prefixedKey) require.Equal(t, tt.expectedIdx, idx) if tt.expectedErr != nil { require.ErrorContains(t, err, tt.expectedErr.Error()) } }) } } // =========================== PRUNING ===================================== func TestRangeDB_DeleteRange_NotSupported(t *testing.T) { t.Parallel() tests := []struct { name string db *mocks.Db }{ { name: "DeleteRangeNotSupported", db: new(mocks.Db), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() t.Helper() require.Panics(t, func() { _ = file.NewRangeDB(tt.db) }) }) } } func TestRangeDB_Prune(t *testing.T) { t.Parallel() tests := []struct { name string setupFunc func(rdb *file.RangeDB) error start uint64 end uint64 expectedError bool testFunc func(t *testing.T, rdb *file.RangeDB) }{ { name: "PruneWithDeleteRange", setupFunc: func(rdb *file.RangeDB) error { return populateTestDB(rdb, 0, 50) }, start: 2, end: 7, expectedError: false, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() requireNotExist(t, rdb, 2, 6) requireExist(t, rdb, 0, 1) requireExist(t, rdb, 7, 50) }, }, { name: "PruneWithDeleteRange-InvalidRange", setupFunc: func(rdb *file.RangeDB) error { return populateTestDB(rdb, 0, 50) }, start: 7, end: 2, expectedError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() rdb := file.NewRangeDB(newTestFDB("/tmp/testdb-2")) if tt.setupFunc != nil { require.NoError(t, tt.setupFunc(rdb)) } err := rdb.Prune(tt.start, tt.end) if (err != nil) != tt.expectedError { t.Fatalf( "Prune() error = %v, expectedError %v", err, tt.expectedError, ) } if tt.testFunc != nil { tt.testFunc(t, rdb) } }) } } // =========================== INVARIANTS ================================. // invariant: all indexes up to the firstNonNilIndex should be nil. func TestRangeDB_Invariants(t *testing.T) { t.Parallel() // we ignore errors for most of the tests below because we want to ensure // that the invariants hold in exceptional circumstances. tests := []struct { name string setupFunc func(rdb *file.RangeDB) error testFunc func(t *testing.T, rdb *file.RangeDB) }{ { name: "Populate from empty", setupFunc: func(rdb *file.RangeDB) error { return populateTestDB(rdb, 1, 5) }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() requireNotExist(t, rdb, 0, lastConsequetiveNilIndex(rdb)) }, }, { name: "Delete from populated", setupFunc: func(rdb *file.RangeDB) error { return populateTestDB(rdb, 1, 5) }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() _ = rdb.Delete(2, []byte("key")) requireNotExist(t, rdb, 0, lastConsequetiveNilIndex(rdb)) }, }, { name: "Prune from populated", setupFunc: func(rdb *file.RangeDB) error { return populateTestDB(rdb, 1, 10) }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() _ = rdb.Prune(0, 3) requireNotExist(t, rdb, 0, lastConsequetiveNilIndex(rdb)) }, }, { name: "Populate, Prune, Set round trip", setupFunc: func(rdb *file.RangeDB) error { return populateTestDB(rdb, 1, 30) }, testFunc: func(t *testing.T, rdb *file.RangeDB) { t.Helper() if err := rdb.Prune(0, 25); err != nil { t.Fatalf("Prune() error = %v", err) } _ = populateTestDB(rdb, 5, 10) requireNotExist(t, rdb, 0, lastConsequetiveNilIndex(rdb)) }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() rdb := file.NewRangeDB(newTestFDB("/tmp/testdb-3")) if tt.setupFunc != nil { if err := tt.setupFunc(rdb); err != nil { requireNotExist( t, rdb, 0, lastConsequetiveNilIndex(rdb), ) } } if tt.testFunc != nil { tt.testFunc(t, rdb) } }) } } // =========================== DELETE BY INDEX ================================ // TestRangeDB_DeleteByIndex_DoesNotAffectLowerBound verifies the critical // invariant that DeleteByIndex does not modify lowerBoundIndex, unlike Prune. func TestRangeDB_DeleteByIndex_DoesNotAffectLowerBound(t *testing.T) { t.Parallel() rdb := file.NewRangeDB(newTestFDB("/tmp/testdb-deletebyindex")) // Populate indexes 1-10 require.NoError(t, populateTestDB(rdb, 1, 10)) // Prune indexes 1-5, which sets lowerBoundIndex to 5 require.NoError(t, rdb.Prune(1, 5)) lowerBoundBefore := getFirstNonNilIndex(rdb) require.Equal(t, uint64(5), lowerBoundBefore, "lowerBoundIndex should be 5 after pruning") // Delete index 7 using DeleteByIndex require.NoError(t, rdb.DeleteByIndex(7)) exists, err := rdb.Has(7, []byte("key")) require.NoError(t, err) require.False(t, exists, "index 7 should be deleted") // Verify lowerBoundIndex was NOT changed lowerBoundAfter := getFirstNonNilIndex(rdb) require.Equal(t, lowerBoundBefore, lowerBoundAfter, "DeleteByIndex must not modify lowerBoundIndex") // Prune again to verify DeleteByIndex didn't break the pruning mechanism require.NoError(t, rdb.Prune(5, 8)) // Verify the second prune worked correctly lowerBoundAfter = getFirstNonNilIndex(rdb) require.Equal(t, uint64(8), lowerBoundAfter, "second Prune should update lowerBoundIndex to 8") } // =============================== HELPERS ================================== // newTestFDB returns a new file DB instance with an in-memory filesystem. func newTestFDB(path string) *file.DB { fs := afero.NewMemMapFs() return file.NewDB( // don't reuse the same txt file for consecutive unit tests bc file // db slow AF file.WithRootDirectory(path), file.WithFileExtension("txt"), file.WithDirectoryPermissions(0700), file.WithLogger(log.NewNopLogger()), file.WithAferoFS(fs), ) } func getFirstNonNilIndex(rdb *file.RangeDB) uint64 { return reflect.ValueOf(rdb).Elem().FieldByName("lowerBoundIndex").Uint() } func lastConsequetiveNilIndex(rdb *file.RangeDB) uint64 { return uint64(max(int64(getFirstNonNilIndex(rdb))-1, 0)) } // requireNotExist requires the indexes from `from` to `to` to be empty. // func requireNotExist(t *testing.T, rdb *file.RangeDB, from uint64, to uint64) { t.Helper() for i := from; i <= to; i++ { exists, err := rdb.Has(i, []byte("key")) require.NoError(t, err) require.False(t, exists, "Index %d should have been pruned", i) } } // requireExist requires the indexes from `from` to `to` not be empty. func requireExist(t *testing.T, rdb *file.RangeDB, from uint64, to uint64) { t.Helper() for i := from; i <= to; i++ { exists, err := rdb.Has(i, []byte("key")) require.NoError(t, err) require.True(t, exists, "Index %d should not have been pruned", i) } } // populateTestDB populates the test DB with indexes from `from` to `to`. func populateTestDB(rdb *file.RangeDB, from, to uint64) error { for i := from; i <= to; i++ { if err := rdb.Set(i, []byte("key"), []byte("value")); err != nil { return err } } return nil } ================================================ FILE: storage/interfaces/db.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package interfaces // DB is the interface for a simple key-value store. type DB interface { Get(key []byte) ([]byte, error) Has(key []byte) (bool, error) Set(key []byte, value []byte) error Delete(key []byte) error // TODO: add Batch and full DB stuff. } ================================================ FILE: storage/interfaces/mocks/db.mock.go ================================================ // Code generated by mockery v2.53.5. DO NOT EDIT. package mocks import mock "github.com/stretchr/testify/mock" // Db is an autogenerated mock type for the DB type type Db struct { mock.Mock } type Db_Expecter struct { mock *mock.Mock } func (_m *Db) EXPECT() *Db_Expecter { return &Db_Expecter{mock: &_m.Mock} } // Delete provides a mock function with given fields: key func (_m *Db) Delete(key []byte) error { ret := _m.Called(key) if len(ret) == 0 { panic("no return value specified for Delete") } var r0 error if rf, ok := ret.Get(0).(func([]byte) error); ok { r0 = rf(key) } else { r0 = ret.Error(0) } return r0 } // Db_Delete_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Delete' type Db_Delete_Call struct { *mock.Call } // Delete is a helper method to define mock.On call // - key []byte func (_e *Db_Expecter) Delete(key interface{}) *Db_Delete_Call { return &Db_Delete_Call{Call: _e.mock.On("Delete", key)} } func (_c *Db_Delete_Call) Run(run func(key []byte)) *Db_Delete_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].([]byte)) }) return _c } func (_c *Db_Delete_Call) Return(_a0 error) *Db_Delete_Call { _c.Call.Return(_a0) return _c } func (_c *Db_Delete_Call) RunAndReturn(run func([]byte) error) *Db_Delete_Call { _c.Call.Return(run) return _c } // Get provides a mock function with given fields: key func (_m *Db) Get(key []byte) ([]byte, error) { ret := _m.Called(key) if len(ret) == 0 { panic("no return value specified for Get") } var r0 []byte var r1 error if rf, ok := ret.Get(0).(func([]byte) ([]byte, error)); ok { return rf(key) } if rf, ok := ret.Get(0).(func([]byte) []byte); ok { r0 = rf(key) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]byte) } } if rf, ok := ret.Get(1).(func([]byte) error); ok { r1 = rf(key) } else { r1 = ret.Error(1) } return r0, r1 } // Db_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' type Db_Get_Call struct { *mock.Call } // Get is a helper method to define mock.On call // - key []byte func (_e *Db_Expecter) Get(key interface{}) *Db_Get_Call { return &Db_Get_Call{Call: _e.mock.On("Get", key)} } func (_c *Db_Get_Call) Run(run func(key []byte)) *Db_Get_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].([]byte)) }) return _c } func (_c *Db_Get_Call) Return(_a0 []byte, _a1 error) *Db_Get_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *Db_Get_Call) RunAndReturn(run func([]byte) ([]byte, error)) *Db_Get_Call { _c.Call.Return(run) return _c } // Has provides a mock function with given fields: key func (_m *Db) Has(key []byte) (bool, error) { ret := _m.Called(key) if len(ret) == 0 { panic("no return value specified for Has") } var r0 bool var r1 error if rf, ok := ret.Get(0).(func([]byte) (bool, error)); ok { return rf(key) } if rf, ok := ret.Get(0).(func([]byte) bool); ok { r0 = rf(key) } else { r0 = ret.Get(0).(bool) } if rf, ok := ret.Get(1).(func([]byte) error); ok { r1 = rf(key) } else { r1 = ret.Error(1) } return r0, r1 } // Db_Has_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Has' type Db_Has_Call struct { *mock.Call } // Has is a helper method to define mock.On call // - key []byte func (_e *Db_Expecter) Has(key interface{}) *Db_Has_Call { return &Db_Has_Call{Call: _e.mock.On("Has", key)} } func (_c *Db_Has_Call) Run(run func(key []byte)) *Db_Has_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].([]byte)) }) return _c } func (_c *Db_Has_Call) Return(_a0 bool, _a1 error) *Db_Has_Call { _c.Call.Return(_a0, _a1) return _c } func (_c *Db_Has_Call) RunAndReturn(run func([]byte) (bool, error)) *Db_Has_Call { _c.Call.Return(run) return _c } // Set provides a mock function with given fields: key, value func (_m *Db) Set(key []byte, value []byte) error { ret := _m.Called(key, value) if len(ret) == 0 { panic("no return value specified for Set") } var r0 error if rf, ok := ret.Get(0).(func([]byte, []byte) error); ok { r0 = rf(key, value) } else { r0 = ret.Error(0) } return r0 } // Db_Set_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Set' type Db_Set_Call struct { *mock.Call } // Set is a helper method to define mock.On call // - key []byte // - value []byte func (_e *Db_Expecter) Set(key interface{}, value interface{}) *Db_Set_Call { return &Db_Set_Call{Call: _e.mock.On("Set", key, value)} } func (_c *Db_Set_Call) Run(run func(key []byte, value []byte)) *Db_Set_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].([]byte), args[1].([]byte)) }) return _c } func (_c *Db_Set_Call) Return(_a0 error) *Db_Set_Call { _c.Call.Return(_a0) return _c } func (_c *Db_Set_Call) RunAndReturn(run func([]byte, []byte) error) *Db_Set_Call { _c.Call.Return(run) return _c } // NewDb creates a new instance of Db. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewDb(t interface { mock.TestingT Cleanup(func()) }) *Db { mock := &Db{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) return mock } ================================================ FILE: storage/kv_store_service.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package storage import ( "context" "cosmossdk.io/core/store" storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ) var ( //nolint:gochecknoglobals // storeKey is a singleton. StoreKey = storetypes.NewKVStoreKey("beacon") _ store.KVStoreService = (*KVStoreService)(nil) ) type KVStoreService struct { Key *storetypes.KVStoreKey } func (k KVStoreService) OpenKVStore(ctx context.Context) store.KVStore { return NewKVStore(sdk.UnwrapSDKContext(ctx).KVStore(k.Key)) } // CoreKVStore is a wrapper of Core/Store kvstore interface // Remove after https://github.com/cosmos/cosmos-sdk/issues/14714 is closed. type coreKVStore struct { kvStore storetypes.KVStore } // NewKVStore returns a wrapper of Core/Store kvstore interface // Remove once store migrates to core/store kvstore interface. func NewKVStore(store storetypes.KVStore) store.KVStore { return coreKVStore{kvStore: store} } // Get returns nil iff key doesn't exist. Errors on nil key. func (store coreKVStore) Get(key []byte) ([]byte, error) { return store.kvStore.Get(key), nil } // Has checks if a key exists. Errors on nil key. func (store coreKVStore) Has(key []byte) (bool, error) { return store.kvStore.Has(key), nil } // Set sets the key. Errors on nil key or value. func (store coreKVStore) Set(key, value []byte) error { store.kvStore.Set(key, value) return nil } // Delete deletes the key. Errors on nil key. func (store coreKVStore) Delete(key []byte) error { store.kvStore.Delete(key) return nil } // Iterator iterates over a domain of keys in ascending order. End is exclusive. // Start must be less than end, or the Iterator is invalid. // Iterator must be closed by caller. // To iterate over entire domain, use store.Iterator(nil, nil) // CONTRACT: No writes may happen within a domain while an iterator exists over // it. // Exceptionally allowed for cachekv.Store, safe to write in the modules. func (store coreKVStore) Iterator(start, end []byte) (store.Iterator, error) { return store.kvStore.Iterator(start, end), nil } // ReverseIterator iterates over a domain of keys in descending order. End is // exclusive. // Start must be less than end, or the Iterator is invalid. // Iterator must be closed by caller. // CONTRACT: No writes may happen within a domain while an iterator exists over // it. // Exceptionally allowed for cachekv.Store, safe to write in the modules. func (store coreKVStore) ReverseIterator( start, end []byte, ) (store.Iterator, error) { return store.kvStore.ReverseIterator(start, end), nil } ================================================ FILE: testing/benchmarks/logger_benchmark_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package benchmarks_test import ( "bytes" "testing" "github.com/berachain/beacon-kit/log/phuslu" ) /* -------------------------------------------------------------------------- */ /* Info */ /* -------------------------------------------------------------------------- */ // Benchmark function for phuslu logger with pretty style. func BenchmarkPhusluLoggerPrettyInfo(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithPretty("info")) b.ResetTimer() for range b.N { logger.Info("This is an info message", "key1", "value1", "key2", 2) } } // Benchmark function for phuslu logger with JSON style. func BenchmarkPhusluLoggerJSONInfo(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithJSON("info")) b.ResetTimer() for range b.N { logger.Info("This is an info message", "key1", "value1", "key2", 2) } } /* -------------------------------------------------------------------------- */ /* Warn */ /* -------------------------------------------------------------------------- */ // Benchmark function for phuslu logger Warn. func BenchmarkPhusluLoggerPrettyWarn(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithPretty("warn")) b.ResetTimer() for range b.N { logger.Warn("This is a warning message", "key1", "value1", "key2", 2) } } // Benchmark function for phuslu logger with JSON style. func BenchmarkPhusluLoggerJSONWarn(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithJSON("warn")) b.ResetTimer() for range b.N { logger.Warn("This is a warning message", "key1", "value1", "key2", 2) } } /* -------------------------------------------------------------------------- */ /* Error */ /* -------------------------------------------------------------------------- */ // Benchmark function for phuslu logger Error. func BenchmarkPhusluLoggerPrettyError(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithPretty("error")) b.ResetTimer() for range b.N { logger.Error("This is an error message", "key1", "value1", "key2", 2) } } // Benchmark function for phuslu logger with JSON style. func BenchmarkPhusluLoggerJSONError(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithJSON("error")) b.ResetTimer() for range b.N { logger.Error("This is an error message", "key1", "value1", "key2", 2) } } /* -------------------------------------------------------------------------- */ /* Debug */ /* -------------------------------------------------------------------------- */ // Benchmark function for phuslu logger Debug. func BenchmarkPhusluLoggerPrettyDebug(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithPretty("debug")) b.ResetTimer() for range b.N { logger.Debug("This is a debug message", "key1", "value1", "key2", 2) } } // Benchmark function for phuslu logger with JSON style. func BenchmarkPhusluLoggerJSONDebug(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithJSON("debug")) b.ResetTimer() for range b.N { logger.Debug("This is a debug message", "key1", "value1", "key2", 2) } } func BenchmarkPhusluLoggerPrettyDebugSilent(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithPretty("info")) b.ResetTimer() for range b.N { logger.Debug("This is a debug message", "key1", "value1", "key2", 2) } } func BenchmarkPhusluLoggerJSONDebugSilent(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithJSON("info")) b.ResetTimer() for range b.N { logger.Debug("This is a debug message", "key1", "value1", "key2", 2) } } /* -------------------------------------------------------------------------- */ /* With */ /* -------------------------------------------------------------------------- */ // Benchmark function for phuslu logger With. func BenchmarkPhusluLoggerPrettyWith(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithPretty("info")) b.ResetTimer() for range b.N { newLogger := logger.With("contextKey", "contextValue") newLogger.Info("This is a contextual info message", "key1", "value1", "key2", 2) } } // Benchmark function for phuslu logger With JSON style. func BenchmarkPhusluLoggerJSONWith(b *testing.B) { logger := newPhusluLogger().WithConfig(configWithJSON("info")) b.ResetTimer() for range b.N { newLogger := logger.With("contextKey", "contextValue") newLogger.Info("This is a contextual info message", "key1", "value1", "key2", 2) } } /* -------------------------------------------------------------------------- */ /* Helpers */ /* -------------------------------------------------------------------------- */ // setup func to create a new phuslu logger with the given log level. func newPhusluLogger() *phuslu.Logger { cfg := phuslu.DefaultConfig() // dummy config l := phuslu.NewLogger( &bytes.Buffer{}, &cfg) return l } // setup func to create a phuslu logger config with pretty style. func configWithPretty(level string) *phuslu.Config { cfg := phuslu.DefaultConfig() cfg.LogLevel = level cfg.Style = phuslu.StylePretty return &cfg } // setup func to create a phuslu logger config with JSON style. func configWithJSON(level string) *phuslu.Config { cfg := phuslu.DefaultConfig() cfg.LogLevel = level cfg.Style = phuslu.StyleJSON return &cfg } ================================================ FILE: testing/e2e/.gitignore ================================================ e2e-logs/ ================================================ FILE: testing/e2e/README.md ================================================ # E2E Tests End-to-end tests for BeaconKit using [Kurtosis](https://www.kurtosis.com/), a platform for running distributed systems on Docker. Each test suite spins up a full beacon-kit network inside a Kurtosis enclave, runs tests against it, and tears it down automatically. ## Directory Structure ``` testing/e2e/ config/ # Network configuration structs and defaults config.go # E2ETestConfig, NetworkConfiguration, NodeSet, etc. defaults.go # DefaultE2ETestConfig(), suite/ # Shared test framework (Kurtosis orchestration, lifecycle) suite.go # KurtosisE2ESuite struct and accessors setup.go # SetupSuite, TearDownSuite, FundAccounts, WaitForFinalizedBlockNumber options.go # Functional options logs.go # Log fetching, dumping on failure constants.go # Ether, gas limits, timeouts errors.go # Shared error variables types/ # Client wrappers (ConsensusClient, RPCClient, EthAccount, etc.) standard/ # Standard e2e test suite (package standard_test) setup_test.go # BeaconKitE2ESuite struct + entry point *_test.go # One file per feature (blobs, beacon API, staking, ...) ``` ## How It Works ### Suite Lifecycle Each test suite (`standard/`) defines a struct that embeds `suite.KurtosisE2ESuite` and uses [testify suites](https://pkg.go.dev/github.com/stretchr/testify/suite) for lifecycle management. 1. **SetupSuite** (runs once before all tests in a suite): - Loads configuration from `config/defaults.go` (or applies custom options) - Connects to the local Kurtosis engine - Destroys any leftover `e2e-test-enclave` from a previous run - Creates a fresh Kurtosis enclave named `e2e-test-enclave` - Runs the `kurtosis/` Starlark package to spin up validators, full nodes, seed nodes, and EL clients - Sets up consensus clients and a JSON-RPC connection to the execution layer - Waits for the network to reach a minimum finalized block number - Funds test accounts from the genesis account 2. **Test methods** run against the live network (e.g., `TestBasicStartup`, `Test4844Live`). 3. **TearDownSuite** (runs once after all tests): - If any test failed, dumps all service logs to `e2e-logs//` (one `.log` file per service) - Stops all consensus clients - Destroys the Kurtosis enclave ### Enclave = One Suite Each test suite gets its own Kurtosis enclave. The standard suite uses `DefaultE2ETestConfig()` (5 bera-reth validators. 5 bera-reth full nodes, 1 bera-reth seed node). ### Build Tags All e2e test files use `//go:build e2e`. This prevents them from running during `go test ./...`. You must explicitly pass `-tags e2e` (the Makefile targets handle this). ### Log Collection on Failure When any test in a suite fails, `TearDownSuite` automatically calls `DumpAllServiceLogs()`, which fetches up to 100,000 log lines from every service in the enclave and writes them to: ``` e2e-logs//.log ``` This directory is git-ignored. Logs from previous runs are overwritten. ## Prerequisites - **Docker** running locally - **Kurtosis CLI** installed ([instructions](https://docs.kurtosis.com/install)) with the engine started (`kurtosis engine start`) - **Go 1.26.2+** ## Running Tests ### With Docker Build (builds `beacond:kurtosis-local` image first) ```bash make test-e2e # Run ALL e2e tests (standard, sequentially) make test-e2e-standard # Run only standard suite make test-e2e-4844 # Run only blob tests make test-e2e-deposits # Run only deposit tests ``` ### Without Docker Build (image must already exist) ```bash make test-e2e-standard-no-build ``` ### Running a Specific Test ```bash go test -timeout 0 -tags e2e,bls12381,test ./testing/e2e/standard/. -v -testify.m TestBasicStartup ``` ## Configuration Network topology is defined in `config/defaults.go`. Key settings: - **Validators**: 5 nodes (5 bera-reth) by default - **Full nodes**: 5 nodes (5 bera-reth) by default - **Seed nodes**: 1 node (1 bera-reth) by default - **Chain ID**: 80087 (devnet). To modify the chain spec, see `config/spec/devnet.go`. - **EL images**: Configured in `defaultExecutionSettings()` (bera-reth) - **CL image**: `beacond:kurtosis-local` (built from local source) To add a new test suite configuration, create a function in `defaults.go` that returns `*E2ETestConfig` and wire it via a functional option in `suite/options.go`. ## Adding New Tests 1. Pick the appropriate suite directory (`standard/`). 2. Create a new `*_test.go` file with the `//go:build e2e` tag and the matching package name (`standard_test`). 3. Add test methods on the suite struct (e.g., `func (s *BeaconKitE2ESuite) TestMyFeature() { ... }`). 4. Use `s.ExecutionClients()` for EL queries, `s.ConsensusClients()` for CL queries, `s.GenesisAccount()` / `s.TestAccounts()` for funded accounts. ## Debugging 1. Check Kurtosis engine status: ```bash kurtosis engine status kurtosis engine restart ``` 2. Inspect a running enclave: ```bash kurtosis enclave inspect e2e-test-enclave ``` 3. If tests fail, check `e2e-logs/` for service logs. 4. If the enclave wasn't cleaned up (e.g., test was killed), destroy it manually: ```bash kurtosis enclave rm -f e2e-test-enclave ``` ================================================ FILE: testing/e2e/config/config.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //nolint:tagliatelle // starlark uses snek case. package config import ( "github.com/berachain/beacon-kit/primitives/encoding/json" ) // E2ETestConfig defines the configuration for end-to-end tests, including any // additional services and validators involved. type E2ETestConfig struct { // NetworkConfiguration specifies the configuration for the network. NetworkConfiguration NetworkConfiguration `json:"network_configuration"` // NodeSettings specifies the configuration for the nodes in the test. NodeSettings NodeSettings `json:"node_settings"` // AdditionalServices specifies any extra services that should be included // in the test environment. AdditionalServices []AdditionalService `json:"additional_services"` } type NetworkConfiguration struct { // Validators lists the configurations for each validator in the test. Validators NodeSet `json:"validators"` // FullNodes specifies the number of full nodes to include in the test. FullNodes NodeSet `json:"full_nodes"` // SeedNodes specifies the number of seed nodes to include in the test. SeedNodes NodeSet `json:"seed_nodes"` } // NodeSet holds nodes that have a distinct role in the network. type NodeSet struct { // Type is the type of node set. Type string `json:"type"` // Nodes is a list of nodes in the set. Nodes []Node `json:"nodes"` } // Node holds the configuration for a single node in the test, // including client images and types. type Node struct { // ElType denotes the type of execution layer client (e.g., reth). ElType string `json:"el_type"` // Replicas specifies the number of replicas to use for the client. Replicas int `json:"replicas"` // KZGImpl specifies the KZG implementation to use for the client. KZGImpl string `json:"kzg_impl"` } // NodeSettings holds the configuration for a single node in the test, // including client images and types. type NodeSettings struct { // ConsensusSettings holds the configuration for the consensus layer // clients. ConsensusSettings ConsensusSettings `json:"consensus_settings"` // ExecutionSettings holds the configuration for the execution layer // clients. ExecutionSettings ExecutionSettings `json:"execution_settings"` } // ExecutionSettings holds the configuration for the execution layer // clients. type ExecutionSettings struct { // Specs holds the node specs for all nodes in the execution layer. Specs NodeSpecs `json:"specs"` // Images specifies the images available for the execution layer. Images map[string]string `json:"images"` } // ConsensusSettings holds the configuration for the consensus layer // clients. type ConsensusSettings struct { // Specs holds the node specs for all nodes in the consensus layer. Specs NodeSpecs `json:"specs"` // Images specifies the images available for the consensus layer. Images map[string]string `json:"images"` // Config specifies the config.toml edits for the consensus layer nodes. Config ConsensusConfig `json:"config"` // AppConfig specifies the app.toml edits for the consensus layer nodes. AppConfig AppConfig `json:"app"` } // ConsensusConfig holds the configuration for the consensus layer. type ConsensusConfig struct { // TimeoutPropose specifies the timeout for proposing a block. TimeoutPropose string `json:"timeout_propose"` // TimeoutPrevote specifies the timeout for prevoting on a block. TimeoutPrevote string `json:"timeout_prevote"` // TimeoutPrecommit specifies the timeout for precommiting on a block. TimeoutPrecommit string `json:"timeout_precommit"` // MaxNumInboundPeers specifies the maximum number of inbound peers. MaxNumInboundPeers int `json:"max_num_inbound_peers"` // MaxNumOutboundPeers specifies the maximum number of outbound peers. MaxNumOutboundPeers int `json:"max_num_outbound_peers"` } // AppConfig holds the configuration for the app layer. type AppConfig struct { // PayloadTimeout specifies the timeout for the payload. PayloadTimeout string `json:"payload_timeout"` } // NodeSpecs holds the node specs for all nodes in a single layer. type NodeSpecs struct { // MinCPU specifies the minimum number of CPUs to use for all nodes in the // layer. MinCPU int `json:"min_cpu"` // MaxCPU specifies the maximum number of CPUs to use for all nodes in the // layer. MaxCPU int `json:"max_cpu"` // MinMemory specifies the minimum amount of memory to use for all nodes in // the layer. MinMemory int `json:"min_memory"` // MaxMemory specifies the maximum amount of memory to use for all nodes in // the layer. MaxMemory int `json:"max_memory"` } // AdditionalService holds the configuration for an additional service // to be included in the test. type AdditionalService struct { // Name specifies the name of the additional service. Name string `json:"name"` // Replicas specifies the number of replicas to use for the service. Replicas int `json:"replicas"` } // MustMarshalJSON marshals the E2ETestConfig to JSON, panicking if an error. func (c *E2ETestConfig) MustMarshalJSON() string { jsonBytes, err := json.Marshal(c) if err != nil { panic(err) } return string(jsonBytes) } ================================================ FILE: testing/e2e/config/defaults.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package config import ( "fmt" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/payload/builder" ) const ( NumFullNodes = 5 NumValidators = 5 consensusClientFmt = "cl-validator-beaconkit-%d" executionClientFmt = "el-full-reth-%d" ) func ValidatorConsensusClientName(i int) string { return fmt.Sprintf(consensusClientFmt, i) } func FullNodeExecutionClientName(i int) string { return fmt.Sprintf(executionClientFmt, i) } // DefaultE2ETestConfig provides a default configuration for end-to-end tests, // pre-populating with a standard set of validators and no additional // services. func DefaultE2ETestConfig() *E2ETestConfig { return &E2ETestConfig{ NetworkConfiguration: defaultNetworkConfiguration(), NodeSettings: defaultNodeSettings(), AdditionalServices: defaultAdditionalServices(), } } func defaultNetworkConfiguration() NetworkConfiguration { return NetworkConfiguration{ Validators: defaultValidators(), FullNodes: defaultFullNodes(), SeedNodes: defaultSeedNodes(), } } func defaultValidators() NodeSet { return NodeSet{ Type: "validator", Nodes: []Node{ { ElType: "reth", Replicas: 5, //nolint:mnd // we want 5 replicas here KZGImpl: "crate-crypto/go-kzg-4844", }, }, } } func defaultFullNodes() NodeSet { return NodeSet{ Type: "full", Nodes: []Node{ { ElType: "reth", Replicas: 5, //nolint:mnd // we want 5 replicas here KZGImpl: "crate-crypto/go-kzg-4844", }, }, } } func defaultSeedNodes() NodeSet { return NodeSet{ Type: "seed", Nodes: []Node{ { ElType: "reth", Replicas: 1, KZGImpl: "crate-crypto/go-kzg-4844", }, }, } } func defaultNodeSettings() NodeSettings { return NodeSettings{ ExecutionSettings: defaultExecutionSettings(), ConsensusSettings: defaultConsensusSettings(), } } func defaultExecutionSettings() ExecutionSettings { return ExecutionSettings{ Specs: NodeSpecs{ MinCPU: 0, MaxCPU: 0, MinMemory: 0, MaxMemory: 2048, //nolint:mnd // 2 GB }, Images: map[string]string{ "reth": "ghcr.io/berachain/bera-reth:nightly", }, } } func defaultConsensusSettings() ConsensusSettings { var ( builderCfg = builder.DefaultConfig() defaultCfg = cometbft.DefaultConfig() consensus = defaultCfg.Consensus p2p = defaultCfg.P2P ) return ConsensusSettings{ Specs: NodeSpecs{ MinCPU: 0, MaxCPU: 2000, //nolint:mnd // 2 vCPUs MinMemory: 0, MaxMemory: 2048, //nolint:mnd // 2 GB }, Images: map[string]string{ "beaconkit": "beacond:kurtosis-local", }, Config: ConsensusConfig{ TimeoutPropose: consensus.TimeoutPropose.String(), TimeoutPrevote: consensus.TimeoutPrevote.String(), TimeoutPrecommit: consensus.TimeoutPrecommit.String(), MaxNumInboundPeers: p2p.MaxNumInboundPeers, MaxNumOutboundPeers: p2p.MaxNumOutboundPeers, }, AppConfig: AppConfig{ PayloadTimeout: builderCfg.PayloadTimeout.String(), }, } } func defaultAdditionalServices() []AdditionalService { return []AdditionalService{} } ================================================ FILE: testing/e2e/standard/beacon_api_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build e2e package standard_test import ( "encoding/json" "errors" "fmt" "io" "net" "net/http" "strings" "time" beaconapi "github.com/attestantio/go-eth2-client/api" apiv1 "github.com/attestantio/go-eth2-client/api/v1" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/berachain/beacon-kit/config/spec" beacontypes "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/testing/e2e/config" "github.com/berachain/beacon-kit/testing/e2e/suite/types" "github.com/ethereum/go-ethereum/common" ) const localHost = "localhost" // BeaconHTTPClient wraps http.Client with baseURL. // This is needed to change the default baseURL of the http.Client. type BeaconHTTPClient struct { *http.Client baseURL string } // Get overrides http.Client.Get to use baseURL func (c *BeaconHTTPClient) Get(path string) (*http.Response, error) { return c.Client.Get(c.baseURL + path) } // initHTTPBeaconTest initializes the http client for the beacon node api. // It gets the public ports from the consensus client and creates a http client with the baseURL. // This is needed where we want to test the node-api directly as // some of the methods are not present in go-eth2-client library. func (s *BeaconKitE2ESuite) initHTTPBeaconTest() *BeaconHTTPClient { // Initialize consensus client to get public ports. ports := s.initBeaconTest().GetPublicPorts() // As kurtosis assigns public port randomly, we need to get the port from the consensus client. // Get node-api port and format it. portStr := ports["node-api"].String() portNum := strings.Replace(portStr, "/0", "", 1) hostPort := net.JoinHostPort(localHost, portNum) // Create client with baseURL return &BeaconHTTPClient{ Client: &http.Client{ Timeout: time.Second * 10, }, baseURL: "http://" + hostPort, } } // initBeaconTest initializes the any tests for the beacon node api. func (s *BeaconKitE2ESuite) initBeaconTest() *types.ConsensusClient { // Wait for execution block 5. err := s.WaitForFinalizedBlockNumber(5) s.Require().NoError(err) // Get the consensus client. client := s.ConsensusClients(0) s.Require().NotNil(client) return client } // TestBeaconStateRoot tests the beacon node api for beacon state root. func (s *BeaconKitE2ESuite) TestBeaconStateRoot() { client := s.initBeaconTest() // Ensure the state root is not nil. stateRootResp, err := client.BeaconStateRoot( s.Ctx(), &beaconapi.BeaconStateRootOpts{ State: utils.StateIDHead, }, ) s.Require().NoError(err) s.Require().NotEmpty(stateRootResp) s.Require().False(stateRootResp.Data.IsZero()) } // TestBeaconValidatorsWithIndices tests the beacon node api for beacon validators with indices. func (s *BeaconKitE2ESuite) TestBeaconValidatorsWithIndices() { client := s.initBeaconTest() indices := []phase0.ValidatorIndex{0} validatorsResp, err := client.Validators( s.Ctx(), &beaconapi.ValidatorsOpts{ State: utils.StateIDHead, Indices: indices, }, ) s.Require().NoError(err) s.Require().NotNil(validatorsResp) validatorData := validatorsResp.Data s.Require().NotNil(validatorData, "Validator data should not be nil") s.Require(). Len(validatorData, len(indices), "Number of validator responses should match number of requested indices") validator := validatorData[0] s.Require().NotNil(validator, "Validator should not be nil") s.Require().Equal(phase0.ValidatorIndex(0), validator.Index, "Should be validator index 0") s.Require(). NotEmpty(validator.Validator.PublicKey, "Validator public key should not be empty") s.Require(). Len(validator.Validator.PublicKey, 48, "Validator public key should be 48 bytes long") s.Require(). NotEmpty(validator.Validator.WithdrawalCredentials, "Withdrawal credentials should not be empty") s.Require(). Len(validator.Validator.WithdrawalCredentials, 32, "Withdrawal credentials should be 32 bytes long") s.Require(). True(validator.Validator.EffectiveBalance > 0, "Effective balance should be positive") s.Require(). True(validator.Validator.EffectiveBalance <= 32e9, "Effective balance should not exceed 32 ETH") s.Require(). False(validator.Validator.Slashed, "Slashed status should not be true") s.Require(). True(validator.Validator.ActivationEpoch >= validator.Validator.ActivationEligibilityEpoch, "Activation epoch should be greater than or equal to activation eligibility epoch") s.Require(). True(validator.Validator.WithdrawableEpoch >= validator.Validator.ExitEpoch, "Withdrawable epoch should be greater than or equal to exit epoch") s.Require(). NotEmpty(validator.Status, "Validator status should not be empty") s.Require(). True(validator.Balance > 0, "Validator balance should be positive") s.Require(). True(validator.Balance <= 32e9, "Validator balance should not exceed 32 ETH") } // TestValidatorsEmptyIndicesAndStatuses tests that querying validators with empty indices and empty statuses returns all validators. // Empty indices and statuses is same as not populating the indices and statuses. Basically, querying by State. func (s *BeaconKitE2ESuite) TestValidatorsEmptyIndicesAndStatuses() { client := s.initBeaconTest() // Query validators with empty indices and empty statuses emptyIndices := []phase0.ValidatorIndex{} emptyStatuses := []apiv1.ValidatorState{} validatorsResp, err := client.Validators( s.Ctx(), &beaconapi.ValidatorsOpts{ State: utils.StateIDHead, Indices: emptyIndices, ValidatorStates: emptyStatuses, }, ) s.Require().NoError(err) s.Require().NotNil(validatorsResp) // Verify we got all validators validatorData := validatorsResp.Data s.Require().NotNil(validatorData, "Validator data should not be nil") s.Require().Equal(config.NumValidators, len(validatorData), "Should return all validators when using empty statuses and empty indices") // Verify each validator has required fields for _, validator := range validatorData { s.Require().NotNil(validator, "Validator should not be nil") s.Require().NotEmpty(validator.Validator.PublicKey, "Validator public key should not be empty") s.Require().Len(validator.Validator.PublicKey, 48, "Validator public key should be 48 bytes long") s.Require().NotEmpty(validator.Validator.WithdrawalCredentials, "Withdrawal credentials should not be empty") s.Require().Len(validator.Validator.WithdrawalCredentials, 32, "Withdrawal credentials should be 32 bytes long") s.Require().True(validator.Validator.EffectiveBalance > 0, "Effective balance should be positive") } } // TestValidatorsWithMultipleIndices tests querying multiple specific validator indices. func (s *BeaconKitE2ESuite) TestValidatorsWithMultipleIndices() { client := s.initBeaconTest() indices := []phase0.ValidatorIndex{0, 1, 2} validatorsResp, err := client.Validators(s.Ctx(), &beaconapi.ValidatorsOpts{ State: utils.StateIDHead, Indices: indices, }) s.Require().NoError(err) s.Require().NotNil(validatorsResp) s.Require().Len(validatorsResp.Data, len(indices)) } // TestValidatorsWithInvalidIndex tests querying a non-existent validator index // This should return an empty list of validators. func (s *BeaconKitE2ESuite) TestValidatorsWithInvalidIndex() { client := s.initBeaconTest() indices := []phase0.ValidatorIndex{999999} // Invalid index validatorsResp, err := client.Validators(s.Ctx(), &beaconapi.ValidatorsOpts{ State: utils.StateIDHead, Indices: indices, }) s.Require().NoError(err) s.Require().NotNil(validatorsResp) // No validators returned s.Require().Len(validatorsResp.Data, 0) } // TestValidatorsWithSpecificStatus tests filtering validators by status. func (s *BeaconKitE2ESuite) TestValidatorsWithSpecificStatus() { client := s.initBeaconTest() validatorsResp, err := client.Validators(s.Ctx(), &beaconapi.ValidatorsOpts{ State: utils.StateIDHead, ValidatorStates: []apiv1.ValidatorState{apiv1.ValidatorStateActiveOngoing}, }) s.Require().NoError(err) s.Require().NotNil(validatorsResp) // Verify all returned validators have the requested status for _, validator := range validatorsResp.Data { s.Require().Equal(apiv1.ValidatorStateActiveOngoing, validator.Status) } } // TestValidatorBalances tests querying validator balances. func (s *BeaconKitE2ESuite) TestValidatorBalances() { client := s.initBeaconTest() balancesResp, err := client.ValidatorBalances(s.Ctx(), &beaconapi.ValidatorBalancesOpts{ State: utils.StateIDHead, }) s.Require().NoError(err) s.Require().NotNil(balancesResp) // Verify the response is not empty s.Require().NotNil(balancesResp.Data) s.Require().NotEmpty(balancesResp.Data) balanceMap := balancesResp.Data for _, balance := range balanceMap { s.Require().True(balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True(balance <= 4e12, "Validator balance should not exceed 4e12 gwei (4000 BERA)") } } // TestValidatorBalancesWithSpecificIndices tests querying validator balances with specific indices. func (s *BeaconKitE2ESuite) TestValidatorBalancesWithSpecificIndices() { client := s.initBeaconTest() indices := []phase0.ValidatorIndex{0} balancesResp, err := client.ValidatorBalances(s.Ctx(), &beaconapi.ValidatorBalancesOpts{ State: utils.StateIDHead, Indices: indices, }) s.Require().NoError(err) s.Require().NotNil(balancesResp) // Verify the response is not empty s.Require().NotNil(balancesResp.Data) s.Require().Len(balancesResp.Data, len(indices)) // Verify balance data for index, balance := range balancesResp.Data { s.Require().NotNil(balance) s.Require().Contains(indices, index) s.Require().True(balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True(balance <= 4e12, "Validator balance should not exceed 4000 BERA") } } // TestValidatorBalancesMultipleIndices tests querying balances for multiple validator indices. func (s *BeaconKitE2ESuite) TestValidatorBalancesMultipleIndices() { client := s.initBeaconTest() indices := []phase0.ValidatorIndex{0, 1, 2} balancesResp, err := client.ValidatorBalances( s.Ctx(), &beaconapi.ValidatorBalancesOpts{ State: utils.StateIDHead, Indices: indices, }, ) s.Require().NoError(err) s.Require().NotNil(balancesResp) s.Require().Len(balancesResp.Data, len(indices)) // Verify all requested indices are present returnedIndices := make(map[phase0.ValidatorIndex]struct{}) for index, balance := range balancesResp.Data { returnedIndices[index] = struct{}{} s.Require().True(balance > 0) // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True(balance <= 4e12, "Validator balance should not exceed 4000 BERA") } for _, idx := range indices { _, exists := returnedIndices[idx] s.Require().True(exists, "Expected validator index not found in response") } } // TestValidatorBalancesWithInvalidIndex tests querying validator balances with an invalid index. func (s *BeaconKitE2ESuite) TestValidatorBalancesWithInvalidIndex() { client := s.initBeaconTest() indices := []phase0.ValidatorIndex{999999} // Invalid index balancesResp, err := client.ValidatorBalances(s.Ctx(), &beaconapi.ValidatorBalancesOpts{ State: utils.StateIDHead, Indices: indices, }) s.Require().NoError(err) s.Require().NotNil(balancesResp) // Should return an empty list of balances s.Require().Len(balancesResp.Data, 0) } // TestValidatorBalancesWithPubkey tests querying validator balances using a public key. func (s *BeaconKitE2ESuite) TestValidatorBalancesWithPubkey() { client := s.initBeaconTest() // First call validators to get the validator public key validatorsResp, err := client.Validators(s.Ctx(), &beaconapi.ValidatorsOpts{ State: utils.StateIDHead, }) s.Require().NoError(err) s.Require().NotNil(validatorsResp) validator := validatorsResp.Data[0] s.Require().NotNil(validator) pubkey := validator.Validator.PublicKey balancesResp, err := client.ValidatorBalances(s.Ctx(), &beaconapi.ValidatorBalancesOpts{ State: utils.StateIDHead, Indices: []phase0.ValidatorIndex{}, PubKeys: []phase0.BLSPubKey{pubkey}, }) s.Require().NoError(err) s.Require().NotNil(balancesResp) s.Require().Len(balancesResp.Data, 1) // Verify balance data for _, balance := range balancesResp.Data { s.Require().NotNil(balance) s.Require().True(balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True(balance <= 4e12, "Validator balance should not exceed 4000 BERA") } } // TestValidatorBalancesWithInvalidPubkey tests querying validator balances using a public key. func (s *BeaconKitE2ESuite) TestValidatorBalancesWithInvalidPubkey() { client := s.initBeaconTest() // Example validator pubkey (48 bytes with 0x prefix) notFoundPubkey := "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a" balancesResp, err := client.ValidatorBalances(s.Ctx(), &beaconapi.ValidatorBalancesOpts{ State: utils.StateIDHead, Indices: []phase0.ValidatorIndex{}, PubKeys: []phase0.BLSPubKey{phase0.BLSPubKey(common.FromHex(notFoundPubkey))}, }) s.Require().NoError(err) s.Require().NotNil(balancesResp) // Should return an empty list of balances s.Require().Len(balancesResp.Data, 0) } // Helper functions // decodeResponse is a generic function that decodes an HTTP response into the specified type T. func decodeResponse[T any](resp *http.Response) (T, error) { var result T if resp == nil { return result, errors.New("nil response") } defer resp.Body.Close() bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return result, err } // First decode into GenericResponse. var genericResp beacontypes.GenericResponse if err = json.Unmarshal(bodyBytes, &genericResp); err != nil { return result, err } // Convert the data field to JSON. dataBytes, err := json.Marshal(genericResp.Data) if err != nil { return result, err } // Unmarshal into the target type. if err = json.Unmarshal(dataBytes, &result); err != nil { return result, err } return result, nil } // decodeValidatorResponse decodes a single validator response. func (s *BeaconKitE2ESuite) decodeValidatorResponse(resp *http.Response) (*beacontypes.ValidatorData, error) { validator, err := decodeResponse[beacontypes.ValidatorData](resp) if err != nil { return nil, err } return &validator, nil } // getStateValidator gets the state validator by index or pubkey. func (s *BeaconKitE2ESuite) getStateValidator(stateID, validatorID string) (*http.Response, error) { client := s.initHTTPBeaconTest() resp, err := client.Get(fmt.Sprintf("/eth/v1/beacon/states/%s/validators/%s", stateID, validatorID)) if err != nil { return nil, fmt.Errorf("failed to get validator: %w", err) } if resp == nil { return nil, errors.New("received nil response") } return resp, nil } // TestGetStateValidatorByIndex tests getting the state validator by index. func (s *BeaconKitE2ESuite) TestGetStateValidatorByIndex() { resp, err := s.getStateValidator(utils.StateIDHead, "0") s.Require().NoError(err) s.Require().NotNil(resp, "response should not be nil") s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() validatorResp, err := s.decodeValidatorResponse(resp) s.Require().NoError(err) s.Require().NotNil(validatorResp, "validator response should not be nil") s.Require().Equal(uint64(0), validatorResp.Index) s.Require().Equal("active_ongoing", validatorResp.Status) } // TestGetStateValidatorBySlotAndIndex tests getting the state validator by slot and index. func (s *BeaconKitE2ESuite) TestGetStateValidatorBySlotAndIndex() { // Here the stateID is a slot number which is 10. resp, err := s.getStateValidator("10", "0") s.Require().NoError(err) s.Require().NotNil(resp, "response should not be nil") s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() validatorResp, err := s.decodeValidatorResponse(resp) s.Require().NoError(err) s.Require().NotNil(validatorResp, "validator response should not be nil") s.Require().Equal(uint64(0), validatorResp.Index) s.Require().Equal("active_ongoing", validatorResp.Status) } // TestGetStateValidatorByPubkey tests getting the state validator by pubkey. func (s *BeaconKitE2ESuite) TestGetStateValidatorByPubkey() { // First call validators to get the validator public key resp, err := s.getStateValidator(utils.StateIDHead, "0") s.Require().NoError(err) s.Require().NotNil(resp, "response should not be nil") s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() validatorResp, err := s.decodeValidatorResponse(resp) s.Require().NoError(err) s.Require().NotNil(validatorResp, "validator response should not be nil") // Retrieve the public key. pubkey := validatorResp.Validator.PublicKey // Actual test starts here. resp, err = s.getStateValidator(utils.StateIDHead, pubkey) s.Require().NoError(err) s.Require().NotNil(resp, "response should not be nil") s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() validatorResp, errInDecode := s.decodeValidatorResponse(resp) s.Require().NoError(errInDecode) s.Require().NotNil(validatorResp, "validator response should not be nil") s.Require().Equal("active_ongoing", validatorResp.Status) } // TestGetStateValidatorInvalidID tests getting the state validator with an invalid id. func (s *BeaconKitE2ESuite) TestGetStateValidatorInvalidID() { resp, err := s.getStateValidator(utils.StateIDHead, "invalid_id") s.Require().NoError(err) s.Require().NotNil(resp, "response should not be nil") s.Require().Equal(http.StatusBadRequest, resp.StatusCode) defer resp.Body.Close() } // getValidatorBalances gets the validator balances for the given stateID and optional ids. func (s *BeaconKitE2ESuite) getValidatorBalances(stateID string, ids ...string) (*http.Response, error) { client := s.initHTTPBeaconTest() url := fmt.Sprintf("/eth/v1/beacon/states/%s/validator_balances", stateID) // Add ID parameters if provided if len(ids) > 0 { queryParams := make([]string, 0, len(ids)) for _, id := range ids { queryParams = append(queryParams, "id="+id) } url = url + "?" + strings.Join(queryParams, "&") } resp, err := client.Get(url) if err != nil { return nil, fmt.Errorf("failed to get validator balances: %w", err) } if resp == nil { return nil, errors.New("received nil response") } return resp, nil } // decodeValidatorBalancesResponse decodes a response containing validator balances. func (s *BeaconKitE2ESuite) decodeValidatorBalancesResponse(resp *http.Response) (*[]beacontypes.ValidatorBalanceData, error) { balances, err := decodeResponse[[]beacontypes.ValidatorBalanceData](resp) if err != nil { return nil, err } return &balances, nil } // TestGetValidatorBalances tests querying validator balances for state head. func (s *BeaconKitE2ESuite) TestGetValidatorBalances() { resp, err := s.getValidatorBalances(utils.StateIDHead) s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() balancesResp, err := s.decodeValidatorBalancesResponse(resp) s.Require().NoError(err) s.Require().NotNil(balancesResp, "balances response should not be nil") s.Require().NotEmpty(balancesResp, "balances response should not be empty") for _, balance := range *balancesResp { s.Require().True(balance.Balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True(balance.Balance <= 4e12, "Validator balance should not exceed 4000 BERA") } } // TestGetValidatorBalancesWithSpecificID tests querying validator balances with specific ID. func (s *BeaconKitE2ESuite) TestGetValidatorBalancesWithSpecificID() { resp, err := s.getValidatorBalances(utils.StateIDHead, "0") s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() balancesResp, err := s.decodeValidatorBalancesResponse(resp) s.Require().NoError(err) s.Require().NotNil(balancesResp, "balances response should not be nil") s.Require().Len(*balancesResp, 1) s.Require().True((*balancesResp)[0].Balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True((*balancesResp)[0].Balance <= 4e12, "Validator balance should not exceed 4000 BERA") } // TestGetValidatorBalancesWithMultipleIDs tests querying validator balances with multiple IDs. func (s *BeaconKitE2ESuite) TestGetValidatorBalancesWithMultipleIDs() { resp, err := s.getValidatorBalances(utils.StateIDHead, "0", "1") s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() balancesResp, err := s.decodeValidatorBalancesResponse(resp) s.Require().NoError(err) s.Require().NotNil(balancesResp, "balances response should not be nil") s.Require().NotEmpty(balancesResp, "balances response should not be empty") // The response should contain 2 validator balances. s.Require().Len(*balancesResp, 2) for _, balance := range *balancesResp { s.Require().True(balance.Balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True(balance.Balance <= 4e12, "Validator balance should not exceed 4000 BERA") } } // TestGetValidatorBalancesWithInvalidID tests querying validator balances with invalid ID. func (s *BeaconKitE2ESuite) TestGetValidatorBalancesWithInvalidID() { resp, err := s.getValidatorBalances(utils.StateIDHead, "invalid_id") s.Require().NoError(err) s.Require().Equal(http.StatusBadRequest, resp.StatusCode) defer resp.Body.Close() balancesResp, err := s.decodeValidatorBalancesResponse(resp) s.Require().NoError(err) s.Require().NotNil(balancesResp, "balances response should not be nil") s.Require().Len(*balancesResp, 0) } // TestGetValidatorBalancesWithNonExistentIndex tests querying validator balances with non-existent index. func (s *BeaconKitE2ESuite) TestGetValidatorBalancesWithNonExistentIndex() { resp, err := s.getValidatorBalances(utils.StateIDHead, "99999") s.Require().NoError(err) // If an index does not match any validator, no balance will be returned but this will not cause an error. // The response should be 200 OK with empty data. s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() balancesResp, err := s.decodeValidatorBalancesResponse(resp) s.Require().NoError(err) s.Require().NotNil(balancesResp, "balances response should not be nil") s.Require().Len(*balancesResp, 0) } // TestGetValidatorBalancesWithPublicKey tests querying validator balances with public key. func (s *BeaconKitE2ESuite) TestGetValidatorBalancesWithPublicKey() { client := s.initBeaconTest() // First call validators to get the validator public key validatorsResp, err := client.Validators(s.Ctx(), &beaconapi.ValidatorsOpts{ State: utils.StateIDHead, }) s.Require().NoError(err) s.Require().NotNil(validatorsResp) validator := validatorsResp.Data[0] s.Require().NotNil(validator) pubkey := validator.Validator.PublicKey resp, err := s.getValidatorBalances(utils.StateIDHead, pubkey.String()) s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() balancesResp, err := s.decodeValidatorBalancesResponse(resp) s.Require().NoError(err) s.Require().NotNil(balancesResp, "balances response should not be nil") s.Require().NotEmpty(balancesResp, "balances response should not be empty") s.Require().Len(*balancesResp, 1) s.Require().True((*balancesResp)[0].Balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True((*balancesResp)[0].Balance <= 4e12, "Validator balance should not exceed 4000 BERA") } // TestGetValidatorBalancesWithInvalidPublicKey tests querying validator balances with invalid public key. func (s *BeaconKitE2ESuite) TestGetValidatorBalancesWithInvalidPublicKey() { // Example validator pubkey (48 bytes with 0x prefix) notFoundPubkey := "0x93247f2209abcacf57b75a51dafae777f9dd38bc7053d1af526f220a7489a6d3a2753e5f3e8b1cfe39b56f43611df74a" resp, err := s.getValidatorBalances(utils.StateIDHead, notFoundPubkey) s.Require().NoError(err) // If public key does not match any validator, no balance will be returned but this will not cause an error. // The response should be 200 OK with empty data. s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() balancesResp, err := s.decodeValidatorBalancesResponse(resp) s.Require().NoError(err) s.Require().NotNil(balancesResp, "balances response should not be nil") s.Require().Len(*balancesResp, 0) } // TestGetValidatorBalancesForGenesis tests querying validator balances for state genesis. func (s *BeaconKitE2ESuite) TestGetValidatorBalancesForGenesis() { resp, err := s.getValidatorBalances(utils.StateIDGenesis) s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() balancesResp, err := s.decodeValidatorBalancesResponse(resp) s.Require().NoError(err) s.Require().NotNil(balancesResp, "balances response should not be nil") s.Require().NotEmpty(balancesResp, "balances response should not be empty") for _, balance := range *balancesResp { s.Require().True(balance.Balance > 0, "Validator balance should be positive") // At genesis, the validator balance is 32 BERA. // 32e9 Gwei = 32 * 10^9 Gwei = 32,000,000,000 Gwei = 32 BERA s.Require().True(balance.Balance <= 32e9, "Validator balance should not exceed 32 BERA") } } // getValidator gets the validator with the given stateID and optional options. func (s *BeaconKitE2ESuite) getValidator(stateID string, options ...map[string]string) (*http.Response, error) { client := s.initHTTPBeaconTest() url := fmt.Sprintf("/eth/v1/beacon/states/%s/validators", stateID) // Process options if provided if len(options) > 0 { queryParams := []string{} // Extract options from the map for _, opts := range options { for key, value := range opts { queryParams = append(queryParams, fmt.Sprintf("%s=%s", key, value)) } } // Add query parameters to URL if any exist if len(queryParams) > 0 { url = url + "?" + strings.Join(queryParams, "&") } } resp, err := client.Get(url) if err != nil { return nil, fmt.Errorf("failed to get validator: %w", err) } if resp == nil { return nil, errors.New("received nil response") } return resp, nil } // decodeValidatorsResponse decodes a response containing multiple validators. func (s *BeaconKitE2ESuite) decodeValidatorsResponse(resp *http.Response) (*[]beacontypes.ValidatorData, error) { validators, err := decodeResponse[[]beacontypes.ValidatorData](resp) if err != nil { return nil, err } return &validators, nil } // TestGetValidatorsWithStateHead tests querying validators with state head. func (s *BeaconKitE2ESuite) TestGetValidatorsWithStateHead() { resp, err := s.getValidator(utils.StateIDHead) s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() validators, err := s.decodeValidatorsResponse(resp) s.Require().NoError(err) s.Require().NotNil(validators) for _, validator := range *validators { s.Require().True(validator.Status == "active_ongoing") s.Require().True(validator.Balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True(validator.Balance <= 4e12, "Validator balance should not exceed 4000 BERA") } } // TestGetValidatorsWithID tests querying validators with ID parameter. func (s *BeaconKitE2ESuite) TestGetValidatorsWithID() { resp, err := s.getValidator(utils.StateIDHead, map[string]string{ "id": "0", }) s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() validators, err := s.decodeValidatorsResponse(resp) s.Require().NoError(err) s.Require().NotNil(validators) s.Require().Len(*validators, 1) s.Require().Equal(uint64(0), (*validators)[0].Index, "Validator index should be 0") s.Require().Equal("active_ongoing", (*validators)[0].Status, "Validator status should be active_ongoing") s.Require().True((*validators)[0].Balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True((*validators)[0].Balance <= 4e12, "Validator balance should not exceed 4000 BERA") } // TestGetValidatorsWithStatus tests querying validators with status parameter. func (s *BeaconKitE2ESuite) TestGetValidatorsWithStatus() { resp, err := s.getValidator(utils.StateIDHead, map[string]string{ "status": "active_ongoing", }) s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() validators, err := s.decodeValidatorsResponse(resp) s.Require().NoError(err) s.Require().NotNil(validators) for _, validator := range *validators { s.Require().Equal("active_ongoing", validator.Status, "Validator status should be active_ongoing") s.Require().True(validator.Balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True(validator.Balance <= 4e12, "Validator balance should not exceed 4000 BERA") } } // TestGetValidatorsWithIDAndStatus tests querying validators with both ID and status parameters. func (s *BeaconKitE2ESuite) TestGetValidatorsWithIDAndStatus() { // Call with both ID and status resp, err := s.getValidator(utils.StateIDHead, map[string]string{ "id": "0", "status": "active_ongoing", }) s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() // Decode and verify response validators, err := s.decodeValidatorsResponse(resp) s.Require().NoError(err) s.Require().NotNil(validators) s.Require().Len(*validators, 1) // Verify the validator has the expected ID and status s.Require().Equal(uint64(0), (*validators)[0].Index, "Validator index should be 0") s.Require().Equal("active_ongoing", (*validators)[0].Status, "Validator status should be active_ongoing") s.Require().True((*validators)[0].Balance > 0, "Validator balance should be positive") // 4e12 Gwei = 4 * 10^12 Gwei = 4,000,000,000,000 Gwei = 4000 BERA s.Require().True((*validators)[0].Balance <= 4e12, "Validator balance should not exceed 4000 BERA") } // TestGetValidatorsWithStateGenesis tests querying validators with state genesis. func (s *BeaconKitE2ESuite) TestGetValidatorsWithStateGenesis() { resp, err := s.getValidator(utils.StateIDGenesis) s.Require().NoError(err) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() validators, err := s.decodeValidatorsResponse(resp) s.Require().NoError(err) s.Require().NotNil(validators) for _, validator := range *validators { s.Require().True(validator.Status == "active_ongoing") s.Require().True(validator.Balance > 0, "Validator balance should be positive") // 32e9 Gwei = 32 * 10^9 Gwei = 32,000,000,000 Gwei = 32 BERA s.Require().True(validator.Balance <= 32e9, "Validator balance should not exceed 32 BERA") } } // TestGenesis tests querying the genesis of the beacon node. func (s *BeaconKitE2ESuite) TestGenesis() { client := s.initBeaconTest() genesisResp, err := client.Genesis(s.Ctx(), &beaconapi.GenesisOpts{}) s.Require().NoError(err) s.Require().NotNil(genesisResp) s.Require().NotEmpty(genesisResp.Data) genesis := genesisResp.Data s.Require().NotZero(genesis.GenesisTime, "Genesis time should not be zero") s.Require().True(genesis.GenesisTime.Unix() < time.Now().Unix(), "Genesis time should be in the past") s.Require().NotEmpty(genesis.GenesisValidatorsRoot, "Genesis validators root should not be empty") s.Require().NotEmpty(genesis.GenesisForkVersion, "Genesis fork version should not be empty") expectedVersion := version.Fulu() // TODO: change this back to Deneb once devnet spec is updated. s.Require().Equal( expectedVersion[:], genesis.GenesisForkVersion[:], "Genesis fork version does not match expected value", ) } // TestConfigSpec tests querying the config spec. func (s *BeaconKitE2ESuite) TestConfigSpec() { client := s.initBeaconTest() resp, err := client.Spec(s.Ctx(), &beaconapi.SpecOpts{}) s.Require().NoError(err) s.Require().NotNil(resp) specData := resp.Data s.Require().NotNil(specData) // TODO: make test use configurable chain spec. chainspec, err := spec.DevnetChainSpec() s.Require().NoError(err) // Verify essential config parameters exist and have expected types s.Require().Contains(specData, "DEPOSIT_CONTRACT_ADDRESS") addressBytes, ok := specData["DEPOSIT_CONTRACT_ADDRESS"].([]byte) s.Require().True(ok, "DEPOSIT_CONTRACT_ADDRESS should be a byte array") var executionAddress common.Address copy(executionAddress[:], addressBytes) // Convert chainspec's ExecutionAddress to common.Address depositAddr := common.Address(chainspec.DepositContractAddress()) s.Require().Equal(depositAddr, executionAddress) s.Require().Contains(specData, "DEPOSIT_NETWORK_ID") s.Require().Equal(chainspec.DepositEth1ChainID(), specData["DEPOSIT_NETWORK_ID"]) s.Require().Contains(specData, "DOMAIN_AGGREGATE_AND_PROOF") s.Require().EqualValues(chainspec.DomainTypeAggregateAndProof(), specData["DOMAIN_AGGREGATE_AND_PROOF"]) // Check penalty quotients s.Require().Contains(specData, "INACTIVITY_PENALTY_QUOTIENT") s.Require().Zero(specData["INACTIVITY_PENALTY_QUOTIENT"]) s.Require().Contains(specData, "INACTIVITY_PENALTY_QUOTIENT_ALTAIR") s.Require().Zero(specData["INACTIVITY_PENALTY_QUOTIENT_ALTAIR"]) } ================================================ FILE: testing/e2e/standard/blob_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build e2e package standard_test import ( "bytes" "context" "encoding/binary" "math/big" "sync" "github.com/attestantio/go-eth2-client/api" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/testing/e2e/suite" "github.com/berachain/beacon-kit/testing/e2e/suite/types/tx" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/txpool" coretypes "github.com/ethereum/go-ethereum/core/types" ) const ( // NumBlobsLoad is the number of blob-carrying transactions to submit in // the Test4844Live test. Cannot pool more than 16 txs currently. NumBlobsLoad uint64 = 16 // BlocksToWait4844 is the number of blocks to wait for the nodes to catch up. BlocksToWait4844 = 5 ) // Test4844Live tests sending a large number of blob carrying txs over the // network. func (s *BeaconKitE2ESuite) Test4844Live() { ctx, cancel := context.WithTimeout(s.Ctx(), suite.DefaultE2ETestTimeout) defer cancel() // Connect the consensus client node-api client0 := s.ConsensusClients(0) s.Require().NotNil(client0) // Grab values to plug into txs elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) sender := s.TestAccounts()[0] chainID, err := elClient.ChainID(ctx) s.Require().NoError(err) blkNum, err := elClient.BlockNumber(ctx) s.Require().NoError(err) tip, err := elClient.SuggestGasTipCap(ctx) s.Require().NoError(err) gasFee, err := elClient.SuggestGasPrice(ctx) s.Require().NoError(err) nonce, err := elClient.NonceAt(ctx, sender.Address(), new(big.Int).SetUint64(blkNum)) s.Require().NoError(err) // Craft and send each blob-carrying transaction. blobTxs := make([]*coretypes.Transaction, 0, NumBlobsLoad) for i := range NumBlobsLoad { blobData := make([]byte, 8) // For the first 5 transactions, submit duplicate blobs in separate // transactions by leaving blobData empty. This is allowed by the // protocol. if i >= 5 { binary.LittleEndian.PutUint64(blobData, nonce+i) } // Craft the blob-carrying transaction. blobTx := tx.New4844Tx( nonce+i, nil, 1000000, chainID, tip, gasFee, big.NewInt(0), []byte{0x01, 0x02, 0x03, 0x04}, big.NewInt(1), blobData, coretypes.AccessList{}, ) // Sign and submit the transaction. blobTx, err = sender.SignTx(chainID, blobTx) s.Require().NoError(err) s.Logger().Info("submitting blob transaction", "blobTx", blobTx.Hash().Hex()) blobTxs = append(blobTxs, blobTx) err = elClient.SendTransaction(ctx, blobTx) // TODO: Figure out what is causing this to happen. // Also, `errors.Is(err, txpool.ErrAlreadyKnown)` doesn't catch it. if err != nil && err.Error() == txpool.ErrAlreadyKnown.Error() { continue } s.Require().NoError(err) } // All node-api calls and verification are asynchronous. node-api should // be able to handle async calls. var wg sync.WaitGroup for _, blobTx := range blobTxs { wg.Add(1) go func(blobTx *coretypes.Transaction) { defer wg.Done() // Wait for the blob transaction to be mined before making request. s.Logger(). Info("waiting for blob transaction to be mined", "blobTx", blobTx.Hash().Hex()) receipt, errWait := bind.WaitMined(ctx, elClient, blobTx) s.Require().NoError(errWait) s.Require().Equal(coretypes.ReceiptStatusSuccessful, receipt.Status) // WaitMined only waits until the tx is included in a block. This // gets triggered whenever beacon-kit sends a FCU including the // block. In the optimistic builder, this happens before the block // is finalized. Meaning the data has not yet been stored. Let's // just wait 1 block. // //nolint:contextcheck // uses the service context. s.Require().NoError(s.WaitForNBlockNumbers(1)) // Fetch blobs from node-api. response, errAPI := client0.BlobSidecars(ctx, &api.BlobSidecarsOpts{Block: receipt.BlockNumber.String()}) s.Require().NoError(errAPI, "unable to fetch blob sidecars from node-api") // Verify blob data from each transaction is published by the node-api. sidecar := blobTx.BlobTxSidecar() for i, commitment := range sidecar.Commitments { verified := false for _, blob := range response.Data { if bytes.Equal(blob.KZGCommitment[:], commitment[:]) { s.Require().Equal(sidecar.Blobs[i][:], blob.Blob[:], "blob data not equal") verified = true } } s.Require().True(verified, "blob data was not made available by node-api") s.Logger().Info("verified blob data availability", "KzgCommitment", hex.EncodeBytes(commitment[:])) } }(blobTx) } // Wait for DA validation to finish wg.Wait() // Ensure Blob Tx doesn't cause liveliness issues. err = s.WaitForNBlockNumbers(BlocksToWait4844) s.Require().NoError(err) } ================================================ FILE: testing/e2e/standard/comet_api_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build e2e package standard_test import ( "bytes" "encoding/json" "fmt" "io" "net/http" "sync" sdkcollections "cosmossdk.io/collections" "github.com/berachain/beacon-kit/storage/beacondb/keys" "github.com/berachain/beacon-kit/testing/e2e/config" rpcclient "github.com/cometbft/cometbft/rpc/client" ics23 "github.com/cosmos/ics23/go" ) // TestABCIInfo compares the ABCI info response among all nodes and cross-checks with the EL. func (s *BeaconKitE2ESuite) TestABCIInfo() { // Wait for execution block 5 to ensure nodes have progressed. s.Require().NoError(s.WaitForFinalizedBlockNumber(5)) // Retrieve heights from all nodes in parallel. var ( wg sync.WaitGroup heightsMap sync.Map errorsMap sync.Map ) for i := range config.NumValidators { wg.Add(1) go func(i int) { defer wg.Done() client, name := s.ConsensusClients(i), config.ValidatorConsensusClientName(i) s.Require().NotNil(client) abciInfo, err := client.ABCIInfo(s.Ctx()) if err != nil { errorsMap.Store(name, err) return } heightsMap.Store(name, abciInfo.LastBlockHeight) }(i) } // Also retrieve height from the EL client. wg.Add(1) go func() { defer wg.Done() elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) elHeight, err := elClient.BlockNumber(s.Ctx()) s.Require().NoError(err) heightsMap.Store("el", int64(elHeight)) // #nosec G115 }() wg.Wait() // Check for errors. errorsMap.Range(func(key, value interface{}) bool { name := key.(string) //nolint:errcheck // Safe to ignore. err := value.(error) //nolint:errcheck // Safe to ignore. s.Require().NoError(err, "Error getting ABCI info from node %s", name) return true }) // Collect heights into a map for comparison. heights := make(map[string]int64) heightsMap.Range(func(key, value interface{}) bool { name := key.(string) //nolint:errcheck // Safe to ignore. height := value.(int64) //nolint:errcheck // Safe to ignore. heights[name] = height return true }) // Verify that all heights are within +/- 1 of each other. for name1, height1 := range heights { for name2, height2 := range heights { if name1 == name2 { continue } diff := height1 - height2 if diff < 0 { diff = -diff } s.Require().LessOrEqual(diff, int64(1), "Height difference between nodes %s (%d) and %s (%d) exceeds 1 block", name1, height1, name2, height2) } } } // TestABCIQuery checks that the ABCI query response is valid. func (s *BeaconKitE2ESuite) TestABCIQuery() { // Wait for execution block 5 to ensure nodes have progressed. s.Require().NoError(s.WaitForFinalizedBlockNumber(5)) // Get the full node consensus client. client := s.ConsensusClients(2) s.Require().NotNil(client) // membership // Get ABCI query with proof of the fork data from a node. key := sdkcollections.NewPrefix([]byte{keys.ForkPrefix}) abciQuery, err := client.ABCIQuery( s.Ctx(), "store/beacon/key", key, rpcclient.ABCIQueryOptions{ Prove: true, Height: 5, }, ) s.Require().NoError(err) s.Require().NotNil(abciQuery) s.Require().Equal(abciQuery.Height, int64(5)) block := int64(6) commit, err := client.Commit(s.Ctx(), &block) if err != nil { panic(err) } proofs := make([]*ics23.CommitmentProof, len(abciQuery.ProofOps.Ops)) for i := range abciQuery.ProofOps.Ops { proofs[i] = &ics23.CommitmentProof{} err = proofs[i].Unmarshal(abciQuery.ProofOps.Ops[i].Data) s.Require().NoError(err) } verifyChainedMembershipProof( ics23.CommitmentRoot(commit.SignedHeader.Header.AppHash), []*ics23.ProofSpec{ics23.IavlSpec, ics23.TendermintSpec}, proofs, [][]byte{[]byte("beacon"), key.Bytes()}, abciQuery.Value, 0, ) // non-membership // Get ABCI query with proof of the fork data from a node. key = []byte("oogabooga") abciQuery, err = client.ABCIQuery( s.Ctx(), "store/beacon/key", key, rpcclient.ABCIQueryOptions{ Prove: true, Height: 5, }, ) s.Require().NoError(err) s.Require().NotNil(abciQuery) s.Require().Equal(abciQuery.Height, int64(5)) block = int64(6) commit, err = client.Commit(s.Ctx(), &block) if err != nil { panic(err) } s.Assert().Empty(abciQuery.Value) proofs = make([]*ics23.CommitmentProof, len(abciQuery.ProofOps.Ops)) for i := range abciQuery.ProofOps.Ops { proofs[i] = &ics23.CommitmentProof{} err = proofs[i].Unmarshal(abciQuery.ProofOps.Ops[i].Data) s.Require().NoError(err) } verifyNonMembership( proofs, []*ics23.ProofSpec{ics23.IavlSpec, ics23.TendermintSpec}, commit.SignedHeader.Header.AppHash.Bytes(), [][]byte{[]byte("beacon"), key.Bytes()}, ) } // TestCometBFTBlock tests the /cometbft/v1/block/:height endpoint. func (s *BeaconKitE2ESuite) TestCometBFTBlock() { client := s.initHTTPBeaconTest() resp, err := client.Get("/cometbft/v1/block/5") s.Require().NoError(err) s.Require().NotNil(resp) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() blockData := s.decodeCometBFTResponse(resp) // Validate block structure. header, ok := blockData["header"].(map[string]any) s.Require().True(ok, "block should have a 'header' field") s.Require().NotEmpty(header["chain_id"], "header should have chain_id") s.Require().Equal(float64(5), header["height"], "header height should match requested height") s.Require().NotEmpty(header["time"], "header should have time") _, ok = blockData["data"].(map[string]any) s.Require().True(ok, "block should have a 'data' field") _, ok = blockData["evidence"].(map[string]any) s.Require().True(ok, "block should have an 'evidence' field") } // TestCometBFTBlockInvalidHeight tests the /cometbft/v1/block/:height endpoint with a non-numeric height. func (s *BeaconKitE2ESuite) TestCometBFTBlockInvalidHeight() { client := s.initHTTPBeaconTest() resp, err := client.Get("/cometbft/v1/block/invalid") s.Require().NoError(err) s.Require().NotNil(resp) s.Require().Equal(http.StatusBadRequest, resp.StatusCode) resp.Body.Close() } // TestCometBFTSignedHeader tests the /cometbft/v1/signed_header/:height endpoint. func (s *BeaconKitE2ESuite) TestCometBFTSignedHeader() { client := s.initHTTPBeaconTest() resp, err := client.Get("/cometbft/v1/signed_header/5") s.Require().NoError(err) s.Require().NotNil(resp) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() shData := s.decodeCometBFTResponse(resp) // Validate signed header structure. header, ok := shData["header"].(map[string]any) s.Require().True(ok, "signed header should have a 'header' field") s.Require().NotEmpty(header["chain_id"], "header should have chain_id") s.Require().Equal(float64(5), header["height"], "header height should match requested height") s.Require().NotEmpty(header["time"], "header should have time") commit, ok := shData["commit"].(map[string]any) s.Require().True(ok, "signed header should have a 'commit' field") s.Require().NotNil(commit["height"], "commit should have height") s.Require().NotNil(commit["round"], "commit should have round") } // TestCometBFTSignedHeaderInvalidHeight tests the /cometbft/v1/signed_header/:height endpoint with a non-numeric height. func (s *BeaconKitE2ESuite) TestCometBFTSignedHeaderInvalidHeight() { client := s.initHTTPBeaconTest() resp, err := client.Get("/cometbft/v1/signed_header/invalid") s.Require().NoError(err) s.Require().NotNil(resp) s.Require().Equal(http.StatusBadRequest, resp.StatusCode) resp.Body.Close() } // TestCometBFTSignedHeaderMatchesCommit cross-validates the CometBFT signed header API response // against the CometBFT RPC Commit response for the same height. func (s *BeaconKitE2ESuite) TestCometBFTSignedHeaderMatchesCommit() { httpClient := s.initHTTPBeaconTest() // Get signed header from the node-api. resp, err := httpClient.Get("/cometbft/v1/signed_header/5") s.Require().NoError(err) s.Require().NotNil(resp) s.Require().Equal(http.StatusOK, resp.StatusCode) defer resp.Body.Close() shData := s.decodeCometBFTResponse(resp) apiHeader, ok := shData["header"].(map[string]any) s.Require().True(ok) // Get the same data via CometBFT RPC Commit. client := s.ConsensusClients(0) s.Require().NotNil(client) height := int64(5) commit, err := client.Commit(s.Ctx(), &height) s.Require().NoError(err) s.Require().NotNil(commit) // Cross-validate chain_id and height. s.Require().Equal( commit.SignedHeader.Header.ChainID, apiHeader["chain_id"], "chain_id from node-api should match CometBFT RPC", ) s.Require().Equal( float64(5), apiHeader["height"], "height from node-api should match requested height", ) s.Require().Equal( height, commit.SignedHeader.Header.Height, "height from CometBFT RPC should match requested height", ) } // decodeCometBFTResponse reads an HTTP response body and extracts the "data" field // from the CometBFT API response envelope. func (s *BeaconKitE2ESuite) decodeCometBFTResponse(resp *http.Response) map[string]any { bodyBytes, err := io.ReadAll(resp.Body) s.Require().NoError(err) var envelope map[string]any err = json.Unmarshal(bodyBytes, &envelope) s.Require().NoError(err) data, ok := envelope["data"].(map[string]any) s.Require().True(ok, "response should have a 'data' field") return data } // https://github.com/cosmos/ibc-go/blob/20326046a09330898fac90540134d8556f4506cc/modules/core/23-commitment/types/merkle.go#L143-L189 func verifyChainedMembershipProof( root []byte, specs []*ics23.ProofSpec, proofs []*ics23.CommitmentProof, keys [][]byte, value []byte, index int, ) { var ( subroot []byte err error ) // Initialize subroot to value since the proofs list may be empty. // This may happen if this call is verifying intermediate proofs after the lowest proof has been executed. // In this case, there may be no intermediate proofs to verify and we just check that lowest proof root equals final root subroot = value for i := index; i < len(proofs); i++ { subroot, err = proofs[i].Calculate() if err != nil { panic(fmt.Sprintf("could not calculate proof root at index %d, merkle tree may be empty. %v", i, err)) } // Since keys are passed in from highest to lowest, we must grab their indices in reverse order // from the proofs and specs which are lowest to highest key := keys[len(keys)-1-i] ep := proofs[i].GetExist() if ep == nil { panic(fmt.Sprintf("commitment proof must be existence proof. got: %T at index %d", i, proofs[i])) } // verify membership of the proof at this index with appropriate key and value if err = ep.Verify(specs[i], subroot, key, value); err != nil { panic(fmt.Sprintf("failed to verify membership proof at index %d: %v", i, err)) } // Set value to subroot so that we verify next proof in chain commits to this subroot value = subroot } // Check that chained proof root equals passed-in root if !bytes.Equal(root, subroot) { panic(fmt.Sprintf("proof did not commit to expected root: %X, got: %X.", root, subroot)) } } // https://github.com/cosmos/ibc-go/blob/20326046a09330898fac90540134d8556f4506cc/modules/core/23-commitment/types/merkle.go#L105-L141 func verifyNonMembership(proofs []*ics23.CommitmentProof, specs []*ics23.ProofSpec, root []byte, path [][]byte) { // VerifyNonMembership will verify the absence of key in lowest subtree, and then chain inclusion proofs // of all subroots up to final root subroot, err := proofs[0].Calculate() if err != nil { panic(fmt.Sprintf("could not calculate root for proof index 0, merkle tree is likely empty. %v", err)) } key := path[uint64(len(path)-1)] np := proofs[0].GetNonexist() if np == nil { panic(fmt.Sprintf("commitment proof must be non-existence proof for verifying non-membership. got: %T", proofs[0])) } if err = np.Verify(specs[0], subroot, key); err != nil { panic(fmt.Sprintf("failed to verify non-membership proof with key %s: %v", string(key), err)) } // Verify chained membership proof starting from index 1 with value = subroot verifyChainedMembershipProof(root, specs, proofs, path, subroot, 1) } ================================================ FILE: testing/e2e/standard/inflation_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build e2e package standard_test import ( "math/big" "sync" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" ) // TestEVMInflation checks that the EVM inflation address receives the correct // amount of EVM inflation per block. func (s *BeaconKitE2ESuite) TestEVMInflation() { // TODO: make test use configurable chain spec. chainspec, err := spec.DevnetChainSpec() s.Require().NoError(err) elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) var ( inflationPerBlock uint64 inflationAddress common.ExecutionAddress oldInflationAddress common.ExecutionAddress preForkAddressFinalBalance *big.Int preForkLatestBalance *big.Int balance *big.Int expectedBalance *big.Int forkSlot int64 onceOnFork sync.Once ) // Arbitrarily run test for 2 epochs. for blkNum := range int64(2 * chainspec.SlotsPerEpoch()) { err = s.WaitForFinalizedBlockNumber(uint64(blkNum)) s.Require().NoError(err) header, errBlk := elClient.HeaderByNumber(s.Ctx(), big.NewInt(blkNum)) s.Require().NoError(errBlk) payloadTime := header.Time inflationPerBlock = chainspec.EVMInflationPerBlock(math.U64(payloadTime)).Unwrap() inflationAddress = chainspec.EVMInflationAddress(math.U64(payloadTime)) if chainspec.Deneb1ForkTime() > 0 && payloadTime >= chainspec.Deneb1ForkTime() { // If we have passed the Deneb1 fork, do some verifications and update inflation values. onceOnFork.Do(func() { oldInflationPerBlock := chainspec.EVMInflationPerBlock(math.U64(chainspec.Deneb1ForkTime() - 1)) oldInflationAddress = chainspec.EVMInflationAddress(math.U64(chainspec.Deneb1ForkTime() - 1)) // Verify the post fork inflation changes s.Require().NotEqual(oldInflationPerBlock, inflationPerBlock) s.Require().NotEqual(oldInflationAddress, inflationAddress) forkSlot = blkNum // take the snapshot of balance right before the fork and check it won't change anymore preForkAddressFinalBalance, err = elClient.BalanceAt( s.Ctx(), gethcommon.Address(oldInflationAddress), big.NewInt(blkNum-1), ) s.Require().NoError(err) }) // Enforce that the balance of the EVM inflation address // prior to the hardfork is the same as it is now. preForkLatestBalance, err = elClient.BalanceAt( s.Ctx(), gethcommon.Address(oldInflationAddress), nil, // at the current block ) s.Require().NoError(err) s.Require().Zero(preForkAddressFinalBalance.Cmp(preForkLatestBalance)) expectedBalance = new(big.Int).Mul( new(big.Int).SetUint64(inflationPerBlock*params.GWei), big.NewInt(blkNum-forkSlot+1), ) } else { // Pre-Deneb1 expectedBalance = new(big.Int).Mul( new(big.Int).SetUint64(inflationPerBlock*params.GWei), big.NewInt(blkNum), ) } balance, err = elClient.BalanceAt( s.Ctx(), gethcommon.Address(inflationAddress), big.NewInt(blkNum), ) s.Require().NoError(err) s.Require().Zero(balance.Cmp(expectedBalance), "height", blkNum, "balance", balance, "expectedBalance", expectedBalance, ) } } ================================================ FILE: testing/e2e/standard/proofs_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build e2e package standard_test import ( "math/big" "strconv" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/gethlib/ssztest" "github.com/berachain/beacon-kit/node-api/handlers/proof/merkle" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/math" "github.com/ethereum/go-ethereum/accounts/abi/bind" coretypes "github.com/ethereum/go-ethereum/core/types" ) // TestBlockProposerProof tests the block proposer proof endpoint by fetching and verifying // the block proposer proofs against the SSZTest contract. Refer to // beacon-kit/contracts/src/eip4788/SSZ.sol for details. func (s *BeaconKitE2ESuite) TestBlockProposerProof() { // Sender account sender := s.TestAccounts()[0] // Get the execution client. elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) // Get the chain ID. chainID, err := elClient.ChainID(s.Ctx()) s.Require().NoError(err) // Deploy the SSZTest contract to verify the block proposer proof. addr, tx, sszTest, err := ssztest.DeploySSZTest(&bind.TransactOpts{ From: sender.Address(), Signer: sender.SignerFunc(chainID), GasLimit: 1000000, Context: s.Ctx(), }, elClient) s.Require().NoError(err) // Confirm deployment. receipt, err := bind.WaitMined(s.Ctx(), elClient, tx) s.Require().NoError(err) s.Require().Equal(coretypes.ReceiptStatusSuccessful, receipt.Status) s.Logger().Info("SSZTest contract deployed successfully", "address", addr.Hex()) // Get the current block number. blockNumber, err := elClient.BlockNumber(s.Ctx()) s.Require().NoError(err) // Get the block proposer proof for the parent block number. blockProposerResp, err := s.ConsensusClients(0).BlockProposerProof( s.Ctx(), strconv.FormatUint(blockNumber-1, 10), ) s.Require().NoError(err) s.Require().NotNil(blockProposerResp) s.Require().NotNil(blockProposerResp.BeaconBlockHeader) // Get the next block header. nextHeader, err := elClient.HeaderByNumber( s.Ctx(), new(big.Int).SetUint64(blockNumber), ) s.Require().NoError(err) s.Require().NotNil(nextHeader) // Get the block proposer proof for the next timestamp and enforce equality. blockProposerResp2, err := s.ConsensusClients(0).BlockProposerProof( s.Ctx(), "t"+strconv.FormatUint(nextHeader.Time, 10), ) s.Require().NoError(err) s.Require().NotNil(blockProposerResp2) s.Require().NotNil(blockProposerResp2.BeaconBlockHeader) s.Require().Equal(*blockProposerResp.BeaconBlockHeader, *blockProposerResp2.BeaconBlockHeader) s.Require().Equal(blockProposerResp.BeaconBlockRoot, blockProposerResp2.BeaconBlockRoot) s.Require().Equal(blockProposerResp.ValidatorPubkey, blockProposerResp2.ValidatorPubkey) s.Require().ElementsMatch( blockProposerResp.ValidatorPubkeyProof, blockProposerResp2.ValidatorPubkeyProof, ) s.Require().ElementsMatch( blockProposerResp.ProposerIndexProof, blockProposerResp2.ProposerIndexProof, ) // Get the parent beacon block root of the current timestamp using EIP-4788 Beacon Roots // and verify equal to what is returned by the API proof/ endpoint. parentBlockRoot4788, err := sszTest.GetParentBlockRootAt( &bind.CallOpts{ Context: s.Ctx(), }, nextHeader.Time, ) s.Require().NoError(err) s.Require().Equal(common.Root(parentBlockRoot4788), blockProposerResp.BeaconBlockRoot) // Verify the beacon block root is equal to HTR(BeaconBlockHeader). s.Require().Equal( blockProposerResp.BeaconBlockRoot, blockProposerResp.BeaconBlockHeader.HashTreeRoot(), ) // Verify the slot is equal to the requested block number. s.Require().Equal(blockProposerResp.BeaconBlockHeader.Slot.Unwrap(), blockNumber-1) // First verify the proposer index proof. proposerIndexProof := make([][32]byte, len(blockProposerResp.ProposerIndexProof)) for i, proofItem := range blockProposerResp.ProposerIndexProof { proposerIndexProof[i] = proofItem } err = sszTest.MustVerifyProof( &bind.CallOpts{ Context: s.Ctx(), }, proposerIndexProof, blockProposerResp.BeaconBlockRoot, blockProposerResp.BeaconBlockHeader.ProposerIndex.HashTreeRoot(), big.NewInt(merkle.ProposerIndexGIndexBlock), ) s.Require().NoError(err) // If the proof or leaf is modified, the proof should not verify. isVerified, err := sszTest.VerifyProof( &bind.CallOpts{ Context: s.Ctx(), }, proposerIndexProof, blockProposerResp.BeaconBlockRoot, (blockProposerResp.BeaconBlockHeader.ProposerIndex + 2).HashTreeRoot(), // malicious leaf big.NewInt(merkle.ProposerIndexGIndexBlock), ) s.Require().NoError(err) s.Require().False(isVerified) // Get the chain spec to determine the fork version. // TODO: make test use configurable chain spec. cs, err := spec.DevnetChainSpec() s.Require().NoError(err) // Get the fork version based on the block's timestamp. header, err := elClient.HeaderByNumber( s.Ctx(), new(big.Int).SetUint64(blockNumber-1), ) s.Require().NoError(err) forkVersion := cs.ActiveForkVersionForTimestamp(math.U64(header.Time)) zeroValidatorPubkeyGIndex, err := merkle.GetZeroValidatorPubkeyGIndexBlock(forkVersion) s.Require().NoError(err) // Calculate the validator pubkey GIndex based on fork version. gIndex := zeroValidatorPubkeyGIndex + (blockProposerResp.BeaconBlockHeader.ProposerIndex.Unwrap() * merkle.ValidatorGIndexOffset) // Next verify the validator pubkey proof. validatorPubkeyProof := make([][32]byte, len(blockProposerResp.ValidatorPubkeyProof)) for i, proofItem := range blockProposerResp.ValidatorPubkeyProof { validatorPubkeyProof[i] = proofItem } err = sszTest.MustVerifyProof( &bind.CallOpts{ Context: s.Ctx(), }, validatorPubkeyProof, blockProposerResp.BeaconBlockRoot, blockProposerResp.ValidatorPubkey.HashTreeRoot(), new(big.Int).SetUint64(gIndex), ) s.Require().NoError(err) } // TestValidatorBalanceProof tests the validator balance proof endpoint by fetching and verifying // validator balance proofs against the SSZTest contract. func (s *BeaconKitE2ESuite) TestValidatorBalanceProof() { // Sender account sender := s.TestAccounts()[0] // Get the execution client. elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) // Get the chain ID. chainID, err := elClient.ChainID(s.Ctx()) s.Require().NoError(err) // Deploy the SSZTest contract to verify the validator balance proof. addr, tx, sszTest, err := ssztest.DeploySSZTest(&bind.TransactOpts{ From: sender.Address(), Signer: sender.SignerFunc(chainID), GasLimit: 1000000, Context: s.Ctx(), }, elClient) s.Require().NoError(err) // Confirm deployment. receipt, err := bind.WaitMined(s.Ctx(), elClient, tx) s.Require().NoError(err) s.Require().Equal(coretypes.ReceiptStatusSuccessful, receipt.Status) s.Logger().Info("SSZTest contract deployed successfully", "address", addr.Hex()) // Get the current block number. blockNumber, err := elClient.BlockNumber(s.Ctx()) s.Require().NoError(err) // Get the validator balance proof for validator 0 at the parent block number. validatorIndex := uint64(0) balanceResp, err := s.ConsensusClients(0).ValidatorBalanceProof( s.Ctx(), strconv.FormatUint(blockNumber-1, 10), strconv.FormatUint(validatorIndex, 10), ) s.Require().NoError(err) s.Require().NotNil(balanceResp) s.Require().NotNil(balanceResp.BeaconBlockHeader) s.Require().Equal(balanceResp.BeaconBlockRoot, balanceResp.BeaconBlockHeader.HashTreeRoot()) s.Require().Equal(balanceResp.BeaconBlockHeader.Slot.Unwrap(), blockNumber-1) // Get the next block header. nextHeader, err := elClient.HeaderByNumber(s.Ctx(), new(big.Int).SetUint64(blockNumber)) s.Require().NoError(err) s.Require().NotNil(nextHeader) // Get the block proposer proof for the next timestamp and enforce equality. balanceResp2, err := s.ConsensusClients(0).ValidatorBalanceProof( s.Ctx(), "t"+strconv.FormatUint(nextHeader.Time, 10), strconv.FormatUint(validatorIndex, 10), ) s.Require().NoError(err) s.Require().NotNil(balanceResp2) s.Require().NotNil(balanceResp2.BeaconBlockHeader) s.Require().Equal(*balanceResp.BeaconBlockHeader, *balanceResp2.BeaconBlockHeader) s.Require().Equal(balanceResp.BeaconBlockRoot, balanceResp2.BeaconBlockRoot) s.Require().Equal(balanceResp.BalanceLeaf, balanceResp2.BalanceLeaf) s.Require().ElementsMatch( balanceResp.BalanceProof, balanceResp2.BalanceProof, ) // Get the parent beacon block root of the current timestamp using EIP-4788 Beacon Roots // and verify equal to what is returned by the API proof/ endpoint. parentBlockRoot4788, err := sszTest.GetParentBlockRootAt( &bind.CallOpts{ Context: s.Ctx(), }, nextHeader.Time, ) s.Require().NoError(err) s.Require().Equal(common.Root(parentBlockRoot4788), balanceResp.BeaconBlockRoot) // Get the chain spec to determine the fork version. cs, err := spec.DevnetChainSpec() s.Require().NoError(err) // Get the fork version based on the block's timestamp. header, err := elClient.HeaderByNumber( s.Ctx(), new(big.Int).SetUint64(blockNumber-1), ) s.Require().NoError(err) forkVersion := cs.ActiveForkVersionForTimestamp(math.U64(header.Time)) zeroValidatorBalanceGIndex, err := merkle.GetZeroValidatorBalanceGIndexBlock(forkVersion) s.Require().NoError(err) // Calculate the balance GIndex based on fork version. // Balances are packed 4 per leaf, so we need to divide by 4. leafIndex := validatorIndex / 4 gIndex := zeroValidatorBalanceGIndex + leafIndex // Verify the validator balance proof. balanceProof := make([][32]byte, len(balanceResp.BalanceProof)) for i, proofItem := range balanceResp.BalanceProof { balanceProof[i] = proofItem } err = sszTest.MustVerifyProof( &bind.CallOpts{ Context: s.Ctx(), }, balanceProof, balanceResp.BeaconBlockRoot, balanceResp.BalanceLeaf, // The leaf contains 4 packed balances new(big.Int).SetUint64(gIndex), ) s.Require().NoError(err) } // TestValidatorCredentialsProof tests the validator withdrawal credentials proof endpoint by fetching // and verifying withdrawal credentials proofs against the SSZTest contract. func (s *BeaconKitE2ESuite) TestValidatorCredentialsProof() { // Sender account sender := s.TestAccounts()[0] // Get the execution client. elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) // Get the chain ID. chainID, err := elClient.ChainID(s.Ctx()) s.Require().NoError(err) // Deploy the SSZTest contract to verify the validator credentials proof. addr, tx, sszTest, err := ssztest.DeploySSZTest(&bind.TransactOpts{ From: sender.Address(), Signer: sender.SignerFunc(chainID), GasLimit: 1000000, Context: s.Ctx(), }, elClient) s.Require().NoError(err) // Confirm deployment. receipt, err := bind.WaitMined(s.Ctx(), elClient, tx) s.Require().NoError(err) s.Require().Equal(coretypes.ReceiptStatusSuccessful, receipt.Status) s.Logger().Info("SSZTest contract deployed successfully", "address", addr.Hex()) // Get the current block number. blockNumber, err := elClient.BlockNumber(s.Ctx()) s.Require().NoError(err) // Get the validator credentials proof for validator 0 at the parent block number. validatorIndex := uint64(0) credsResp, err := s.ConsensusClients(0).ValidatorCredentialsProof( s.Ctx(), strconv.FormatUint(blockNumber-1, 10), strconv.FormatUint(validatorIndex, 10), ) s.Require().NoError(err) s.Require().NotNil(credsResp) s.Require().NotNil(credsResp.BeaconBlockHeader) s.Require().Equal(credsResp.BeaconBlockRoot, credsResp.BeaconBlockHeader.HashTreeRoot()) s.Require().Equal(credsResp.BeaconBlockHeader.Slot.Unwrap(), blockNumber-1) // Get the next block header. nextHeader, err := elClient.HeaderByNumber(s.Ctx(), new(big.Int).SetUint64(blockNumber)) s.Require().NoError(err) s.Require().NotNil(nextHeader) // Get the block proposer proof for the next timestamp and enforce equality. credsResp1, err := s.ConsensusClients(0).ValidatorCredentialsProof( s.Ctx(), "t"+strconv.FormatUint(nextHeader.Time, 10), strconv.FormatUint(validatorIndex, 10), ) s.Require().NoError(err) s.Require().NotNil(credsResp1) s.Require().NotNil(credsResp1.BeaconBlockHeader) s.Require().Equal(*credsResp.BeaconBlockHeader, *credsResp1.BeaconBlockHeader) s.Require().Equal(credsResp.BeaconBlockRoot, credsResp1.BeaconBlockRoot) s.Require().Equal(credsResp.ValidatorWithdrawalCredentials, credsResp1.ValidatorWithdrawalCredentials) s.Require().ElementsMatch(credsResp.WithdrawalCredentialsProof, credsResp1.WithdrawalCredentialsProof) // Get the parent beacon block root of the current timestamp using EIP-4788 Beacon Roots // and verify equal to what is returned by the API proof/ endpoint. parentBlockRoot4788, err := sszTest.GetParentBlockRootAt( &bind.CallOpts{ Context: s.Ctx(), }, nextHeader.Time, ) s.Require().NoError(err) s.Require().Equal(common.Root(parentBlockRoot4788), credsResp.BeaconBlockRoot) // Get the chain spec to determine the fork version. cs, err := spec.DevnetChainSpec() s.Require().NoError(err) // Get the fork version based on the block's timestamp. header, err := elClient.HeaderByNumber( s.Ctx(), new(big.Int).SetUint64(blockNumber-1), ) s.Require().NoError(err) forkVersion := cs.ActiveForkVersionForTimestamp(math.U64(header.Time)) zeroValidatorCredentialsGIndex, err := merkle.GetZeroValidatorCredentialsGIndexBlock(forkVersion) s.Require().NoError(err) // Calculate the credentials GIndex based on fork version. gIndex := zeroValidatorCredentialsGIndex + (validatorIndex * merkle.ValidatorGIndexOffset) // Verify the validator withdrawal credentials proof. credentialsProof := make([][32]byte, len(credsResp.WithdrawalCredentialsProof)) for i, proofItem := range credsResp.WithdrawalCredentialsProof { credentialsProof[i] = proofItem } err = sszTest.MustVerifyProof( &bind.CallOpts{ Context: s.Ctx(), }, credentialsProof, credsResp.BeaconBlockRoot, common.Root(credsResp.ValidatorWithdrawalCredentials), new(big.Int).SetUint64(gIndex), ) s.Require().NoError(err) // Test with a different validator index validatorIndex2 := uint64(1) credsResp2, err := s.ConsensusClients(0).ValidatorCredentialsProof( s.Ctx(), strconv.FormatUint(blockNumber-1, 10), strconv.FormatUint(validatorIndex2, 10), ) s.Require().NoError(err) s.Require().NotNil(credsResp2) // Calculate the credentials GIndex for validator 1 gIndex2 := zeroValidatorCredentialsGIndex + (validatorIndex2 * merkle.ValidatorGIndexOffset) // Verify the validator withdrawal credentials proof for validator 1 credentialsProof2 := make([][32]byte, len(credsResp2.WithdrawalCredentialsProof)) for i, proofItem := range credsResp2.WithdrawalCredentialsProof { credentialsProof2[i] = proofItem } err = sszTest.MustVerifyProof( &bind.CallOpts{ Context: s.Ctx(), }, credentialsProof2, credsResp2.BeaconBlockRoot, common.Root(credsResp2.ValidatorWithdrawalCredentials), new(big.Int).SetUint64(gIndex2), ) s.Require().NoError(err) } // TestValidatorPubkeyProof tests the validator pubkey proof endpoint by fetching and verifying // validator pubkey proofs against the SSZTest contract. func (s *BeaconKitE2ESuite) TestValidatorPubkeyProof() { // Sender account sender := s.TestAccounts()[0] // Get the execution client. elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) // Get the chain ID. chainID, err := elClient.ChainID(s.Ctx()) s.Require().NoError(err) // Deploy the SSZTest contract to verify the validator pubkey proof. addr, tx, sszTest, err := ssztest.DeploySSZTest(&bind.TransactOpts{ From: sender.Address(), Signer: sender.SignerFunc(chainID), GasLimit: 1000000, Context: s.Ctx(), }, elClient) s.Require().NoError(err) // Confirm deployment. receipt, err := bind.WaitMined(s.Ctx(), elClient, tx) s.Require().NoError(err) s.Require().Equal(coretypes.ReceiptStatusSuccessful, receipt.Status) s.Logger().Info("SSZTest contract deployed successfully", "address", addr.Hex()) // Get the current block number. blockNumber, err := elClient.BlockNumber(s.Ctx()) s.Require().NoError(err) // Get the validator pubkey proof for validator 0 at the parent block number. validatorIndex := uint64(0) pubkeyResp, err := s.ConsensusClients(0).ValidatorPubkeyProof( s.Ctx(), strconv.FormatUint(blockNumber-1, 10), strconv.FormatUint(validatorIndex, 10), ) s.Require().NoError(err) s.Require().NotNil(pubkeyResp) s.Require().NotNil(pubkeyResp.BeaconBlockHeader) s.Require().Equal(pubkeyResp.BeaconBlockRoot, pubkeyResp.BeaconBlockHeader.HashTreeRoot()) s.Require().Equal(pubkeyResp.BeaconBlockHeader.Slot.Unwrap(), blockNumber-1) // Get the next block header. nextHeader, err := elClient.HeaderByNumber(s.Ctx(), new(big.Int).SetUint64(blockNumber)) s.Require().NoError(err) s.Require().NotNil(nextHeader) // Get the pubkey proof for the next timestamp and enforce equality. pubkeyResp2, err := s.ConsensusClients(0).ValidatorPubkeyProof( s.Ctx(), "t"+strconv.FormatUint(nextHeader.Time, 10), strconv.FormatUint(validatorIndex, 10), ) s.Require().NoError(err) s.Require().NotNil(pubkeyResp2) s.Require().NotNil(pubkeyResp2.BeaconBlockHeader) s.Require().Equal(*pubkeyResp.BeaconBlockHeader, *pubkeyResp2.BeaconBlockHeader) s.Require().Equal(pubkeyResp.BeaconBlockRoot, pubkeyResp2.BeaconBlockRoot) s.Require().Equal(pubkeyResp.ValidatorPubkey, pubkeyResp2.ValidatorPubkey) s.Require().ElementsMatch(pubkeyResp.ValidatorPubkeyProof, pubkeyResp2.ValidatorPubkeyProof) // Get the parent beacon block root of the current timestamp using EIP-4788 Beacon Roots // and verify equal to what is returned by the API proof/ endpoint. parentBlockRoot4788, err := sszTest.GetParentBlockRootAt( &bind.CallOpts{Context: s.Ctx()}, nextHeader.Time, ) s.Require().NoError(err) s.Require().Equal(common.Root(parentBlockRoot4788), pubkeyResp.BeaconBlockRoot) // Get the chain spec to determine the fork version. cs, err := spec.DevnetChainSpec() s.Require().NoError(err) // Get the fork version based on the block's timestamp. header, err := elClient.HeaderByNumber( s.Ctx(), new(big.Int).SetUint64(blockNumber-1), ) s.Require().NoError(err) forkVersion := cs.ActiveForkVersionForTimestamp(math.U64(header.Time)) zeroValidatorPubkeyGIndex, err := merkle.GetZeroValidatorPubkeyGIndexBlock(forkVersion) s.Require().NoError(err) // Calculate the pubkey GIndex based on fork version. gIndex := zeroValidatorPubkeyGIndex + (validatorIndex * merkle.ValidatorGIndexOffset) // Verify the validator pubkey proof. validatorPubkeyProof := make([][32]byte, len(pubkeyResp.ValidatorPubkeyProof)) for i, proofItem := range pubkeyResp.ValidatorPubkeyProof { validatorPubkeyProof[i] = proofItem } err = sszTest.MustVerifyProof( &bind.CallOpts{Context: s.Ctx()}, validatorPubkeyProof, pubkeyResp.BeaconBlockRoot, pubkeyResp.ValidatorPubkey.HashTreeRoot(), new(big.Int).SetUint64(gIndex), ) s.Require().NoError(err) // Test with a different validator index validatorIndex2 := uint64(1) pubkeyResp3, err := s.ConsensusClients(0).ValidatorPubkeyProof( s.Ctx(), strconv.FormatUint(blockNumber-1, 10), strconv.FormatUint(validatorIndex2, 10), ) s.Require().NoError(err) s.Require().NotNil(pubkeyResp3) // Calculate the pubkey GIndex for validator 1 gIndex2 := zeroValidatorPubkeyGIndex + (validatorIndex2 * merkle.ValidatorGIndexOffset) // Verify the validator pubkey proof for validator 1 validatorPubkeyProof2 := make([][32]byte, len(pubkeyResp3.ValidatorPubkeyProof)) for i, proofItem := range pubkeyResp3.ValidatorPubkeyProof { validatorPubkeyProof2[i] = proofItem } err = sszTest.MustVerifyProof( &bind.CallOpts{Context: s.Ctx()}, validatorPubkeyProof2, pubkeyResp3.BeaconBlockRoot, pubkeyResp3.ValidatorPubkey.HashTreeRoot(), new(big.Int).SetUint64(gIndex2), ) s.Require().NoError(err) } ================================================ FILE: testing/e2e/standard/setup_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build e2e package standard_test import ( "testing" "github.com/berachain/beacon-kit/testing/e2e/suite" ) // BeaconE2ESuite is a suite of tests simulating a fully function beacon-kit // network. type BeaconKitE2ESuite struct { suite.KurtosisE2ESuite } // TestBeaconKitE2ESuite runs the test suite. func TestBeaconKitE2ESuite(t *testing.T) { suite.Run(t, new(BeaconKitE2ESuite)) } // TestBasicStartup tests the basic startup of the beacon-kit network. // TODO: Should check all clients, opposed to just the RPC client. func (s *BeaconKitE2ESuite) TestBasicStartup() { err := s.WaitForFinalizedBlockNumber(10) s.Require().NoError(err) } ================================================ FILE: testing/e2e/standard/staking_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build e2e package standard_test import ( "math/big" "github.com/attestantio/go-eth2-client/api" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/gethlib/deposit" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/testing/e2e/config" "github.com/berachain/beacon-kit/testing/e2e/suite/types" "github.com/cometbft/cometbft/crypto/bls12381" "github.com/ethereum/go-ethereum/accounts/abi/bind" gethcommon "github.com/ethereum/go-ethereum/common" coretypes "github.com/ethereum/go-ethereum/core/types" ) const ( // NumDepositsLoad is the number of deposits to load in the Deposit Robustness e2e test. NumDepositsLoad uint64 = 500 ) // Contains pre-test state for validator info to facilitate validation of the post-state. type ValidatorTestStruct struct { Index uint64 Power *big.Int WithdrawalBalance *big.Int WithdrawalCredentials [32]byte Name string Client *types.ConsensusClient } // TestDepositRobustness tests sending a large number of deposits txs to the Deposit Contract. // Then it checks whether all the validators' voting power have increased by the correct amount. // // TODO: // 1) Add staking tests for adding a new validator to the network. // 2) Add staking tests for hitting the validator set cap and eviction. func (s *BeaconKitE2ESuite) TestDepositRobustness() { // TODO: make test use configurable chain spec. chainSpec, err := spec.DevnetChainSpec() s.Require().NoError(err) weiPerGwei := big.NewInt(1e9) // This value is determined by the MIN_DEPOSIT_AMOUNT_IN_GWEI variable from the deposit contract. contractMinDepositAmountWei := big.NewInt(0).Mul(big.NewInt(10_000), big.NewInt(1e9*1e9)) depositAmountWei := new(big.Int).Mul(contractMinDepositAmountWei, big.NewInt(100)) depositAmountGwei := new(big.Int).Div(depositAmountWei, weiPerGwei) // Our deposits should be greater than the min deposit amount. s.Require().Equal(1, depositAmountWei.Cmp(contractMinDepositAmountWei)) s.Require().Equal( 0, int(NumDepositsLoad%config.NumValidators), "every validator must get an equal amount of deposits", ) // Get the execution client. elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) // Get the chain ID. chainID, err := elClient.ChainID(s.Ctx()) s.Require().NoError(err) // Bind the deposit contract. depositContractAddress := gethcommon.Address(chainSpec.DepositContractAddress()) dc, err := deposit.NewDepositContract(depositContractAddress, elClient) s.Require().NoError(err) // Enforce the deposit count at genesis is equal to the number of validators. depositCount, err := dc.DepositCount(&bind.CallOpts{ BlockNumber: big.NewInt(0), }) s.Require().NoError(err) s.Require().Equal(uint64(config.NumValidators), depositCount, "initial deposit count should match number of validators") // Check that the genesis deposits root is not empty. It is important that this value is // consistent across all EL nodes to ensure the EL has a consistent view of the CL deposits // at genesis. If the EL chain progresses past the genesis block, this is guaranteed. genesisRoot, err := dc.GenesisDepositsRoot(&bind.CallOpts{ BlockNumber: big.NewInt(0), }) s.Require().NoError(err) s.Require().False(genesisRoot == [32]byte{}) apiClient := s.ConsensusClients(0) s.Require().NotNil(apiClient) // Grab genesis validators to get withdrawal creds. response, err := apiClient.Validators(s.Ctx(), &api.ValidatorsOpts{ State: "genesis", Indices: []phase0.ValidatorIndex{0, 1, 2, 3, 4}, }) s.Require().NoError(err) s.Require().NotNil(response, "Validators response should not be nil") s.Require().NotNil(response.Data, "Validators data should not be nil") vals := response.Data s.Require().Len(vals, config.NumValidators) // Grab pre-state data for each validator. validators := make([]*ValidatorTestStruct, config.NumValidators) var idx uint64 for i := range config.NumValidators { client, name := s.ConsensusClients(i), config.ValidatorConsensusClientName(i) s.Require().NotNil(client) power, cErr := client.GetConsensusPower(s.Ctx()) s.Require().NoError(cErr) s.Require().Contains(vals, phase0.ValidatorIndex(idx)) val := vals[phase0.ValidatorIndex(idx)] s.Require().NotNil(val) s.Require().NotNil(val.Validator) creds := [32]byte(val.Validator.WithdrawalCredentials) withdrawalAddress := gethcommon.Address(creds[12:]) withdrawalBalance, jErr := elClient.BalanceAt(s.Ctx(), withdrawalAddress, nil) s.Require().NoError(jErr) // Populate the validators testing struct so we can keep track of the pre-state. validators[idx] = &ValidatorTestStruct{ Index: idx, Power: new(big.Int).SetUint64(power), WithdrawalBalance: withdrawalBalance, WithdrawalCredentials: creds, Name: name, Client: client, } idx++ } // Sender account sender := s.TestAccounts()[0] // Get the block num blkNum, err := elClient.BlockNumber(s.Ctx()) s.Require().NoError(err) // Get original evm balance balance, err := elClient.BalanceAt( s.Ctx(), sender.Address(), new(big.Int).SetUint64(blkNum), ) s.Require().NoError(err) // Get the nonce. nonce, err := elClient.NonceAt( s.Ctx(), sender.Address(), new(big.Int).SetUint64(blkNum), ) s.Require().NoError(err) var ( tx *coretypes.Transaction clientPubkey []byte pk *bls12381.PubKey signature [96]byte value = depositAmountWei signer = sender.SignerFunc(chainID) from = sender.Address() ) for i := range NumDepositsLoad { // Create a deposit transaction using the default validators' pubkeys. curVal := validators[i%config.NumValidators] clientPubkey, err = curVal.Client.GetPubKey(s.Ctx()) s.Require().NoError(err) pk, err = bls12381.NewPublicKeyFromBytes(clientPubkey) s.Require().NoError(err) pubkey := pk.Compress() s.Require().Len(pubkey, 48) // Only the first deposit for a pubkey has a non-zero operator. operator := gethcommon.Address{} if i < config.NumValidators { operator = from } tx, err = dc.Deposit(&bind.TransactOpts{ From: from, Value: value, Signer: signer, Nonce: new(big.Int).SetUint64(nonce + i), GasLimit: 1000000, Context: s.Ctx(), }, pubkey, curVal.WithdrawalCredentials[:], signature[:], operator) s.Require().NoError(err) s.Logger().Info("Deposit tx created", "num", i+1, "hash", tx.Hash().Hex(), "value", value) } // Wait for the final deposit tx to be mined. s.Logger().Info( "Waiting for the final deposit tx to be mined", "num", NumDepositsLoad, "hash", tx.Hash().Hex(), ) receipt, err := bind.WaitMined(s.Ctx(), elClient, tx) s.Require().NoError(err) s.Require().Equal(coretypes.ReceiptStatusSuccessful, receipt.Status) s.Logger().Info("Final deposit tx mined successfully", "hash", receipt.TxHash.Hex()) // Give time for the nodes to catch up. err = s.WaitForNBlockNumbers(NumDepositsLoad / chainSpec.MaxDepositsPerBlock()) s.Require().NoError(err) // Compare height of nodes 0 and 1 height, err := validators[0].Client.ABCIInfo(s.Ctx()) s.Require().NoError(err) height2, err := validators[1].Client.ABCIInfo(s.Ctx()) s.Require().NoError(err) s.Require().InDelta(height.LastBlockHeight, height2.LastBlockHeight, 1) // Check to see if evm balance decreased. postDepositBalance, err := elClient.BalanceAt(s.Ctx(), sender.Address(), nil) s.Require().NoError(err) // Check that the eth spent is somewhere~ (gas) between // (depositAmountWei * NumDepositsLoad, depositAmountWei * NumDepositsLoad + 2ether) lowerBound := new(big.Int).Mul(value, new(big.Int).SetUint64(NumDepositsLoad)) upperBound := new(big.Int).Add(lowerBound, big.NewInt(2e18)) amtSpent := new(big.Int).Sub(balance, postDepositBalance) s.Require().Equal(1, amtSpent.Cmp(lowerBound), "amount spent is less than lower bound") s.Require().Equal(-1, amtSpent.Cmp(upperBound), "amount spent is greater than upper bound") // Check that all validators' voting power have increased by // (NumDepositsLoad / NumValidators) * depositAmountWei // after the end of the epoch (next multiple of SlotsPerEpoch after receipt.BlockNumber). blkNum, err = elClient.BlockNumber(s.Ctx()) s.Require().NoError(err) nextEpoch := chainSpec.SlotToEpoch(math.Slot(blkNum)) + 1 nextEpochBlockNum := nextEpoch.Unwrap() * chainSpec.SlotsPerEpoch() err = s.WaitForFinalizedBlockNumber(nextEpochBlockNum + 1) s.Require().NoError(err) increaseAmt := new(big.Int).Mul(depositAmountGwei, big.NewInt(int64(NumDepositsLoad/config.NumValidators))) for _, val := range validators { // Consensus Power is in Gwei. powerAfterRaw, cErr := val.Client.GetConsensusPower(s.Ctx()) s.Require().NoError(cErr) powerAfter := new(big.Int).SetUint64(powerAfterRaw) powerDiff := new(big.Int).Sub(powerAfter, val.Power) // withdrawal balance is in Wei, so we'll convert it to Gwei. withdrawalAddress := gethcommon.Address(val.WithdrawalCredentials[12:]) withdrawalBalanceAfter, jErr := elClient.BalanceAt(s.Ctx(), withdrawalAddress, nil) s.Require().NoError(jErr) withdrawalDiff := new(big.Int).Sub(withdrawalBalanceAfter, val.WithdrawalBalance) withdrawalDiff.Div(withdrawalDiff, weiPerGwei) // TODO: currently the kurtosis devnet sets the withdrawal address the same for all validators. // We simply validate that the balance is NumValidators times larger than we expect it to be. withdrawalDiff.Div(withdrawalDiff, new(big.Int).SetUint64(config.NumValidators)) // Verify input balance is equal to the power + withdrawal balances. s.Require().Equal(increaseAmt, new(big.Int).Add(powerDiff, withdrawalDiff)) } } ================================================ FILE: testing/e2e/standard/withdrawal_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build e2e package standard_test import ( "context" "encoding/json" "errors" "fmt" "math/big" "strconv" beaconapi "github.com/attestantio/go-eth2-client/api" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/execution/requests/eip7002" "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/handlers/utils" "github.com/berachain/beacon-kit/primitives/crypto" beaconmath "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/testing/e2e/suite" e2etypes "github.com/berachain/beacon-kit/testing/e2e/suite/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" gethcore "github.com/ethereum/go-ethereum/core/types" ethcrypto "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" ) const ( // DefaultWithdrawalAmount is the default withdrawal amount in Gwei for testing DefaultWithdrawalAmount = 1_000_000_000 // 1 BERA (10^9 Gwei) // WithdrawalTxGasLimit is the gas limit for withdrawal transactions WithdrawalTxGasLimit = 500_000 // BlocksToWaitAfterWithdrawal is the number of blocks to wait after a withdrawal BlocksToWaitAfterWithdrawal = 3 ) // rpcWrapper wraps an rpc.Client and implements the rpcClient interface required by EIP7002. // Referenced from execution/requests/eip7002/interfaces.go type rpcWrapper struct { *rpc.Client } // Call implements the rpcClient interface. // Referenced from execution/requests/eip7002/interfaces.go func (r *rpcWrapper) Call(ctx context.Context, target any, method string, params ...any) error { return r.Client.CallContext(ctx, target, method, params...) } // getPendingPartialWithdrawals calls the beacon node's /eth/v1/beacon/states/{state_id}/pending_partial_withdrawals endpoint // and returns the list of pending withdrawals data if any func (s *BeaconKitE2ESuite) getPendingPartialWithdrawals(stateID string) ([]types.PendingPartialWithdrawalData, error) { client := s.initHTTPBeaconTest() url := fmt.Sprintf("/eth/v1/beacon/states/%s/pending_partial_withdrawals", stateID) resp, err := client.Get(url) if err != nil { return nil, fmt.Errorf("failed to get pending partial withdrawals: %w", err) } if resp == nil { return nil, errors.New("received nil response") } defer resp.Body.Close() var response types.PendingPartialWithdrawalsResponse decoder := json.NewDecoder(resp.Body) if err = decoder.Decode(&response); err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } // Validate response fields s.Require().Equal(response.Version, version.Name(version.Fulu())) // TODO: assert this is after Electra s.Require().False(response.ExecutionOptimistic) s.Require().True(response.Finalized) withdrawals, ok := response.Data.([]types.PendingPartialWithdrawalData) if !ok { // Only if direct type assertion fails, fall back to JSON remarshal dataBytes, errInMarshal := json.Marshal(response.Data) if errInMarshal != nil { return nil, fmt.Errorf("failed to marshal data: %w", errInMarshal) } if errInUnmarshal := json.Unmarshal(dataBytes, &withdrawals); errInUnmarshal != nil { return nil, fmt.Errorf("failed to unmarshal withdrawals: %w", errInUnmarshal) } } return withdrawals, nil } // findValidatorWithExecutionCredentials finds a validator with execution credentials // It returns the validator index and the BLS public key of the validator with execution credentials func (s *BeaconKitE2ESuite) findValidatorWithExecutionCredentials(client *e2etypes.ConsensusClient) (string, crypto.BLSPubkey, error) { // Get the validators to identify one with execution credentials (0x01) validatorsResp, err := client.Validators( s.Ctx(), &beaconapi.ValidatorsOpts{ State: utils.StateIDHead, }, ) if err != nil { return "", crypto.BLSPubkey{}, fmt.Errorf("failed to get validators: %w", err) } if len(validatorsResp.Data) == 0 { return "", crypto.BLSPubkey{}, errors.New("no validators found") } // Find a validator with execution withdrawal credentials (starting with 0x01) var validatorIndex string var blsPubkey crypto.BLSPubkey for _, validator := range validatorsResp.Data { credentials := validator.Validator.WithdrawalCredentials // Create beacon-kit's WithdrawalCredentials type var beaconKitCredentials ctypes.WithdrawalCredentials copy(beaconKitCredentials[:], credentials) // Check if it has execution withdrawal credentials if beaconKitCredentials.IsValidEth1WithdrawalCredentials() { validatorIndex = fmt.Sprintf("%d", validator.Index) // Convert the phase0.BLSPubKey to our crypto.BLSPubkey type copy(blsPubkey[:], validator.Validator.PublicKey[:]) return validatorIndex, blsPubkey, nil } } return "", crypto.BLSPubkey{}, errors.New("no validator with execution withdrawal credentials found") } // TestSubmitPartialWithdrawalTransaction tests submitting a partial withdrawal transaction via the withdrawal contract func (s *BeaconKitE2ESuite) TestSubmitPartialWithdrawalTransaction() { // Use timeout context to better control the test ctx, cancel := context.WithTimeout(s.Ctx(), suite.DefaultE2ETestTimeout) defer cancel() // Initialize test client client := s.initBeaconTest() // Find a validator with execution credentials validatorIndex, blsPubkey, err := s.findValidatorWithExecutionCredentials(client) s.Require().NoError(err) s.T().Logf("Found validator with index %s for withdrawal test", validatorIndex) // Set withdrawal amount withdrawalAmount := beaconmath.Gwei(DefaultWithdrawalAmount) // Create an rpc client using the EL client URL elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) rpcClient, err := rpc.Dial(elClient.URL()) s.Require().NoError(err) defer rpcClient.Close() rpcWrapper := &rpcWrapper{Client: rpcClient} // Get current block number before withdrawal blkNum, err := elClient.BlockNumber(ctx) s.Require().NoError(err) s.T().Logf("Block number before withdrawal: %d", blkNum) // Check for pending partial withdrawals before submitting the transaction pendingWithdrawalsBefore, err := s.getPendingPartialWithdrawals(utils.StateIDHead) s.Require().NoError(err) s.Require().Len(pendingWithdrawalsBefore, 0, "Expected no pending withdrawals initially") // Get the withdrawal fee fee, err := eip7002.GetWithdrawalFee(ctx, rpcWrapper) s.Require().NoError(err) s.T().Logf("Withdrawal fee: %s wei", fee.String()) // Create the withdrawal transaction data withdrawalTxData, err := eip7002.CreateWithdrawalRequestData(blsPubkey, withdrawalAmount) s.Require().NoError(err) // Use the private key of the withdrawal address of the validator used to submit the transaction privateKey, err := ethcrypto.HexToECDSA("fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306") s.Require().NoError(err) chainID, err := elClient.ChainID(ctx) s.Require().NoError(err) signer := gethcore.NewPragueSigner(chainID) // Get the sender's nonce var nonce hexutil.Uint64 // Use the address derived from the validator's withdrawal credentials. // In kurtosis we use the same withdrawal address for all validators. err = rpcClient.CallContext(ctx, &nonce, "eth_getTransactionCount", common.HexToAddress("0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4"), "latest", ) s.Require().NoError(err) // Create and sign the transaction tx := gethcore.MustSignNewTx(privateKey, signer, &gethcore.DynamicFeeTx{ ChainID: chainID, Nonce: uint64(nonce), To: ¶ms.WithdrawalQueueAddress, Gas: WithdrawalTxGasLimit, GasFeeCap: big.NewInt(10000000000), GasTipCap: big.NewInt(10000000000), Value: fee, Data: withdrawalTxData, }) // Serialize the transaction txBytes, err := tx.MarshalBinary() s.Require().NoError(err) // Send the transaction var txHash common.Hash err = rpcClient.CallContext(ctx, &txHash, "eth_sendRawTransaction", hexutil.Encode(txBytes)) s.Require().NoError(err) s.T().Logf("Withdrawal transaction submitted: %s", txHash.Hex()) // Wait for blocks to be mined after submitting the transaction err = s.WaitForNBlockNumbers(BlocksToWaitAfterWithdrawal) s.Require().NoError(err) // Get the transaction receipt receipt, err := elClient.TransactionReceipt(ctx, txHash) s.Require().NoError(err) s.Require().NotNil(receipt, "Transaction receipt should not be nil") s.T().Logf("Withdrawal transaction included in block: %d", receipt.BlockNumber) // Check for pending partial withdrawals after submitting the transaction pendingWithdrawalsAfter, err := s.getPendingPartialWithdrawals(utils.StateIDHead) s.Require().NoError(err) s.Require().Len(pendingWithdrawalsAfter, 1, "Expected one pending withdrawal after transaction") // Verify the withdrawal details s.Require().Equal(validatorIndex, strconv.FormatUint(pendingWithdrawalsAfter[0].ValidatorIndex, 10), "Validator index mismatch in pending withdrawal") s.Require().Equal(uint64(withdrawalAmount), pendingWithdrawalsAfter[0].Amount, "Withdrawal amount mismatch in pending withdrawal") } ================================================ FILE: testing/e2e/suite/constants.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package suite import ( "time" "github.com/ethereum/go-ethereum/params" ) // Ether represents the number of wei in one ether, used for Ethereum // transactions. const ( Ether = params.Ether TenGwei = 10 * params.GWei // 10 Gwei = 1e10 wei ) // EtherTransferGasLimit specifies the gas limit for a standard Ethereum // transfer. // This is the amount of gas required to perform a basic ether transfer. const ( EtherTransferGasLimit uint64 = 21000 // Standard gas limit for ether transfer ) // DefaultE2ETestTimeout defines the default timeout duration for end-to-end // tests. This is used to specify how long to wait for a test before considering // it failed. const ( DefaultE2ETestTimeout = 60 * 10 * time.Second // timeout for E2E tests ) ================================================ FILE: testing/e2e/suite/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package suite import "github.com/berachain/beacon-kit/errors" // ErrUnexpectedBalance is returned when the balance is unexpected. var ErrUnexpectedBalance = errors.New("unexpected balance") ================================================ FILE: testing/e2e/suite/options.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package suite // Option is a functional option for the KurtosisE2ESuite. type Option func(*KurtosisE2ESuite) error ================================================ FILE: testing/e2e/suite/setup.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package suite import ( "context" "crypto/ecdsa" "fmt" "math/big" "os/exec" "path/filepath" "runtime" "sync/atomic" "time" "cosmossdk.io/log" "github.com/berachain/beacon-kit/errors" "github.com/berachain/beacon-kit/testing/e2e/config" "github.com/berachain/beacon-kit/testing/e2e/suite/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rpc" "github.com/kurtosis-tech/kurtosis/api/golang/core/lib/starlark_run_config" "github.com/kurtosis-tech/kurtosis/api/golang/engine/lib/kurtosis_context" "github.com/sourcegraph/conc/iter" ) // SetupSuite executes before the test suite begins execution. func (s *KurtosisE2ESuite) SetupSuite() { s.SetupSuiteWithOptions() } // SetupSuiteWithOptions sets up the test suite with the provided options. // //nolint:funlen // setup suite has many responsibilities... func (s *KurtosisE2ESuite) SetupSuiteWithOptions(opts ...Option) { var ( key0, key1, key2 *ecdsa.PrivateKey err error ) // Setup some sane defaults. s.cfg = config.DefaultE2ETestConfig() s.ctx = context.Background() s.logger = log.NewTestLogger(s.T()) s.Require().NoError(err, "Error loading starlark helper file") s.testAccounts = make([]*types.EthAccount, 3) //nolint:mnd // number of accounts. s.genesisAccount = types.NewEthAccountFromHex( "genesisAccount", "fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306", ) key0, err = crypto.GenerateKey() s.Require().NoError(err, "Error generating key") key1, err = crypto.GenerateKey() s.Require().NoError(err, "Error generating key") key2, err = crypto.GenerateKey() s.Require().NoError(err, "Error generating key") s.testAccounts[0] = types.NewEthAccount("testAccount0", key0) s.testAccounts[1] = types.NewEthAccount("testAccount1", key1) s.testAccounts[2] = types.NewEthAccount("testAccount2", key2) // Apply all the provided options, this allows // the test suite to be configured in a flexible manner by // the caller (i.e. overriding defaults). for _, opt := range opts { if err = opt(s); err != nil { s.Require().NoError(err, "Error applying option") } } s.kCtx, err = kurtosis_context.NewKurtosisContextFromLocalEngine() s.Require().NoError(err) s.logger.Info("Destroying any existing enclave...") //#nosec:G703 // It's okay if this errors out. It will error out // if there is no enclave to destroy. _ = s.kCtx.DestroyEnclave(s.ctx, "e2e-test-enclave") // Restart the engine to clear any stale state (equivalent to `kurtosis engine restart`) cmd := exec.CommandContext(s.ctx, "kurtosis", "engine", "restart") out, restartErr := cmd.CombinedOutput() s.logger.Info("Kurtosis engine restart", "output", string(out)) s.Require().NoError(restartErr, "Failed to restart kurtosis engine") // Re-connect after restart since the engine process changed s.kCtx, err = kurtosis_context.NewKurtosisContextFromLocalEngine() s.Require().NoError(err) s.logger.Info("Creating enclave...") s.enclave, err = s.kCtx.CreateEnclave(s.ctx, "e2e-test-enclave") s.Require().NoError(err) s.logger.Info( "Spinning up enclave...", "num_validators", len(s.cfg.NetworkConfiguration.Validators.Nodes), "num_full_nodes", len(s.cfg.NetworkConfiguration.FullNodes.Nodes), ) _, thisFile, _, ok := runtime.Caller(0) s.Require().True(ok, "could not determine source file path") kurtosisDir := filepath.Join(filepath.Dir(thisFile), "..", "..", "..", "kurtosis") result, err := s.enclave.RunStarlarkPackageBlocking( s.ctx, kurtosisDir, starlark_run_config.NewRunStarlarkConfig( starlark_run_config.WithSerializedParams(s.cfg.MustMarshalJSON()), ), ) s.Require().NoError(err, "Error running Starlark package") s.Require().Nil(result.ExecutionError, "Error running Starlark package") s.Require().Empty(result.ValidationErrors) s.logger.Info("Enclave spun up successfully") s.logger.Info("Setting up consensus clients") err = s.SetupConsensusClients(s.ctx) s.Require().NoError(err, "Error setting up consensus clients") // Setup the JSON-RPC Execution Clients. s.logger.Info("Setting up JSON-RPC Execution Clients") err = s.SetupExecutionClients(s.ctx) s.Require().NoError(err, "Error setting up JSON-RPC Execution Clients") s.logger.Info("Waiting for nodes to get ready...") //nolint:mnd // its okay. time.Sleep(5 * time.Second) // Wait for the finalized block number to increase a bit to // ensure all clients are in sync. //nolint:mnd // 3 blocks err = s.WaitForFinalizedBlockNumber(3) s.Require().NoError(err, "Error waiting for finalized block number") // Fund any requested accounts. s.FundAccounts() } // SetupConsensusClients sets up the consensus clients for the validator nodes. // // TODO: set up consensus clients for full nodes as well. func (s *KurtosisE2ESuite) SetupConsensusClients(ctx context.Context) error { s.consensusClients = make(map[string]*types.ConsensusClient, config.NumValidators) for i := range config.NumValidators { clientName := config.ValidatorConsensusClientName(i) sCtx, err := s.Enclave().GetServiceContext(clientName) if err != nil { return err } s.consensusClients[clientName] = types.NewConsensusClient(sCtx) if err = s.consensusClients[clientName].Start(ctx); err != nil { return err } } return nil } // SetupExecutionClients sets up the execution clients for the full nodes. // // TODO: set up execution clients for validators as well. func (s *KurtosisE2ESuite) SetupExecutionClients(ctx context.Context) error { s.executionClients = make(map[string]*types.ExecutionClient, config.NumFullNodes) for i := range config.NumFullNodes { clientName := config.FullNodeExecutionClientName(i) sCtx, err := s.Enclave().GetServiceContext(clientName) if err != nil { return err } s.executionClients[clientName] = types.NewExecutionClient(sCtx) if err = s.executionClients[clientName].Start(ctx); err != nil { return err } } return nil } // FundAccounts funds the accounts for the test suite. // //nolint:funlen func (s *KurtosisE2ESuite) FundAccounts() { ctx := context.Background() nonce := atomic.Uint64{} elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) pendingNonce, err := elClient.PendingNonceAt( ctx, s.genesisAccount.Address()) s.Require().NoError(err, "Failed to get nonce for genesis account") nonce.Store(pendingNonce) var chainID *big.Int chainID, err = elClient.ChainID(ctx) s.Require().NoError(err, "failed to get chain ID") s.logger.Info("Chain-id is", "chain_id", chainID) _, err = iter.MapErr( s.testAccounts, func(acc **types.EthAccount) (*ethtypes.Receipt, error) { account := *acc var gasTipCap *big.Int if gasTipCap, err = elClient.SuggestGasTipCap(ctx); err != nil { var rpcErr rpc.Error if errors.As(err, &rpcErr) && rpcErr.ErrorCode() == -32601 { // Fallback to default value of 10 Gwei if method not supported gasTipCap = big.NewInt(0).SetUint64(TenGwei) } else { return nil, err } } gasFeeCap := new(big.Int).Add( gasTipCap, big.NewInt(0).SetUint64(TenGwei)) nonceToSubmit := nonce.Add(1) - 1 //nolint:mnd // 2_000_000_000 Ether value := new(big.Int).Mul(big.NewInt(2_000_000_000), big.NewInt(Ether)) dest := account.Address() var signedTx *ethtypes.Transaction if signedTx, err = s.genesisAccount.SignTx( chainID, ethtypes.NewTx(ðtypes.DynamicFeeTx{ ChainID: chainID, Nonce: nonceToSubmit, GasTipCap: gasTipCap, GasFeeCap: gasFeeCap, Gas: EtherTransferGasLimit, To: &dest, Value: value, Data: nil, }), ); err != nil { return nil, err } cctx, cancel := context.WithTimeout(ctx, DefaultE2ETestTimeout) defer cancel() if err = elClient.SendTransaction(cctx, signedTx); err != nil { s.logger.Error( "error submitting funding transaction", "error", err, ) return nil, err } s.logger.Info( "Funding transaction submitted, waiting for confirmation...", "tx_hash", signedTx.Hash().Hex(), "nonce", nonceToSubmit, "account", account.Name(), "value", value, ) var receipt *ethtypes.Receipt if receipt, err = bind.WaitMined( cctx, elClient, signedTx, ); err != nil { return nil, err } s.logger.Info( "Funding transaction confirmed", "tx_hash", signedTx.Hash().Hex(), "account", account.Name(), ) // Verify the receipt status. if receipt.Status != ethtypes.ReceiptStatusSuccessful { return nil, err } // Wait an extra block to ensure all clients are in sync. //nolint:mnd,contextcheck // its okay. if err = s.WaitForFinalizedBlockNumber( receipt.BlockNumber.Uint64() + 2, ); err != nil { return nil, err } // Verify the balance of the account var balance *big.Int if balance, err = elClient.BalanceAt(ctx, dest, nil); err != nil { return nil, err } else if balance.Cmp(value) != 0 { return nil, errors.Wrap( ErrUnexpectedBalance, fmt.Sprintf("expected: %v, got: %v", value, balance), ) } return receipt, nil }, ) s.Require().NoError(err, "Error funding accounts") } // WaitForFinalizedBlockNumber waits for the finalized block number // to reach the target block number across all execution clients. func (s *KurtosisE2ESuite) WaitForFinalizedBlockNumber(target uint64) error { cctx, cancel := context.WithTimeout(s.ctx, DefaultE2ETestTimeout) defer cancel() ticker := time.NewTicker(time.Second) defer ticker.Stop() elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) finalBlockNum, err := elClient.BlockNumber(cctx) if err != nil { s.logger.Error("error getting finalized block number", "error", err) } for finalBlockNum < target { // check if cctx deadline is exceeded to prevent endless loop select { case <-cctx.Done(): return cctx.Err() default: } finalBlockNum, err = elClient.BlockNumber(cctx) if err != nil { s.logger.Error("error getting finalized block number", "error", err) continue } s.logger.Info( "Waiting for finalized block number to reach target", "target", target, "finalized", finalBlockNum, ) select { case <-s.ctx.Done(): return s.ctx.Err() case <-ticker.C: continue } } s.logger.Info( "Finalized block number reached target 🎉", "target", target, "finalized", finalBlockNum, ) return nil } // WaitForNBlockNumbers waits for a specified amount of blocks into the future // from now. func (s *KurtosisE2ESuite) WaitForNBlockNumbers(n uint64) error { elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) current, err := elClient.BlockNumber(s.ctx) if err != nil { return err } return s.WaitForFinalizedBlockNumber(current + n) } // TearDownSuite cleans up resources after all tests have been executed. // this function executes after all tests executed. func (s *KurtosisE2ESuite) TearDownSuite() { s.Logger().Info("Destroying enclave...") for _, client := range s.consensusClients { client.Stop(s.ctx) } s.Require().NoError(s.kCtx.DestroyEnclave(s.ctx, "e2e-test-enclave")) } // CheckForSuccessfulTx returns true if the transaction was successful. func (s *KurtosisE2ESuite) CheckForSuccessfulTx(tx common.Hash) bool { ctx, cancel := context.WithTimeout(s.Ctx(), DefaultE2ETestTimeout) defer cancel() elClient := s.ExecutionClients(0) s.Require().NotNil(elClient) receipt, err := elClient.TransactionReceipt(ctx, tx) if err != nil { s.Logger().Error("Error getting transaction receipt", "error", err) return false } return receipt.Status == ethtypes.ReceiptStatusSuccessful } ================================================ FILE: testing/e2e/suite/suite.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package suite import ( "context" "github.com/berachain/beacon-kit/log" "github.com/berachain/beacon-kit/testing/e2e/config" "github.com/berachain/beacon-kit/testing/e2e/suite/types" "github.com/kurtosis-tech/kurtosis/api/golang/core/lib/enclaves" "github.com/kurtosis-tech/kurtosis/api/golang/engine/lib/kurtosis_context" "github.com/stretchr/testify/suite" ) // Run is an alias for suite.Run to help with importing // in other packages. // //nolint:gochecknoglobals // intentionally. var Run = suite.Run // KurtosisE2ESuite. type KurtosisE2ESuite struct { suite.Suite cfg *config.E2ETestConfig logger log.Logger ctx context.Context kCtx *kurtosis_context.KurtosisContext enclave *enclaves.EnclaveContext consensusClients map[string]*types.ConsensusClient executionClients map[string]*types.ExecutionClient genesisAccount *types.EthAccount testAccounts []*types.EthAccount } // Config returns the E2ETestConfig associated with the KurtosisE2ESuite. func (s *KurtosisE2ESuite) Config() *config.E2ETestConfig { return s.cfg } // ConsensusClients returns the consensus client for the given validator number. func (s *KurtosisE2ESuite) ConsensusClients(numValidator int) *types.ConsensusClient { return s.consensusClients[config.ValidatorConsensusClientName(numValidator)] } // Ctx returns the context associated with the KurtosisE2ESuite. // This context is used throughout the suite to control the flow of operations, // including timeouts and cancellations. func (s *KurtosisE2ESuite) Ctx() context.Context { return s.ctx } // Enclave returns the enclave running the beacon-kit network. func (s *KurtosisE2ESuite) Enclave() *enclaves.EnclaveContext { return s.enclave } // ExecutionClients returns the execution client for the given full node number. func (s *KurtosisE2ESuite) ExecutionClients(numFullNode int) *types.ExecutionClient { return s.executionClients[config.FullNodeExecutionClientName(numFullNode)] } // GenesisAccount returns the genesis account for the test suite. func (s *KurtosisE2ESuite) GenesisAccount() *types.EthAccount { return s.genesisAccount } // KurtosisCtx returns the KurtosisContext associated with the KurtosisE2ESuite. // The KurtosisContext is a critical component that facilitates interaction with // the Kurtosis testnet, including creating and managing enclaves. func (s *KurtosisE2ESuite) KurtosisCtx() *kurtosis_context.KurtosisContext { return s.kCtx } // Logger returns the logger for the test suite. func (s *KurtosisE2ESuite) Logger() log.Logger { return s.logger } // TestAccounts returns the test accounts for the test suite. func (s *KurtosisE2ESuite) TestAccounts() []*types.EthAccount { return s.testAccounts } ================================================ FILE: testing/e2e/suite/types/account.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "crypto/ecdsa" "math/big" "github.com/berachain/beacon-kit/errors" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" ) // EthAccount represents an Ethereum account. type EthAccount struct { name string pk *ecdsa.PrivateKey } // NewEthAccountFromHex creates a new Ethereum account from hex private key. func NewEthAccountFromHex( name string, hexPk string, ) *EthAccount { pk, err := crypto.HexToECDSA(hexPk) if err != nil { panic(err) } return &EthAccount{ name: name, pk: pk, } } // NewEthAccount creates a new Ethereum account. func NewEthAccount( name string, pk *ecdsa.PrivateKey, ) *EthAccount { return &EthAccount{ name: name, pk: pk, } } // Name returns the name of the account. func (a EthAccount) Name() string { return a.name } // SignTx signs a transaction with the account's private key. func (a EthAccount) SignTx( chainID *big.Int, tx *types.Transaction, ) (*types.Transaction, error) { return types.SignTx( tx, types.LatestSignerForChainID(chainID), a.pk, ) } // SignerFunc returns a signer function for the account. func (a EthAccount) SignerFunc(chainID *big.Int) bind.SignerFn { return func( addr common.Address, tx *types.Transaction, ) (*types.Transaction, error) { if addr != a.Address() { return nil, errors.New("account not authorized to sign") } return a.SignTx(chainID, tx) } } // PublicKey returns the public key of the account. func (a EthAccount) PublicKey() *ecdsa.PublicKey { return &a.pk.PublicKey } // PrivateKey returns the private key of the account. func (a EthAccount) PrivateKey() *ecdsa.PrivateKey { return a.pk } // Address returns the address of the account. func (a EthAccount) Address() common.Address { return crypto.PubkeyToAddress(a.pk.PublicKey) } ================================================ FILE: testing/e2e/suite/types/account_test.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types_test import ( "testing" "github.com/berachain/beacon-kit/testing/e2e/suite/types" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) func TestNewEthAccount(t *testing.T) { t.Parallel() name := "testAccount" hexPk := "f561d45d1df30a6556d30e39f97011faa3632e43cd378224ad6cc83bb8aea3e6" account := types.NewEthAccountFromHex(name, hexPk) require.NotNil(t, account.PrivateKey()) require.Equal(t, name, account.Name()) } func TestEthAccount_PublicKey(t *testing.T) { t.Parallel() hexPk := "f561d45d1df30a6556d30e39f97011faa3632e43cd378224ad6cc83bb8aea3e6" expectedPrivateKey, _ := crypto.HexToECDSA(hexPk) require.NotNil(t, expectedPrivateKey) account := types.NewEthAccountFromHex("testAccount", hexPk) publicKey := account.PublicKey() require.Equal(t, expectedPrivateKey.PublicKey, *publicKey) } func TestEthAccount_Address(t *testing.T) { t.Parallel() hexPk := "f561d45d1df30a6556d30e39f97011faa3632e43cd378224ad6cc83bb8aea3e6" account := types.NewEthAccountFromHex("testAccount", hexPk) address := account.Address() expectedAddress := common.HexToAddress( "0x9e0437E86fE55b4D6Bb1191CbACdA384775fF63D", ) require.Equal(t, expectedAddress, address) } ================================================ FILE: testing/e2e/suite/types/beacon_client.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "context" "encoding/json" "fmt" "net/http" "strings" client "github.com/attestantio/go-eth2-client" beaconapi "github.com/attestantio/go-eth2-client/api" apiv1 "github.com/attestantio/go-eth2-client/api/v1" beaconhttp "github.com/attestantio/go-eth2-client/http" "github.com/attestantio/go-eth2-client/spec/phase0" ptypes "github.com/berachain/beacon-kit/node-api/handlers/proof/types" "github.com/pkg/errors" ) // BeaconKitNodeClient is a wrapper around the client.Service interface to add // additional methods specific to a beacon-kit node's API. type BeaconKitNodeClient interface { client.Service client.FarFutureEpochProvider client.SignedBeaconBlockProvider client.BlobSidecarsProvider client.BeaconCommitteesProvider client.SyncCommitteesProvider client.AggregateAttestationProvider client.AggregateAttestationsSubmitter client.AttestationDataProvider client.AttestationPoolProvider client.AttestationsSubmitter client.AttesterSlashingSubmitter client.AttesterDutiesProvider client.SyncCommitteeDutiesProvider client.SyncCommitteeMessagesSubmitter client.SyncCommitteeSubscriptionsSubmitter client.SyncCommitteeContributionProvider client.SyncCommitteeContributionsSubmitter client.BLSToExecutionChangesSubmitter client.BeaconBlockHeadersProvider client.ProposalProvider client.ProposalSlashingSubmitter client.BeaconBlockRootProvider client.ProposalSubmitter client.BeaconCommitteeSubscriptionsSubmitter client.BeaconStateProvider client.BeaconStateRandaoProvider client.BeaconStateRootProvider client.BlindedProposalSubmitter client.ValidatorRegistrationsSubmitter client.EventsProvider client.FinalityProvider client.ForkChoiceProvider client.ForkProvider client.ForkScheduleProvider client.GenesisProvider client.NodePeersProvider client.NodeSyncingProvider client.NodeVersionProvider client.ProposalPreparationsSubmitter client.ProposerDutiesProvider client.SpecProvider client.ValidatorBalancesProvider client.ValidatorsProvider client.VoluntaryExitSubmitter client.VoluntaryExitPoolProvider client.DomainProvider client.NodeClientProvider // BlockProposerProof calls `bkit/v1/proof/block_proposer/:timestamp_id` endpoint to get // the merkle proofs that can be used to verify the block proposer for a given timestamp id. BlockProposerProof( ctx context.Context, timestampID string, ) (*ptypes.BlockProposerResponse, error) // ValidatorBalanceProof calls `bkit/v1/proof/validator_balance/:timestamp_id/:validator_index` endpoint to get // the merkle proofs that can be used to verify the validator balance for a given timestamp id and validator index. ValidatorBalanceProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorBalanceResponse, error) // ValidatorCredentialsProof calls `bkit/v1/proof/validator_credentials/:timestamp_id/:validator_index` endpoint to get // the merkle proofs that can be used to verify the validator withdrawal credentials for a given timestamp id and validator index. ValidatorCredentialsProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorWithdrawalCredentialsResponse, error) // ValidatorPubkeyProof calls `bkit/v1/proof/validator_pubkey/:timestamp_id/:validator_index` endpoint to get // the merkle proof that can be used to verify the validator pubkey for a given timestamp id and validator index. ValidatorPubkeyProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorPubkeyResponse, error) } // customBeaconClient is a custom implementation of the BeaconKitNodeClient interface // that overrides the Validators method to handle deneb1. type customBeaconClient struct { *beaconhttp.Service address string client *http.Client } // NewBeaconKitNodeClient creates a new beacon-kit node-api client instance // with the given cancel context. func NewBeaconKitNodeClient( cancelCtx context.Context, params ...beaconhttp.Parameter, ) (BeaconKitNodeClient, error) { service, err := beaconhttp.New( cancelCtx, params..., ) if err != nil { return nil, err } if service == nil { return nil, errors.New("service is nil") } address := service.Address() if address == "" { return nil, errors.New("no address specified") } // Type assert service to beaconhttp.Service httpService, ok := service.(*beaconhttp.Service) if !ok { return nil, errors.New("failed to cast service to beaconhttp.Service") } return &customBeaconClient{ Service: httpService, address: address, client: &http.Client{}, }, nil } // Validators implements a custom validator query that handles deneb1. func (c *customBeaconClient) Validators( ctx context.Context, opts *beaconapi.ValidatorsOpts, ) (*beaconapi.Response[map[phase0.ValidatorIndex]*apiv1.Validator], error) { if opts == nil { return nil, errors.New("no options specified") } if opts.State == "" { return nil, errors.New("no state specified") } // Construct the URL url := fmt.Sprintf("%s/eth/v1/beacon/states/%s/validators", c.address, opts.State) params := make([]string, 0) // Add indices for _, idx := range opts.Indices { params = append(params, fmt.Sprintf("id=%d", idx)) } // Add pubkeys for _, key := range opts.PubKeys { params = append(params, fmt.Sprintf("id=%s", key)) } // Add validator states for _, state := range opts.ValidatorStates { params = append(params, fmt.Sprintf("status=%s", state)) } if len(params) > 0 { url = fmt.Sprintf("%s?%s", url, strings.Join(params, "&")) } // Make GET request for empty indices req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } resp, err := c.client.Do(req) //#nosec:G704 // URL is from trusted test infrastructure. if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } if resp == nil { return nil, errors.New("received nil response") } defer resp.Body.Close() // Parse response var result struct { Data []*apiv1.Validator `json:"data"` ExecutionOptimistic bool `json:"execution_optimistic"` Finalized bool `json:"finalized"` } if err = json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } // Convert array to map validators := make(map[phase0.ValidatorIndex]*apiv1.Validator) for _, v := range result.Data { validators[v.Index] = v } return &beaconapi.Response[map[phase0.ValidatorIndex]*apiv1.Validator]{ Data: validators, Metadata: map[string]any{ "execution_optimistic": result.ExecutionOptimistic, "finalized": result.Finalized, }, }, nil } // BlockProposerProof calls `bkit/v1/proof/block_proposer/:timestamp_id` endpoint to get // the merkle proofs that can be used to verify the block proposer for a given timestamp id. func (c *customBeaconClient) BlockProposerProof( ctx context.Context, timestampID string, ) (*ptypes.BlockProposerResponse, error) { url := fmt.Sprintf("%s/bkit/v1/proof/block_proposer/%s", c.address, timestampID) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } resp, err := c.client.Do(req) //#nosec:G704 // URL is from trusted test infrastructure. if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } if resp == nil { return nil, errors.New("received nil response") } defer resp.Body.Close() var result ptypes.BlockProposerResponse if err = json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } return &result, nil } // ValidatorBalanceProof calls `bkit/v1/proof/validator_balance/:timestamp_id/:validator_index` endpoint to get // the merkle proofs that can be used to verify the validator balance for a given timestamp id and validator index. func (c *customBeaconClient) ValidatorBalanceProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorBalanceResponse, error) { url := fmt.Sprintf("%s/bkit/v1/proof/validator_balance/%s/%s", c.address, timestampID, validatorIndex) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } resp, err := c.client.Do(req) //#nosec:G704 // URL is from trusted test infrastructure. if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } if resp == nil { return nil, errors.New("received nil response") } defer resp.Body.Close() var result ptypes.ValidatorBalanceResponse if err = json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } return &result, nil } // ValidatorCredentialsProof calls `bkit/v1/proof/validator_credentials/:timestamp_id/:validator_index` endpoint to get // the merkle proofs that can be used to verify the validator withdrawal credentials for a given timestamp id and validator index. func (c *customBeaconClient) ValidatorCredentialsProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorWithdrawalCredentialsResponse, error) { url := fmt.Sprintf("%s/bkit/v1/proof/validator_credentials/%s/%s", c.address, timestampID, validatorIndex) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } resp, err := c.client.Do(req) //#nosec:G704 // URL is from trusted test infrastructure. if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } if resp == nil { return nil, errors.New("received nil response") } defer resp.Body.Close() var result ptypes.ValidatorWithdrawalCredentialsResponse if err = json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } return &result, nil } // ValidatorPubkeyProof calls `bkit/v1/proof/validator_pubkey/:timestamp_id/:validator_index` endpoint to get // the merkle proof that can be used to verify the validator pubkey for a given timestamp id and validator index. func (c *customBeaconClient) ValidatorPubkeyProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorPubkeyResponse, error) { url := fmt.Sprintf("%s/bkit/v1/proof/validator_pubkey/%s/%s", c.address, timestampID, validatorIndex) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, fmt.Errorf("failed to create request: %w", err) } resp, err := c.client.Do(req) //#nosec:G704 // URL is from trusted test infrastructure. if err != nil { return nil, fmt.Errorf("failed to send request: %w", err) } if resp == nil { return nil, errors.New("received nil response") } defer resp.Body.Close() var result ptypes.ValidatorPubkeyResponse if err = json.NewDecoder(resp.Body).Decode(&result); err != nil { return nil, fmt.Errorf("failed to decode response: %w", err) } return &result, nil } ================================================ FILE: testing/e2e/suite/types/consensus_client.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "context" "fmt" beaconapi "github.com/attestantio/go-eth2-client/api" apiv1 "github.com/attestantio/go-eth2-client/api/v1" beaconhttp "github.com/attestantio/go-eth2-client/http" "github.com/attestantio/go-eth2-client/spec/deneb" "github.com/attestantio/go-eth2-client/spec/phase0" "github.com/berachain/beacon-kit/errors" ptypes "github.com/berachain/beacon-kit/node-api/handlers/proof/types" abcitypes "github.com/cometbft/cometbft/abci/types" rpcclient "github.com/cometbft/cometbft/rpc/client" httpclient "github.com/cometbft/cometbft/rpc/client/http" coretypes "github.com/cometbft/cometbft/rpc/core/types" "github.com/kurtosis-tech/kurtosis/api/golang/core/lib/services" "github.com/rs/zerolog" ) // ConsensusClient represents a consensus client. type ConsensusClient struct { *services.ServiceContext // Comet JSON-RPC client cometClient rpcclient.Client // Beacon node-api client beaconClient BeaconKitNodeClient // Cancel function for the context cancelFunc context.CancelFunc } // NewConsensusClient creates a new consensus client. func NewConsensusClient(serviceCtx *services.ServiceContext) *ConsensusClient { return &ConsensusClient{ ServiceContext: serviceCtx, } } // Start starts the consensus client. func (cc *ConsensusClient) Start(ctx context.Context) error { // Start by trying to get the public port for the comet JSON-RPC. cometPort, ok := cc.GetPublicPorts()["cometbft-rpc"] if !ok { return ErrPublicPortNotFound } clientURL := fmt.Sprintf("http://0.0.0.0:%d", cometPort.GetNumber()) client, err := httpclient.New(clientURL) if err != nil { return err } cc.cometClient = client // Then try to get the public port for the node API. nodePort, ok := cc.GetPublicPorts()["node-api"] if !ok { return ErrPublicPortNotFound } cancelCtx, cancel := context.WithCancel(ctx) cc.beaconClient, err = NewBeaconKitNodeClient( cancelCtx, beaconhttp.WithAddress( fmt.Sprintf("http://0.0.0.0:%d", nodePort.GetNumber()), ), beaconhttp.WithLogLevel(zerolog.DebugLevel), ) if err != nil { cancel() return err } cc.cancelFunc = cancel return nil } // Stop stops the consensus client. func (cc *ConsensusClient) Stop(context.Context) { if cc.cancelFunc != nil { cc.cancelFunc() } } // GetPubKey returns the public key of the validator running on this node. func (cc *ConsensusClient) GetPubKey(ctx context.Context) ([]byte, error) { res, err := cc.cometClient.Status(ctx) if err != nil { return nil, err } else if res.ValidatorInfo.PubKey == nil { return nil, errors.New("node public key is nil") } return res.ValidatorInfo.PubKey.Bytes(), nil } // GetConsensusPower returns the consensus power of the node. func (cc *ConsensusClient) GetConsensusPower(ctx context.Context) (uint64, error) { res, err := cc.cometClient.Status(ctx) if err != nil { return 0, err } // #nosec G115 -- VotingPower won't ever be negative. return uint64(res.ValidatorInfo.VotingPower), nil } // IsActive returns true if the node is an active validator. func (cc *ConsensusClient) IsActive(ctx context.Context) (bool, error) { res, err := cc.cometClient.Status(ctx) if err != nil { return false, err } return res.ValidatorInfo.VotingPower > 0, nil } // ABCIInfo returns the ABCI info of the node. func (cc ConsensusClient) ABCIInfo( ctx context.Context, ) (*abcitypes.InfoResponse, error) { if cc.cometClient == nil { return nil, errors.New("comet client is not initialized") } resp, err := cc.cometClient.ABCIInfo(ctx) if err != nil { return nil, err } return &resp.Response, nil } // ABCIQuery returns the ABCI query from the comet node. func (cc ConsensusClient) ABCIQuery( ctx context.Context, path string, data []byte, opts rpcclient.ABCIQueryOptions, ) (*abcitypes.QueryResponse, error) { if cc.cometClient == nil { return nil, errors.New("comet client is not initialized") } resp, err := cc.cometClient.ABCIQueryWithOptions(ctx, path, data, opts) if err != nil { return nil, err } return &resp.Response, nil } // BeaconStateRoot returns the beacon state root of the node. func (cc ConsensusClient) BeaconStateRoot( ctx context.Context, opts *beaconapi.BeaconStateRootOpts, ) (*beaconapi.Response[*phase0.Root], error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.BeaconStateRoot(ctx, opts) } // Validators returns the validator. func (cc ConsensusClient) Validators( ctx context.Context, opts *beaconapi.ValidatorsOpts, ) (*beaconapi.Response[map[phase0.ValidatorIndex]*apiv1.Validator], error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.Validators(ctx, opts) } // BlobSidecars returns the blob sidecars for a given block. func (cc ConsensusClient) BlobSidecars( ctx context.Context, opts *beaconapi.BlobSidecarsOpts, ) (*beaconapi.Response[[]*deneb.BlobSidecar], error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.BlobSidecars(ctx, opts) } // ValidatorBalances returns the validator balances for a given state. func (cc ConsensusClient) ValidatorBalances( ctx context.Context, opts *beaconapi.ValidatorBalancesOpts, ) (*beaconapi.Response[map[phase0.ValidatorIndex]phase0.Gwei], error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.ValidatorBalances(ctx, opts) } // Genesis returns the genesis of the beacon node. func (cc ConsensusClient) Genesis( ctx context.Context, opts *beaconapi.GenesisOpts, ) (*beaconapi.Response[*apiv1.Genesis], error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.Genesis(ctx, opts) } // Spec returns the spec of the beacon node. func (cc ConsensusClient) Spec( ctx context.Context, opts *beaconapi.SpecOpts, ) (*beaconapi.Response[map[string]any], error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.Spec(ctx, opts) } // BlockProposerProof returns the block proposer proof for a given timestamp id. func (cc ConsensusClient) BlockProposerProof( ctx context.Context, timestampID string, ) (*ptypes.BlockProposerResponse, error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.BlockProposerProof(ctx, timestampID) } // ValidatorBalanceProof returns the validator balance proof for a given timestamp id and validator index. func (cc ConsensusClient) ValidatorBalanceProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorBalanceResponse, error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.ValidatorBalanceProof(ctx, timestampID, validatorIndex) } // ValidatorCredentialsProof returns the validator withdrawal credentials proof for a given timestamp id and validator index. func (cc ConsensusClient) ValidatorCredentialsProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorWithdrawalCredentialsResponse, error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.ValidatorCredentialsProof(ctx, timestampID, validatorIndex) } // ValidatorPubkeyProof returns the validator pubkey proof for a given timestamp id and validator index. func (cc ConsensusClient) ValidatorPubkeyProof( ctx context.Context, timestampID string, validatorIndex string, ) (*ptypes.ValidatorPubkeyResponse, error) { if cc.beaconClient == nil { return nil, errors.New("beacon client is not initialized") } return cc.beaconClient.ValidatorPubkeyProof(ctx, timestampID, validatorIndex) } // Commit returns the commit for a block. func (cc ConsensusClient) Commit( ctx context.Context, height *int64, ) (*coretypes.ResultCommit, error) { if cc.cometClient == nil { return nil, errors.New("comet client is not initialized") } return cc.cometClient.Commit(ctx, height) } // TODO: Add helpers for the beacon node-api client (converting from // go-eth2-client types to beacon-kit consensus types). ================================================ FILE: testing/e2e/suite/types/errors.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import "github.com/berachain/beacon-kit/errors" var ( // ErrPublicPortNotFound is returned when the public port is not found. ErrPublicPortNotFound = errors.New("failed to get public ports") ) ================================================ FILE: testing/e2e/suite/types/execution_client.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package types import ( "context" "fmt" "net/http" "time" beraclient "github.com/berachain/beacon-kit/gethlib/ethclient" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/rpc" "github.com/kurtosis-tech/kurtosis/api/golang/core/lib/services" ) // ExecutionClient represents an execution client. type ExecutionClient struct { *beraclient.Client serviceCtx *services.ServiceContext url string } // NewExecutionClientFromServiceCtx creates a new execution client from a // service context. func NewExecutionClient(serviceCtx *services.ServiceContext) *ExecutionClient { return &ExecutionClient{ serviceCtx: serviceCtx, } } func (ec *ExecutionClient) Start(ctx context.Context) error { port, ok := ec.serviceCtx.GetPublicPorts()["eth-json-rpc"] if !ok { return ErrPublicPortNotFound } ec.url = fmt.Sprintf("http://0.0.0.0:%d", port.GetNumber()) ethClient, err := DialWithPooling(ctx, ec.url) if err != nil { return err } ec.Client = beraclient.Wrap(ethClient) return nil } // URL returns the URL of the execution client. func (ec *ExecutionClient) URL() string { return ec.url } // DialWithPooling creates an ethclient with an HTTP transport configured // for high connection reuse, avoiding ephemeral port exhaustion under // heavy concurrent load. func DialWithPooling(ctx context.Context, url string) (*ethclient.Client, error) { const ( poolMaxIdleConns = 256 poolIdleTimeoutSecs = 90 ) httpClient := &http.Client{ Transport: &http.Transport{ MaxIdleConns: poolMaxIdleConns, MaxIdleConnsPerHost: poolMaxIdleConns, IdleConnTimeout: poolIdleTimeoutSecs * time.Second, }, } rpcClient, err := rpc.DialOptions(ctx, url, rpc.WithHTTPClient(httpClient)) if err != nil { return nil, err } return ethclient.NewClient(rpcClient), nil } ================================================ FILE: testing/e2e/suite/types/tx/eip4844.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package tx import ( "math/big" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) // New4844Tx creates a new 4844 tx. func New4844Tx( nonce uint64, to *common.Address, gasLimit uint64, chainID, tip, feeCap, value *big.Int, code []byte, blobFeeCap *big.Int, blobData []byte, al types.AccessList, ) *types.Transaction { blobs, commits, aggProof, versionedHashes, err := EncodeBlobs(blobData) if err != nil { panic(err) } if to == nil { to = &common.Address{} } return types.NewTx(&types.BlobTx{ ChainID: uint256.MustFromBig(chainID), Nonce: nonce, GasTipCap: uint256.MustFromBig(tip), GasFeeCap: uint256.MustFromBig(feeCap), Gas: gasLimit, To: *to, Value: uint256.MustFromBig(value), Data: code, AccessList: al, BlobFeeCap: uint256.MustFromBig(blobFeeCap), BlobHashes: versionedHashes, Sidecar: &types.BlobTxSidecar{ Blobs: blobs, Commitments: commits, Proofs: aggProof, }, }) } // EncodeBlobs encodes blobs. func EncodeBlobs( data []byte, ) ( []kzg4844.Blob, []kzg4844.Commitment, []kzg4844.Proof, []common.Hash, error, ) { blobs := encodeBlobs(data) commits := make([]kzg4844.Commitment, 0, len(blobs)) proofs := make([]kzg4844.Proof, 0, len(blobs)) versionedHashes := make([]common.Hash, 0, len(blobs)) for i := range blobs { commit, err := kzg4844.BlobToCommitment(&blobs[i]) if err != nil { return nil, nil, nil, nil, err } commits = append(commits, commit) proof, err := kzg4844.ComputeBlobProof(&blobs[i], commit) if err != nil { return nil, nil, nil, nil, err } proofs = append(proofs, proof) versionedHashes = append( versionedHashes, eip4844.KZGCommitment(commit).ToVersionedHash(), ) } return blobs, commits, proofs, versionedHashes, nil } // encodeBlobs encodes data into blobs. // //nolint:mnd // its chill. func encodeBlobs(data []byte) []kzg4844.Blob { blobs := []kzg4844.Blob{{}} blobIndex := 0 fieldIndex := -1 for i := 0; i < len(data); i += 31 { fieldIndex++ if fieldIndex == params.BlobTxFieldElementsPerBlob { blobs = append(blobs, kzg4844.Blob{}) blobIndex++ fieldIndex = 0 } maxSize := i + 31 if maxSize > len(data) { maxSize = len(data) } copy(blobs[blobIndex][fieldIndex*32+1:], data[i:maxSize]) } return blobs } ================================================ FILE: testing/files/entrypoint.sh ================================================ #!/usr/bin/env bash # SPDX-License-Identifier: MIT # # Copyright (c) 2025 Berachain Foundation # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation # files (the "Software"), to deal in the Software without # restriction, including without limitation the rights to use, # copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following # conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES # OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR # OTHER DEALINGS IN THE SOFTWARE. # function to resolve absolute path from relative resolve_path() { if [[ "$1" =~ : ]]; then # treat as an address or url, return as is echo "$1" fi cd "$(dirname "$1")" local abs_path abs_path="$(pwd -P)/$(basename "$1")" echo "$abs_path" } # Check if the chain spec is provided as an argument. CHAIN_SPEC="" CHAIN_SPEC_ARG="" if [ -z "$1" ]; then echo "No chain spec provided" exit 1 else CHAIN_SPEC="$1" CHAIN_SPEC_ARG="--beacon-kit.chain-spec $CHAIN_SPEC" if [ "$CHAIN_SPEC" == "file" ]; then CHAIN_SPEC_FILE=$(resolve_path "$2") CHAIN_SPEC_ARG="$CHAIN_SPEC_ARG --beacon-kit.chain-spec-file $CHAIN_SPEC_FILE" fi fi CHAINID="beacond-2061" MONIKER="localtestnet" LOGLEVEL="info" HOMEDIR="./.tmp/beacond" # Path variables GENESIS=$HOMEDIR/config/genesis.json TMP_GENESIS=$HOMEDIR/config/tmp_genesis.json ETH_GENESIS=$(resolve_path "./testing/files/eth-genesis.json") KZG_PATH=$(resolve_path "./testing/files/kzg-trusted-setup.json") # used to exit on first error (any non-zero exit code) set -e # Reinstall daemon make build overwrite="N" if [ -d $HOMEDIR ]; then printf "\nAn existing folder at '%s' was found. You can choose to delete this folder and start a new local node with new keys from genesis. When declined, the existing local node is started. \n" $HOMEDIR echo "Overwrite the existing configuration and start a new local node? [y/n]" read -r overwrite else overwrite="Y" fi # Setup local node if overwrite is set to Yes, otherwise skip setup if [[ $overwrite == "y" || $overwrite == "Y" ]]; then rm -rf $HOMEDIR ./build/bin/beacond init $MONIKER --chain-id $CHAINID --home $HOMEDIR $CHAIN_SPEC_ARG if [ "$CHAIN_SPEC" == "testnet" ]; then network_dir="testing/networks/80069" cp -f $network_dir/*.toml $network_dir/genesis.json ${HOMEDIR}/config KZG_PATH=$network_dir/kzg-trusted-setup.json elif [ "$CHAIN_SPEC" == "mainnet" ]; then network_dir="testing/networks/80094" cp -f $network_dir/*.toml $network_dir/genesis.json ${HOMEDIR}/config KZG_PATH=$network_dir/kzg-trusted-setup.json else ./build/bin/beacond genesis add-premined-deposit --home $HOMEDIR \ 32000000000 0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4 $CHAIN_SPEC_ARG ./build/bin/beacond genesis collect-premined-deposits --home $HOMEDIR $CHAIN_SPEC_ARG ./build/bin/beacond genesis set-deposit-storage "$ETH_GENESIS" --home $HOMEDIR $CHAIN_SPEC_ARG ./build/bin/beacond genesis execution-payload "$HOMEDIR/eth-genesis.json" --home $HOMEDIR $CHAIN_SPEC_ARG fi fi # Start the node (remove the --pruning=nothing flag if historical queries are not needed) BEACON_START_CMD="./build/bin/beacond start $CHAIN_SPEC_ARG --pruning=nothing "$TRACE" \ --beacon-kit.logger.log-level $LOGLEVEL --home $HOMEDIR \ --beacon-kit.engine.jwt-secret-path ${JWT_SECRET_PATH} \ --beacon-kit.kzg.trusted-setup-path ${KZG_PATH} \ --beacon-kit.node-api.enabled --beacon-kit.node-api.logging" # Conditionally add the rpc-dial-url flag if RPC_DIAL_URL is not empty if [ -n "$RPC_DIAL_URL" ]; then # this will overwrite the default dial url RPC_DIAL_URL=$(resolve_path "$RPC_DIAL_URL") echo "Overwriting the default dial url with $RPC_DIAL_URL" BEACON_START_CMD="$BEACON_START_CMD --beacon-kit.engine.rpc-dial-url ${RPC_PREFIX}${RPC_DIAL_URL}" fi eval $BEACON_START_CMD ================================================ FILE: testing/files/eth-genesis.json ================================================ { "config": { "chainId": 80087, "homesteadBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "istanbulBlock": 0, "muirGlacierBlock": 0, "berlinBlock": 0, "londonBlock": 0, "arrowGlacierBlock": 0, "grayGlacierBlock": 0, "mergeNetsplitBlock": 0, "shanghaiTime": 0, "cancunTime": 0, "pragueTime": 0, "osakaTime": 0, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true, "ethash": {}, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 }, "prague": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 } }, "berachain": { "prague1": { "time": 0, "baseFeeChangeDenominator": 48, "minimumBaseFeeWei": 1000000000, "polDistributorAddress": "0x4200000000000000000000000000000000000042" }, "prague2": { "time": 0, "minimumBaseFeeWei": 0 } } }, "coinbase": "0x0000000000000000000000000000000000000000", "difficulty": "0x0", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", "nonce": "0x0000000000000000", "timestamp": "0x0", "alloc": { "0x00000961Ef480Eb55e80D19ad83579A64c007002": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd", "nonce": "0x1", "balance": "0x0", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } }, "0x0000BBdDc7CE488642fb579F8B00f3a590007251": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", "nonce": "0x1", "balance": "0x0", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } }, "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4": { "balance": "0x123450000000000000000" }, "0x56898d1aFb10cad584961eb96AcD476C6826e41E": { "balance": "0x12345000000000000000000" }, "0x1e2e53c2451d0f9ED4B7952991BE0c95165D5c01": { "balance": "0x12345000000000000000000" }, "0x3bd0E8f1B1E8Ec99a4E1762F4058F9884C93af31": { "balance": "0x12345000000000000000000" }, "0xD073a84e2ccDF91a9025179330438485E886D206": { "balance": "0x12345000000000000000000" }, "0x8a88215ae882dfA519730c40109556c1C235729f": { "balance": "0x12345000000000000000000" }, "0x1a0A57e5e6a66aD732295ddAF0aed286a4e64310": { "balance": "0x12345000000000000000000" }, "0x185F4Eebd01614aE3d12a5E49b184B054C46d37B": { "balance": "0x12345000000000000000000" }, "0xdb96E9cDD1e457b602f97d33e51736D7a5216496": { "balance": "0x12345000000000000000000" }, "0x44a5FBfa7d6f3Fd92cca01f6764509f8Fc33dfa5": { "balance": "0x12345000000000000000000" }, "0x3649839562C8dA64E6215EB0f5371629Ead9729D": { "balance": "0x12345000000000000000000" }, "0x51e15e71c865FE702C9347610667f83658A20e00": { "balance": "0x12345000000000000000000" }, "0xBC9BC89b295a14F3976234Cc37C73e3D286f3a49": { "balance": "0x12345000000000000000000" }, "0x12De044207a90709Ef2602D3D9D945d64dAe6147": { "balance": "0x12345000000000000000000" }, "0x4Afe0DFDAcc91F0fA2AEe39F9eAd66b64d03EbD6": { "balance": "0x12345000000000000000000" }, "0xBC3c03b4185A6F10618CC4E7B9f4AdD59AB5FbbA": { "balance": "0x12345000000000000000000" }, "0xDc6De65f6070b409125217a12Cf576A208Cc1998": { "balance": "0x12345000000000000000000" }, "0xF60fD8632Fc77E19b3A0637d115d0fdd06F36968": { "balance": "0x12345000000000000000000" }, "0xbcC90AD39D377cA0b7b4F36eC463103E2728C33F": { "balance": "0x12345000000000000000000" }, "0x6F69542fC88fF84C480FFf510aB7108120447247": { "balance": "0x12345000000000000000000" }, "0x2f6eB3D9a41157322dE01A6E707F6F118Cb00A7b": { "balance": "0x12345000000000000000000" }, "0x187bE38A1f448b0F42423151A683dCAea949008B": { "balance": "0x12345000000000000000000" }, "0xA1d283f1a11A36D20FF38F29e12CA8F7Cf8709c1": { "balance": "0x12345000000000000000000" }, "0x868a33C94F91398B6245e1f0E4CF128B2F28714B": { "balance": "0x12345000000000000000000" }, "0x67c942Ef50Fc690eA779067a6A0d444a8234baB5": { "balance": "0x12345000000000000000000" }, "0xDE8E0E641E2Fb52c22460e6a1533c6BD13A00B37": { "balance": "0x12345000000000000000000" }, "0x9beFa0FB7a1A9E6cC7596204DbB8962E87091D64": { "balance": "0x12345000000000000000000" }, "0x62cB9bF32EA104f6D5eBf6879e876439f9492E4B": { "balance": "0x12345000000000000000000" }, "0xdb9cB94B166DfdC9F337EA63b32B448d993d7008": { "balance": "0x12345000000000000000000" }, "0x7c4d7dB81c544B768E1f4782011077202B74B5C0": { "balance": "0x12345000000000000000000" }, "0xaEf63D7F7e2637c99FeA1B63366b244B4da12D70": { "balance": "0x12345000000000000000000" }, "0x3DFb4173ec41EB976260fd689E5AB9772C66beaf": { "balance": "0x12345000000000000000000" }, "0x5145b1B855bca67A119CB02A42aF4Bdbc66B725C": { "balance": "0x12345000000000000000000" }, "0xf4b2eb959A4C4b0E148340676999FC0446D446D4": { "balance": "0x12345000000000000000000" }, "0xb86d37333072eFb48cEaa46C67271A27CA5Bda82": { "balance": "0x12345000000000000000000" }, "0x6CBcF4198fDA91D00fD469340E6DF6df086159e3": { "balance": "0x12345000000000000000000" }, "0xE7F444b5f772281384117674002d540131e533Ca": { "balance": "0x12345000000000000000000" }, "0x719Be866A77CeEc1BaC4FD37910c0975eFd52f55": { "balance": "0x12345000000000000000000" }, "0x0e10cDAd84D788843aF48673C5b260A02ef78742": { "balance": "0x12345000000000000000000" }, "0xcB6632daA65e6c921c2963C37320f63f54fC8fE3": { "balance": "0x12345000000000000000000" }, "0xDe5C7198e2416baB7e7a1EA758858Cd7301740bF": { "balance": "0x12345000000000000000000" }, "0x25fc16D8E2314B305dF05C032E617638284801D6": { "balance": "0x12345000000000000000000" }, "0xD2a3b89AE8D2c3bD39E2F24612ecFCD8600360C9": { "balance": "0x12345000000000000000000" }, "0x2F4fD8a82A1400E654eeEC59b0e588445ffE0F96": { "balance": "0x12345000000000000000000" }, "0x10FdFa4EFc83d6CC42F5ef14c13da8b98E458214": { "balance": "0x12345000000000000000000" }, "0x49cE37B2019bb2d0B8b6a094ef87a6Dd625454A0": { "balance": "0x12345000000000000000000" }, "0x800830F031ab1dd5895a5ec5B561427AD18f9ea8": { "balance": "0x12345000000000000000000" }, "0x3124d9885b11B52c56A2aee610AfCf5740d484F0": { "balance": "0x12345000000000000000000" }, "0xA6177defF3b768b1D678EdF7583b8cf210C777c0": { "balance": "0x12345000000000000000000" }, "0xF99139D2FCc5E25F57B0B91fd382a21B3AFF9cbA": { "balance": "0x12345000000000000000000" }, "0xC4DD08191B4d5173e3698491A11e05b63F9Ee097": { "balance": "0x12345000000000000000000" }, "0xB8865B4B8C56861534CC07ebBD2EA569a9a16323": { "balance": "0x12345000000000000000000" }, "0x2B9935698dc5c19Ab7414AE22f27Da5F4478008a": { "balance": "0x12345000000000000000000" }, "0xAC3c80F41C3049A89Aba8072FFbFc38a90fb6D8c": { "balance": "0x12345000000000000000000" }, "0xD6D4Fb22B91FAa54700852a05698B37d45514166": { "balance": "0x12345000000000000000000" }, "0xAf325Ccc92ae883DEF1634D499d8B093192D7a0c": { "balance": "0x12345000000000000000000" }, "0x7469CeEf99FB67e4990c5F1c085a1B39b2902331": { "balance": "0x12345000000000000000000" }, "0x14DA5251a1EB236238969575ccE943e2Fb0f4AA1": { "balance": "0x12345000000000000000000" }, "0xF9f58a87C3f0B3A4a0592938c80C41a7c659f855": { "balance": "0x12345000000000000000000" }, "0x1CF7e940A657eE706718CF180eb21864DE9672C3": { "balance": "0x12345000000000000000000" }, "0x440C37b22e8D7469128Ea7De6ac2f31419B4A8b1": { "balance": "0x12345000000000000000000" }, "0x4bD04ABA9fc709835b1EE4789195d10E9e8E53F5": { "balance": "0x12345000000000000000000" }, "0x4dC3aC871b22F8a98197B0aae976a8dE08e5Bebe": { "balance": "0x12345000000000000000000" }, "0x1f1D0FCa7e19b799c315d4fDf31bA50e6A2AB153": { "balance": "0x12345000000000000000000" }, "0x28879749Dda99387bdB43295B28bdF251d999F3b": { "balance": "0x12345000000000000000000" }, "0xC4eD09A472B82516daa3A4d8D1E38AE94CF4855C": { "balance": "0x12345000000000000000000" }, "0xf22FbA9cBeB75ED353931418E9eca71EF1Ab9921": { "balance": "0x12345000000000000000000" }, "0xC59D8935c0570E75BA0E55E3C661f535C86e368B": { "balance": "0x12345000000000000000000" }, "0xf97a36c417D33D1fC60a9163A8715e1aecb29102": { "balance": "0x12345000000000000000000" }, "0x4245537d9e3fb36fBBf054247FfFB28b0d931503": { "balance": "0x12345000000000000000000" }, "0xFeb1eafa0154D291e28e393FAF10Bc89e5cCbB22": { "balance": "0x12345000000000000000000" }, "0xf11D16e2EE6BefED82Fbca0b005906E09303aB95": { "balance": "0x12345000000000000000000" }, "0x9C75eD1A37ae420b4FC0a1F4c26B673227Fd3AFa": { "balance": "0x12345000000000000000000" }, "0x6a354C708fd248FD778F6adF75E41AA554700F68": { "balance": "0x12345000000000000000000" }, "0xea94749deFcc40dC5992687974b1C84B1bB9D6df": { "balance": "0x12345000000000000000000" }, "0x7689BE67b205EB5d32811d95D60587Eae4F3036F": { "balance": "0x12345000000000000000000" }, "0xdBfb742BD2e0e6E353cb61E75B9e11257aC8fB1A": { "balance": "0x12345000000000000000000" }, "0x2E5f031578e8FF82199aaF16f42c44D43Fe61819": { "balance": "0x12345000000000000000000" }, "0x611a42A2EF62c2461D123e3F0B64b93938bc4781": { "balance": "0x12345000000000000000000" }, "0x1a0c826048DF0E4661E3c53bBd447d497E3f701F": { "balance": "0x12345000000000000000000" }, "0x7f0E54bc3C1a72405646F5dFbBE0D4565c649fe2": { "balance": "0x12345000000000000000000" }, "0x54e1F990Dc0B7367F1E8eD96dA63BC4bca0E8061": { "balance": "0x12345000000000000000000" }, "0xbE651bc261b9Da5499a24Bf4214fD494c6e1F5Ac": { "balance": "0x12345000000000000000000" }, "0xD3c5dAC705289cD005C402C79C8445a47502d8be": { "balance": "0x12345000000000000000000" }, "0xE5981AA0807eb05611cDb666e32e53b2001bd61d": { "balance": "0x12345000000000000000000" }, "0x0fb648Cb08e21602AF61AF53fE104E29d46433F7": { "balance": "0x12345000000000000000000" }, "0x0474f52d25529c4db5f4E72F43303dA71B3541C6": { "balance": "0x12345000000000000000000" }, "0xe3024d098953661638d59E06f7FcD0B61c424854": { "balance": "0x12345000000000000000000" }, "0x8b1e58f651CacaAa40291d2a6E0a6404d7Ed99e6": { "balance": "0x12345000000000000000000" }, "0x8724C57fb8f38A1FccA7177543dd1D8FcD49E5aa": { "balance": "0x12345000000000000000000" }, "0xd0F043dED28773953562f824334C4cbb84210AE7": { "balance": "0x12345000000000000000000" }, "0xE3d2b9191EaBD3636A5dd057D522335cfae8c7CF": { "balance": "0x12345000000000000000000" }, "0x3f51B3BB6A18141282Ba002F7709c7E2f337F961": { "balance": "0x12345000000000000000000" }, "0xf6B6A52aA9BD788837c6682f47ACE009BD84b6fc": { "balance": "0x12345000000000000000000" }, "0x795B761Db5969B7ba53472d5D37c230C859a472F": { "balance": "0x12345000000000000000000" }, "0x7d7f187C2A05cDDCF700dCF2E02c96E7eF03f9B0": { "balance": "0x12345000000000000000000" }, "0x2d88ECD4d8F4b0A954886eE8C0802aE14684cd07": { "balance": "0x12345000000000000000000" }, "0x92B3feac5b7816Dcef96a303c1D5112271A70D2c": { "balance": "0x12345000000000000000000" }, "0x5DD7bc3BEE395831ce499315ecAFE81DE0556F99": { "balance": "0x12345000000000000000000" }, "0x5227aaebCA3E5e893547A667666E2e4e12Ca20e0": { "balance": "0x12345000000000000000000" }, "0x47575DAE85403cD408d4639068D1187C427B9897": { "balance": "0x12345000000000000000000" }, "0xE69ac59e1DF47291AaB8DEc540C796f81De7c892": { "balance": "0x12345000000000000000000" }, "0xb87fb371Bd3C2093b608cd0E7a8dDD60Bb05C995": { "balance": "0x12345000000000000000000" }, "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": { "balance": "0x0", "nonce": "0x1", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500" }, "0x4e59b44847b379578588920cA78FbF26c0B4956C": { "balance": "0x0", "nonce": "0x1", "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3" }, "0x4242424242424242424242424242424242424242": { "balance": "0x0", "nonce": "0x1", "code": "0x608060405260043610610093575f3560e01c8063577212fe11610066578063c53925d91161004c578063c53925d914610231578063e12cf4cb14610250578063fea7ab7714610263575f80fd5b8063577212fe146101cc5780639eaffa96146101ed575f80fd5b806301ffc9a7146100975780632dfdf0b5146100cb5780633523f9bd14610103578063560036ec14610126575b5f80fd5b3480156100a2575f80fd5b506100b66100b1366004610bb7565b610282565b60405190151581526020015b60405180910390f35b3480156100d6575f80fd5b505f546100ea9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100c2565b34801561010e575f80fd5b5061011860015481565b6040519081526020016100c2565b348015610131575f80fd5b50610193610140366004610c2a565b80516020818301810180516003825292820191909301209152546bffffffffffffffffffffffff8116906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1682565b604080516bffffffffffffffffffffffff909316835273ffffffffffffffffffffffffffffffffffffffff9091166020830152016100c2565b3480156101d7575f80fd5b506101eb6101e6366004610d5f565b61031a565b005b3480156101f8575f80fd5b5061020c610207366004610d5f565b6103e7565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c2565b34801561023c575f80fd5b506101eb61024b366004610d5f565b610428565b6101eb61025e366004610dc1565b61063d565b34801561026e575f80fd5b506101eb61027d366004610e70565b61095c565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061031457507fffffffff0000000000000000000000000000000000000000000000000000000082167f136f920d00000000000000000000000000000000000000000000000000000000145b92915050565b6002828260405161032c929190610ec0565b908152604051908190036020019020543373ffffffffffffffffffffffffffffffffffffffff90911614610383576103837f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b60038282604051610395929190610ec0565b9081526040519081900360200181205f90556103b49083908390610ec0565b604051908190038120907f1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db905f90a25050565b5f600283836040516103fa929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f6003838360405161043b929190610ec0565b908152604051908190036020019020805490915073ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000820416906bffffffffffffffffffffffff163382146104b4576104b47f819a0d0b00000000000000000000000000000000000000000000000000000000610afc565b6bffffffffffffffffffffffff42166104d06201518083610efc565b6bffffffffffffffffffffffff16111561050d5761050d7fe8966d7a00000000000000000000000000000000000000000000000000000000610afc565b5f60028686604051610520929190610ec0565b9081526040519081900360200181205473ffffffffffffffffffffffffffffffffffffffff169150839060029061055a9089908990610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556003906105bf9088908890610ec0565b9081526040519081900360200181205f90556105de9087908790610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a2505050505050565b6030861461066e5761066e7f9f10647200000000000000000000000000000000000000000000000000000000610afc565b6020841461069f5761069f7fb39bca1600000000000000000000000000000000000000000000000000000000610afc565b606082146106d0576106d07f4be6321b00000000000000000000000000000000000000000000000000000000610afc565b5f73ffffffffffffffffffffffffffffffffffffffff16600288886040516106f9929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16036108375773ffffffffffffffffffffffffffffffffffffffff8116610768576107687f51969a7a00000000000000000000000000000000000000000000000000000000610afc565b806002888860405161077b929190610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556107dd9088908890610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff841683525f6020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a261087c565b73ffffffffffffffffffffffffffffffffffffffff81161561087c5761087c7fc4142b4100000000000000000000000000000000000000000000000000000000610afc565b5f610885610b04565b90506509184e72a00067ffffffffffffffff821610156108c8576108c87f0e1eddda00000000000000000000000000000000000000000000000000000000610afc565b5f80547f68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46918a918a918a918a9187918b918b9167ffffffffffffffff16908061091083610f20565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405161094a989796959493929190610f93565b60405180910390a15050505050505050565b5f6002848460405161096f929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690503381146109c7576109c77f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b73ffffffffffffffffffffffffffffffffffffffff8216610a0b57610a0b7fd92e233d00000000000000000000000000000000000000000000000000000000610afc565b5f60038585604051610a1e929190610ec0565b908152604051908190036020018120426bffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff86166c01000000000000000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000161781559150610a969086908690610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff8681168452851660208401524283830152905190917f7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f919081900360600190a25050505050565b805f5260045ffd5b5f610b13633b9aca003461102b565b15610b4157610b417f40567b3800000000000000000000000000000000000000000000000000000000610afc565b5f610b50633b9aca003461103e565b905067ffffffffffffffff811115610b8b57610b8b7f2aa6673400000000000000000000000000000000000000000000000000000000610afc565b610b955f34610b9a565b919050565b5f385f3884865af1610bb35763b12d13eb5f526004601cfd5b5050565b5f60208284031215610bc7575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610bf6575f80fd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215610c3a575f80fd5b813567ffffffffffffffff811115610c50575f80fd5b8201601f81018413610c60575f80fd5b803567ffffffffffffffff811115610c7a57610c7a610bfd565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715610ce657610ce6610bfd565b604052818152828201602001861015610cfd575f80fd5b816020840160208301375f91810160200191909152949350505050565b5f8083601f840112610d2a575f80fd5b50813567ffffffffffffffff811115610d41575f80fd5b602083019150836020828501011115610d58575f80fd5b9250929050565b5f8060208385031215610d70575f80fd5b823567ffffffffffffffff811115610d86575f80fd5b610d9285828601610d1a565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b95575f80fd5b5f805f805f805f6080888a031215610dd7575f80fd5b873567ffffffffffffffff811115610ded575f80fd5b610df98a828b01610d1a565b909850965050602088013567ffffffffffffffff811115610e18575f80fd5b610e248a828b01610d1a565b909650945050604088013567ffffffffffffffff811115610e43575f80fd5b610e4f8a828b01610d1a565b9094509250610e62905060608901610d9e565b905092959891949750929550565b5f805f60408486031215610e82575f80fd5b833567ffffffffffffffff811115610e98575f80fd5b610ea486828701610d1a565b9094509250610eb7905060208501610d9e565b90509250925092565b818382375f9101908152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6bffffffffffffffffffffffff818116838216019081111561031457610314610ecf565b5f67ffffffffffffffff821667ffffffffffffffff8103610f4357610f43610ecf565b60010192915050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60a081525f610fa660a083018a8c610f4c565b8281036020840152610fb981898b610f4c565b905067ffffffffffffffff871660408401528281036060840152610fde818688610f4c565b91505067ffffffffffffffff831660808301529998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261103957611039610ffe565b500690565b5f8261104c5761104c610ffe565b50049056fea164736f6c634300081a000a" }, "0x4200000000000000000000000000000000000042": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063163db71b1461003857806360644a6b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b610065610060366004610183565b610067565b005b3373fffffffffffffffffffffffffffffffffffffffe146100b4576040517f5e742c5a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5f805490806100c2836101f1565b90915550506040517f999da65b0000000000000000000000000000000000000000000000000000000081527342000000000000000000000000000000000000439063999da65b90610119908590859060040161024d565b5f604051808303815f87803b158015610130575f80fd5b505af1158015610142573d5f803e3d5ffd5b505050507f60b106db8802e863a4a9dc4af78cb0dd63feb55ad4ee60f0453c13309bfdbdd4828260405161017792919061024d565b60405180910390a15050565b5f8060208385031215610194575f80fd5b823567ffffffffffffffff8111156101aa575f80fd5b8301601f810185136101ba575f80fd5b803567ffffffffffffffff8111156101d0575f80fd5b8560208284010111156101e1575f80fd5b6020919091019590945092505050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610246577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5060010190565b60208152816020820152818360408301375f818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010191905056fea2646970667358221220e6dfa8c5d72bb391aff9e891c09a1f86d26cfd1d112aaab4b577bcbc5b94bafe64736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" }, "0x4200000000000000000000000000000000000043": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c80634b28f9a214610038578063999da65b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b6100656100603660046100b8565b610067565b005b5f8054908061007583610126565b91905055507fb3a8fa51f8d3759f320e88b7f8d3fb73a2a51b31b3324b37833c4816cf41e7c45f546040516100ac91815260200190565b60405180910390a15050565b5f80602083850312156100c9575f80fd5b823567ffffffffffffffff8111156100df575f80fd5b8301601f810185136100ef575f80fd5b803567ffffffffffffffff811115610105575f80fd5b856020828401011115610116575f80fd5b6020919091019590945092505050565b5f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361017b577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b506001019056fea2646970667358221220e5db2a9698e23f84b7c83d023ea72ca3f01627daffa1ff16ae15918143d892a564736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" } } } ================================================ FILE: testing/files/jwt.hex ================================================ 0xc4d70beb372fc886335d5bef3aabd63b4324b621132f5d8de67a06ddd0405fcd ================================================ FILE: testing/files/kzg-trusted-setup.json ================================================ { "g1_lagrange": [ "0xa0413c0dcafec6dbc9f47d66785cf1e8c981044f7d13cfe3e4fcbb71b5408dfde6312493cb3c1d30516cb3ca88c03654", "0x8b997fb25730d661918371bb41f2a6e899cac23f04fc5365800b75433c0a953250e15e7a98fb5ca5cc56a8cd34c20c57", "0x83302852db89424d5699f3f157e79e91dc1380f8d5895c5a772bb4ea3a5928e7c26c07db6775203ce33e62a114adaa99", "0xa759c48b7e4a685e735c01e5aa6ef9c248705001f470f9ad856cd87806983e917a8742a3bd5ee27db8d76080269b7c83", "0x967f8dc45ebc3be14c8705f43249a30ff48e96205fb02ae28daeab47b72eb3f45df0625928582aa1eb4368381c33e127", "0xa418eb1e9fb84cb32b370610f56f3cb470706a40ac5a47c411c464299c45c91f25b63ae3fcd623172aa0f273c0526c13", "0x8f44e3f0387293bc7931e978165abbaed08f53acd72a0a23ac85f6da0091196b886233bcee5b4a194db02f3d5a9b3f78", "0x97173434b336be73c89412a6d70d416e170ea355bf1956c32d464090b107c090ef2d4e1a467a5632fbc332eeb679bf2d", "0xa24052ad8d55ad04bc5d951f78e14213435681594110fd18173482609d5019105b8045182d53ffce4fc29fc8810516c1", "0xb950768136b260277590b5bec3f56bbc2f7a8bc383d44ce8600e85bf8cf19f479898bcc999d96dfbd2001ede01d94949", "0x92ab8077871037bd3b57b95cbb9fb10eb11efde9191690dcac655356986fd02841d8fdb25396faa0feadfe3f50baf56d", "0xa79b096dff98038ac30f91112dd14b78f8ad428268af36d20c292e2b3b6d9ed4fb28480bb04e465071cc67d05786b6d1", "0xb9ff71461328f370ce68bf591aa7fb13027044f42a575517f3319e2be4aa4843fa281e756d0aa5645428d6dfa857cef2", "0x8d765808c00b3543ff182e2d159c38ae174b12d1314da88ea08e13bd9d1c37184cb515e6bf6420531b5d41767987d7ce", "0xb8c9a837d20c3b53e6f578e4a257bb7ef8fc43178614ec2a154915b267ad2be135981d01ed2ee1b5fbd9d9bb27f0800a", "0xa9773d92cf23f65f98ef68f6cf95c72b53d0683af2f9bf886bb9036e4a38184b1131b26fd24397910b494fbef856f3aa", "0xb41ebe38962d112da4a01bf101cb248d808fbd50aaf749fc7c151cf332032eb3e3bdbd716db899724b734d392f26c412", "0x90fbb030167fb47dcc13d604a726c0339418567c1d287d1d87423fa0cb92eec3455fbb46bcbe2e697144a2d3972142e4", "0xb11d298bd167464b35fb923520d14832bd9ed50ed841bf6d7618424fd6f3699190af21759e351b89142d355952149da1", "0x8bc36066f69dc89f7c4d1e58d67497675050c6aa002244cebd9fc957ec5e364c46bab4735ea3db02b73b3ca43c96e019", "0xab7ab92c5d4d773068e485aa5831941ebd63db7118674ca38089635f3b4186833af2455a6fb9ed2b745df53b3ce96727", "0xaf191ca3089892cb943cd97cf11a51f38e38bd9be50844a4e8da99f27e305e876f9ed4ab0628e8ae3939066b7d34a15f", "0xa3204c1747feabc2c11339a542195e7cb6628fd3964f846e71e2e3f2d6bb379a5e51700682ea1844eba12756adb13216", "0x903a29883846b7c50c15968b20e30c471aeac07b872c40a4d19eb1a42da18b649d5bbfde4b4cf6225d215a461b0deb6d", "0x8e6e9c15ffbf1e16e5865a5fef7ed751dc81957a9757b535cb38b649e1098cda25d42381dc4f776778573cdf90c3e6e0", "0xa8f6dd26100b512a8c96c52e00715c4b2cb9ac457f17aed8ffe1cf1ea524068fe5a1ddf218149845fc1417b789ecfc98", "0xa5b0ffc819451ea639cfd1c18cbc9365cc79368d3b2e736c0ae54eba2f0801e6eb0ee14a5f373f4a70ca463bdb696c09", "0x879f91ccd56a1b9736fbfd20d8747354da743fb121f0e308a0d298ff0d9344431890e41da66b5009af3f442c636b4f43", "0x81bf3a2d9755e206b515a508ac4d1109bf933c282a46a4ae4a1b4cb4a94e1d23642fad6bd452428845afa155742ade7e", "0x8de778d4742f945df40004964e165592f9c6b1946263adcdd5a88b00244bda46c7bb49098c8eb6b3d97a0dd46148a8ca", "0xb7a57b21d13121907ee28c5c1f80ee2e3e83a3135a8101e933cf57171209a96173ff5037f5af606e9fd6d066de6ed693", "0xb0877d1963fd9200414a38753dffd9f23a10eb3198912790d7eddbc9f6b477019d52ddd4ebdcb9f60818db076938a5a9", "0x88da2d7a6611bc16adc55fc1c377480c828aba4496c645e3efe0e1a67f333c05a0307f7f1d2df8ac013602c655c6e209", "0x95719eb02e8a9dede1a888c656a778b1c69b7716fbe3d1538fe8afd4a1bc972183c7d32aa7d6073376f7701df80116d8", "0x8e8a1ca971f2444b35af3376e85dccda3abb8e8e11d095d0a4c37628dfe5d3e043a377c3de68289ef142e4308e9941a0", "0xb720caaff02f6d798ac84c4f527203e823ff685869e3943c979e388e1c34c3f77f5c242c6daa7e3b30e511aab917b866", "0x86040d55809afeec10e315d1ad950d269d37cfee8c144cd8dd4126459e3b15a53b3e68df5981df3c2346d23c7b4baaf4", "0x82d8cabf13ab853db0377504f0aec00dba3a5cd3119787e8ad378ddf2c40b022ecfc67c642b7acc8c1e3dd03ab50993e", "0xb8d873927936719d2484cd03a6687d65697e17dcf4f0d5aed6f5e4750f52ef2133d4645894e7ebfc4ef6ce6788d404c8", "0xb1235594dbb15b674a419ff2b2deb644ad2a93791ca05af402823f87114483d6aa1689b7a9bea0f547ad12fe270e4344", "0xa53fda86571b0651f5affb74312551a082fffc0385cfd24c1d779985b72a5b1cf7c78b42b4f7e51e77055f8e5e915b00", "0xb579adcfd9c6ef916a5a999e77a0cb21d378c4ea67e13b7c58709d5da23a56c2e54218691fc4ac39a4a3d74f88cc31f7", "0xab79e584011713e8a2f583e483a91a0c2a40771b77d91475825b5acbea82db4262132901cb3e4a108c46d7c9ee217a4e", "0xa0fe58ea9eb982d7654c8aaf9366230578fc1362f6faae0594f8b9e659bcb405dff4aac0c7888bbe07f614ecf0d800a6", "0x867e50e74281f28ecd4925560e2e7a6f8911b135557b688254623acce0dbc41e23ac3e706a184a45d54c586edc416eb0", "0x89f81b61adda20ea9d0b387a36d0ab073dc7c7cbff518501962038be19867042f11fcc7ff78096e5d3b68c6d8dc04d9b", "0xa58ee91bb556d43cf01f1398c5811f76dc0f11efdd569eed9ef178b3b0715e122060ec8f945b4dbf6eebfa2b90af6fa6", "0xac460be540f4c840def2eef19fc754a9af34608d107cbadb53334cf194cc91138d53b9538fcd0ec970b5d4aa455b224a", "0xb09b91f929de52c09d48ca0893be6eb44e2f5210a6c394689dc1f7729d4be4e11d0474b178e80cea8c2ac0d081f0e811", "0x8d37a442a76b06a02a4e64c2504aea72c8b9b020ab7bcc94580fe2b9603c7c50d7b1e9d70d2a7daea19c68667e8f8c31", "0xa9838d4c4e3f3a0075a952cf7dd623307ec633fcc81a7cf9e52e66c31780de33dbb3d74c320dc7f0a4b72f7a49949515", "0xa44766b6251af458fe4f5f9ed1e02950f35703520b8656f09fc42d9a2d38a700c11a7c8a0436ac2e5e9f053d0bb8ff91", "0xad78d9481c840f5202546bea0d13c776826feb8b1b7c72e83d99a947622f0bf38a4208551c4c41beb1270d7792075457", "0xb619ffa8733b470039451e224b777845021e8dc1125f247a4ff2476cc774657d0ff9c5279da841fc1236047de9d81c60", "0xaf760b0a30a1d6af3bc5cd6686f396bd41779aeeb6e0d70a09349bd5da17ca2e7965afc5c8ec22744198fbe3f02fb331", "0xa0cc209abdb768b589fcb7b376b6e1cac07743288c95a1cf1a0354b47f0cf91fca78a75c1fcafa6f5926d6c379116608", "0x864add673c89c41c754eeb3cd8dcff5cdde1d739fce65c30e474a082bb5d813cba6412e61154ce88fdb6c12c5d9be35b", "0xb091443b0ce279327dc37cb484e9a5b69b257a714ce21895d67539172f95ffa326903747b64a3649e99aea7bb10d03f7", "0xa8c452b8c4ca8e0a61942a8e08e28f17fb0ef4c5b018b4e6d1a64038280afa2bf1169202f05f14af24a06ca72f448ccd", "0xa23c24721d18bc48d5dcf70effcbef89a7ae24e67158d70ae1d8169ee75d9a051d34b14e9cf06488bac324fe58549f26", "0x92a730e30eb5f3231feb85f6720489dbb1afd42c43f05a1610c6b3c67bb949ec8fde507e924498f4ffc646f7b07d9123", "0x8dbe5abf4031ec9ba6bb06d1a47dd1121fb9e03b652804069250967fd5e9577d0039e233441b7f837a7c9d67ba18c28e", "0xaa456bcfef6a21bb88181482b279df260297b3778e84594ebddbdf337e85d9e3d46ca1d0b516622fb0b103df8ec519b7", "0xa3b31ae621bd210a2b767e0e6f22eb28fe3c4943498a7e91753225426168b9a26da0e02f1dc5264da53a5ad240d9f51b", "0xaa8d66857127e6e71874ce2202923385a7d2818b84cb73a6c42d71afe70972a70c6bdd2aad1a6e8c5e4ca728382a8ea8", "0xac7e8e7a82f439127a5e40558d90d17990f8229852d21c13d753c2e97facf077cf59582b603984c3dd3faebd80aff4f5", "0x93a8bcf4159f455d1baa73d2ef2450dcd4100420de84169bbe28b8b7a5d1746273f870091a87a057e834f754f34204b1", "0x89d0ebb287c3613cdcae7f5acc43f17f09c0213fc40c074660120b755d664109ffb9902ed981ede79e018ddb0c845698", "0xa87ccbfad431406aadbee878d9cf7d91b13649d5f7e19938b7dfd32645a43b114eef64ff3a13201398bd9b0337832e5a", "0x833c51d0d0048f70c3eefb4e70e4ff66d0809c41838e8d2c21c288dd3ae9d9dfaf26d1742bf4976dab83a2b381677011", "0x8bcd6b1c3b02fffead432e8b1680bad0a1ac5a712d4225e220690ee18df3e7406e2769e1f309e2e803b850bc96f0e768", "0xb61e3dbd88aaf4ff1401521781e2eea9ef8b66d1fac5387c83b1da9e65c2aa2a56c262dea9eceeb4ad86c90211672db0", "0x866d3090db944ecf190dd0651abf67659caafd31ae861bab9992c1e3915cb0952da7c561cc7e203560a610f48fae633b", "0xa5e8971543c14274a8dc892b0be188c1b4fbc75c692ed29f166e0ea80874bc5520c2791342b7c1d2fb5dd454b03b8a5b", "0x8f2f9fc50471bae9ea87487ebd1bc8576ef844cc42d606af5c4c0969670fdf2189afd643e4de3145864e7773d215f37f", "0xb1bb0f2527db6d51f42b9224383c0f96048bbc03d469bf01fe1383173ef8b1cc9455d9dd8ba04d46057f46949bfc92b5", "0xaa7c99d906b4d7922296cfe2520473fc50137c03d68b7865c5bfb8adbc316b1034310ec4b5670c47295f4a80fb8d61e9", "0xa5d1da4d6aba555919df44cbaa8ff79378a1c9e2cfdfbf9d39c63a4a00f284c5a5724e28ecbc2d9dba27fe4ee5018bd5", "0xa8db53224f70af4d991b9aae4ffe92d2aa5b618ad9137784b55843e9f16cefbfd25ada355d308e9bbf55f6d2f7976fb3", "0xb6536c4232bb20e22af1a8bb12de76d5fec2ad9a3b48af1f38fa67e0f8504ef60f305a73d19385095bb6a9603fe29889", "0x87f7e371a1817a63d6838a8cf4ab3a8473d19ce0d4f40fd013c03d5ddd5f4985df2956531cc9f187928ef54c68f4f9a9", "0xae13530b1dbc5e4dced9d909ea61286ec09e25c12f37a1ed2f309b0eb99863d236c3b25ed3484acc8c076ad2fa8cd430", "0x98928d850247c6f7606190e687d5c94a627550198dbdbea0161ef9515eacdb1a0f195cae3bb293112179082daccf8b35", "0x918528bb8e6a055ad4db6230d3a405e9e55866da15c4721f5ddd1f1f37962d4904aad7a419218fe6d906fe191a991806", "0xb71e31a06afe065773dd3f4a6e9ef81c3292e27a3b7fdfdd452d03e05af3b6dd654c355f7516b2a93553360c6681a73a", "0x8870b83ab78a98820866f91ac643af9f3ff792a2b7fda34185a9456a63abdce42bfe8ad4dc67f08a6392f250d4062df4", "0x91eea1b668e52f7a7a5087fabf1cab803b0316f78d9fff469fbfde2162f660c250e4336a9eea4cb0450bd30ac067bc8b", "0x8b74990946de7b72a92147ceac1bd9d55999a8b576e8df68639e40ed5dc2062cfcd727903133de482b6dca19d0aaed82", "0x8ebad537fece090ebbab662bdf2618e21ca30cf6329c50935e8346d1217dcbe3c1fe1ea28efca369c6003ce0a94703c1", "0xa8640479556fb59ebd1c40c5f368fbd960932fdbb782665e4a0e24e2bdb598fc0164ce8c0726d7759cfc59e60a62e182", "0xa9a52a6bf98ee4d749f6d38be2c60a6d54b64d5cbe4e67266633dc096cf28c97fe998596707d31968cbe2064b72256bf", "0x847953c48a4ce6032780e9b39d0ed4384e0be202c2bbe2dfda3910f5d87aa5cd3c2ffbfcfae4dddce16d6ab657599b95", "0xb6f6e1485d3ec2a06abaecd23028b200b2e4a0096c16144d07403e1720ff8f9ba9d919016b5eb8dc5103880a7a77a1d3", "0x98dfc2065b1622f596dbe27131ea60bef7a193b12922cecb27f8c571404f483014f8014572e86ae2e341ab738e4887ef", "0xacb0d205566bacc87bbe2e25d10793f63f7a1f27fd9e58f4f653ceae3ffeba511eaf658e068fad289eeb28f9edbeb35b", "0xae4411ed5b263673cee894c11fe4abc72a4bf642d94022a5c0f3369380fcdfc1c21e277f2902972252503f91ada3029a", "0xac4a7a27ba390a75d0a247d93d4a8ef1f0485f8d373a4af4e1139369ec274b91b3464d9738eeaceb19cd6f509e2f8262", "0x87379c3bf231fdafcf6472a79e9e55a938d851d4dd662ab6e0d95fd47a478ed99e2ad1e6e39be3c0fc4f6d996a7dd833", "0x81316904b035a8bcc2041199a789a2e6879486ba9fddcba0a82c745cc8dd8374a39e523b91792170cd30be7aa3005b85", "0xb8206809c6cd027ed019f472581b45f7e12288f89047928ba32b4856b6560ad30395830d71e5e30c556f6f182b1fe690", "0x88d76c028f534a62e019b4a52967bb8642ede6becfa3807be68fdd36d366fc84a4ac8dc176e80a68bc59eb62caf5dff9", "0x8c3b8be685b0f8aad131ee7544d0e12f223f08a6f8edaf464b385ac644e0ddc9eff7cc7cb5c1b50ab5d71ea0f41d2213", "0x8d91410e004f76c50fdc05784157b4d839cb5090022c629c7c97a5e0c3536eeafee17a527b54b1165c3cd81774bb54ce", "0xb25c2863bc28ec5281ce800ddf91a7e1a53f4c6d5da1e6c86ef4616e93bcf55ed49e297216d01379f5c6e7b3c1e46728", "0x865f7b09ac3ca03f20be90c48f6975dd2588838c2536c7a3532a6aa5187ed0b709cd03d91ff4048061c10d0aa72b69ce", "0xb3f7477c90c11596eb4f8bbf34adbcb832638c4ff3cdd090d4d477ee50472ac9ddaf5be9ad7eca3f148960d362bbd098", "0x8db35fd53fca04faecd1c76a8227160b3ab46ac1af070f2492445a19d8ff7c25bbaef6c9fa0c8c088444561e9f7e4eb2", "0xa478b6e9d058a2e01d2fc053b739092e113c23a6a2770a16afbef044a3709a9e32f425ace9ba7981325f02667c3f9609", "0x98caa6bd38916c08cf221722a675a4f7577f33452623de801d2b3429595f988090907a7e99960fff7c076d6d8e877b31", "0xb79aaaacefc49c3038a14d2ac468cfec8c2161e88bdae91798d63552cdbe39e0e02f9225717436b9b8a40a022c633c6e", "0x845a31006c680ee6a0cc41d3dc6c0c95d833fcf426f2e7c573fa15b2c4c641fbd6fe5ebb0e23720cc3467d6ee1d80dc4", "0xa1bc287e272cf8b74dbf6405b3a5190883195806aa351f1dc8e525aa342283f0a35ff687e3b434324dedee74946dd185", "0xa4fd2dc8db75d3783a020856e2b3aa266dc6926e84f5c491ef739a3bddd46dc8e9e0fc1177937839ef1b18d062ffbb9e", "0xacbf0d3c697f57c202bb8c5dc4f3fc341b8fc509a455d44bd86acc67cad2a04495d5537bcd3e98680185e8aa286f2587", "0xa5caf423a917352e1b8e844f5968a6da4fdeae467d10c6f4bbd82b5eea46a660b82d2f5440d3641c717b2c3c9ed0be52", "0x8a39d763c08b926599ab1233219c49c825368fad14d9afc7c0c039224d37c00d8743293fd21645bf0b91eaf579a99867", "0xb2b53a496def0ba06e80b28f36530fbe0fb5d70a601a2f10722e59abee529369c1ae8fd0f2db9184dd4a2519bb832d94", "0xa73980fcef053f1b60ebbb5d78ba6332a475e0b96a0c724741a3abf3b59dd344772527f07203cf4c9cb5155ebed81fa0", "0xa070d20acce42518ece322c9db096f16aed620303a39d8d5735a0df6e70fbeceb940e8d9f5cc38f3314b2240394ec47b", "0xa50cf591f522f19ca337b73089557f75929d9f645f3e57d4f241e14cdd1ea3fb48d84bcf05e4f0377afbb789fbdb5d20", "0x82a5ffce451096aca8eeb0cd2ae9d83db3ed76da3f531a80d9a70a346359bf05d74863ce6a7c848522b526156a5e20cd", "0x88e0e84d358cbb93755a906f329db1537c3894845f32b9b0b691c29cbb455373d9452fadd1e77e20a623f6eaf624de6f", "0xaa07ac7b84a6d6838826e0b9e350d8ec75e398a52e9824e6b0da6ae4010e5943fec4f00239e96433f291fef9d1d1e609", "0xac8887bf39366034bc63f6cc5db0c26fd27307cbc3d6cce47894a8a019c22dd51322fb5096edc018227edfafc053a8f6", "0xb7d26c26c5b33f77422191dca94977588ab1d4b9ce7d0e19c4a3b4cd1c25211b78c328dbf81e755e78cd7d1d622ad23e", "0x99a676d5af49f0ba44047009298d8474cabf2d5bca1a76ba21eff7ee3c4691a102fdefea27bc948ccad8894a658abd02", "0xb0d09a91909ab3620c183bdf1d53d43d39eb750dc7a722c661c3de3a1a5d383ad221f71bae374f8a71867505958a3f76", "0x84681a883de8e4b93d68ac10e91899c2bbb815ce2de74bb48a11a6113b2a3f4df8aceabda1f5f67bc5aacac8c9da7221", "0x9470259957780fa9b43521fab3644f555f5343281c72582b56d2efd11991d897b3b481cafa48681c5aeb80c9663b68f7", "0xab1b29f7ece686e6fa968a4815da1d64f3579fed3bc92e1f3e51cd13a3c076b6cf695ed269d373300a62463dc98a4234", "0x8ab415bfcd5f1061f7687597024c96dd9c7cb4942b5989379a7a3b5742f7d394337886317659cbeacaf030234a24f972", "0xb9b524aad924f9acc63d002d617488f31b0016e0f0548f050cada285ce7491b74a125621638f19e9c96eabb091d945be", "0x8c4c373e79415061837dd0def4f28a2d5d74d21cb13a76c9049ad678ca40228405ab0c3941df49249847ecdefc1a5b78", "0xa8edf4710b5ab2929d3db6c1c0e3e242261bbaa8bcec56908ddadd7d2dad2dca9d6eb9de630b960b122ebeea41040421", "0x8d66bb3b50b9df8f373163629f9221b3d4b6980a05ea81dc3741bfe9519cf3ebba7ab98e98390bae475e8ede5821bd5c", "0x8d3c21bae7f0cfb97c56952bb22084b58e7bb718890935b73103f33adf5e4d99cd262f929c6eeab96209814f0dbae50a", "0xa5c66cfab3d9ebf733c4af24bebc97070e7989fe3c73e79ac85fb0e4d40ae44fb571e0fad4ad72560e13ed453900d14f", "0x9362e6b50b43dbefbc3254471372297b5dcce809cd3b60bf74a1268ab68bdb50e46e462cbd78f0d6c056330e982846af", "0x854630d08e3f0243d570cc2e856234cb4c1a158d9c1883bf028a76525aaa34be897fe918d5f6da9764a3735fa9ebd24a", "0x8c7d246985469ff252c3f4df6c7c9196fc79f05c1c66a609d84725c78001d0837c7a7049394ba5cf7e863e2d58af8417", "0xae050271e01b528925302e71903f785b782f7bf4e4e7a7f537140219bc352dc7540c657ed03d3a297ad36798ecdb98cd", "0x8d2ae9179fcf2b0c69850554580b52c1f4a5bd865af5f3028f222f4acad9c1ad69a8ef6c7dc7b03715ee5c506b74325e", "0xb8ef8de6ce6369a8851cd36db0ccf00a85077e816c14c4e601f533330af9e3acf0743a95d28962ed8bfcfc2520ef3cfe", "0xa6ecad6fdfb851b40356a8b1060f38235407a0f2706e7b8bb4a13465ca3f81d4f5b99466ac2565c60af15f022d26732e", "0x819ff14cdea3ab89d98e133cd2d0379361e2e2c67ad94eeddcdb9232efd509f51d12f4f03ebd4dd953bd262a886281f7", "0x8561cd0f7a6dbcddd83fcd7f472d7dbcba95b2d4fb98276f48fccf69f76d284e626d7e41314b633352df8e6333fd52a1", "0xb42557ccce32d9a894d538c48712cb3e212d06ac05cd5e0527ccd2db1078ee6ae399bf6a601ffdab1f5913d35fc0b20c", "0x89b4008d767aad3c6f93c349d3b956e28307311a5b1cec237e8d74bb0dee7e972c24f347fd56afd915a2342bd7bc32f0", "0x877487384b207e53f5492f4e36c832c2227f92d1bb60542cfeb35e025a4a7afc2b885fae2528b33b40ab09510398f83e", "0x8c411050b63c9053dd0cd81dacb48753c3d7f162028098e024d17cd6348482703a69df31ad6256e3d25a8bbf7783de39", "0xa8506b54a88d17ac10fb1b0d1fe4aa40eae7553a064863d7f6b52ccc4236dd4b82d01dca6ba87da9a239e3069ba879fb", "0xb1a24caef9df64750c1350789bb8d8a0db0f39474a1c74ea9ba064b1516db6923f00af8d57c632d58844fb8786c3d47a", "0x959d6e255f212b0708c58a2f75cb1fe932248c9d93424612c1b8d1e640149656059737e4db2139afd5556bcdacf3eda2", "0x84525af21a8d78748680b6535bbc9dc2f0cf9a1d1740d12f382f6ecb2e73811d6c1da2ad9956070b1a617c61fcff9fe5", "0xb74417d84597a485d0a8e1be07bf78f17ebb2e7b3521b748f73935b9afbbd82f34b710fb7749e7d4ab55b0c7f9de127d", "0xa4a9aecb19a6bab167af96d8b9d9aa5308eab19e6bfb78f5a580f9bf89bdf250a7b52a09b75f715d651cb73febd08e84", "0x9777b30be2c5ffe7d29cc2803a562a32fb43b59d8c3f05a707ab60ec05b28293716230a7d264d7cd9dd358fc031cc13e", "0x95dce7a3d4f23ac0050c510999f5fbf8042f771e8f8f94192e17bcbfa213470802ebdbe33a876cb621cf42e275cbfc8b", "0xb0b963ebcbbee847ab8ae740478544350b3ac7e86887e4dfb2299ee5096247cd2b03c1de74c774d9bde94ae2ee2dcd59", "0xa4ab20bafa316030264e13f7ef5891a2c3b29ab62e1668fcb5881f50a9acac6adbe3d706c07e62f2539715db768f6c43", "0x901478a297669d608e406fe4989be75264b6c8be12169aa9e0ad5234f459ca377f78484ffd2099a2fe2db5e457826427", "0x88c76e5c250810c057004a03408b85cd918e0c8903dc55a0dd8bb9b4fc2b25c87f9b8cf5943eb19fbbe99d36490050c5", "0x91607322bbad4a4f03fc0012d0821eff5f8c516fda45d1ec1133bface6f858bf04b25547be24159cab931a7aa08344d4", "0x843203e07fce3c6c81f84bc6dc5fb5e9d1c50c8811ace522dc66e8658433a0ef9784c947e6a62c11bf705307ef05212e", "0x91dd8813a5d6dddcda7b0f87f672b83198cd0959d8311b2b26fb1fae745185c01f796fbd03aad9db9b58482483fdadd8", "0x8d15911aacf76c8bcd7136e958febd6963104addcd751ce5c06b6c37213f9c4fb0ffd4e0d12c8e40c36d658999724bfd", "0x8a36c5732d3f1b497ebe9250610605ee62a78eaa9e1a45f329d09aaa1061131cf1d9df00f3a7d0fe8ad614a1ff9caaae", "0xa407d06affae03660881ce20dab5e2d2d6cddc23cd09b95502a9181c465e57597841144cb34d22889902aff23a76d049", "0xb5fd856d0578620a7e25674d9503be7d97a2222900e1b4738c1d81ff6483b144e19e46802e91161e246271f90270e6cf", "0x91b7708869cdb5a7317f88c0312d103f8ce90be14fb4f219c2e074045a2a83636fdc3e69e862049fc7c1ef000e832541", "0xb64719cc5480709d1dae958f1d3082b32a43376da446c8f9f64cb02a301effc9c34d9102051733315a8179aed94d53cc", "0x94347a9542ff9d18f7d9eaa2f4d9b832d0e535fe49d52aa2de08aa8192400eddabdb6444a2a78883e27c779eed7fdf5a", "0x840ef44a733ff1376466698cd26f82cf56bb44811e196340467f932efa3ae1ef9958a0701b3b032f50fd9c1d2aed9ab5", "0x90ab3f6f67688888a31ffc2a882bb37adab32d1a4b278951a21646f90d03385fc976715fc639a785d015751171016f10", "0xb56f35d164c24b557dbcbc8a4bfa681ec916f8741ffcb27fb389c164f4e3ed2be325210ef5bdaeae7a172ca9599ab442", "0xa7921a5a80d7cf6ae81ba9ee05e0579b18c20cd2852762c89d6496aa4c8ca9d1ca2434a67b2c16d333ea8e382cdab1e3", "0xa506bcfbd7e7e5a92f68a1bd87d07ad5fe3b97aeee40af2bf2cae4efcd77fff03f872732c5b7883aa6584bee65d6f8cb", "0xa8c46cff58931a1ce9cbe1501e1da90b174cddd6d50f3dfdfb759d1d4ad4673c0a8feed6c1f24c7af32865a7d6c984e5", "0xb45686265a83bff69e312c5149db7bb70ac3ec790dc92e392b54d9c85a656e2bf58596ce269f014a906eafc97461aa5f", "0x8d4009a75ccb2f29f54a5f16684b93202c570d7a56ec1a8b20173269c5f7115894f210c26b41e8d54d4072de2d1c75d0", "0xaef8810af4fc676bf84a0d57b189760ddc3375c64e982539107422e3de2580b89bd27aa6da44e827b56db1b5555e4ee8", "0x888f0e1e4a34f48eb9a18ef4de334c27564d72f2cf8073e3d46d881853ac1424d79e88d8ddb251914890588937c8f711", "0xb64b0aa7b3a8f6e0d4b3499fe54e751b8c3e946377c0d5a6dbb677be23736b86a7e8a6be022411601dd75012012c3555", "0x8d57776f519f0dd912ea14f79fbab53a30624e102f9575c0bad08d2dc754e6be54f39b11278c290977d9b9c7c0e1e0ad", "0xa018fc00d532ceb2e4de908a15606db9b6e0665dd77190e2338da7c87a1713e6b9b61554e7c1462f0f6d4934b960b15c", "0x8c932be83ace46f65c78e145b384f58e41546dc0395270c1397874d88626fdeda395c8a289d602b4c312fe98c1311856", "0x89174838e21639d6bdd91a0621f04dc056907b88e305dd66e46a08f6d65f731dea72ae87ca5e3042d609e8de8de9aa26", "0xb7b7f508bb74f7a827ac8189daa855598ff1d96fa3a02394891fd105d8f0816224cd50ac4bf2ed1cf469ace516c48184", "0xb31877ad682583283baadd68dc1bebd83f5748b165aadd7fe9ef61a343773b88bcd3a022f36d6c92f339b7bfd72820a9", "0xb79d77260b25daf9126dab7a193df2d7d30542786fa1733ffaf6261734770275d3ca8bae1d9915d1181a78510b3439db", "0x91894fb94cd4c1dd2ceaf9c53a7020c5799ba1217cf2d251ea5bc91ed26e1159dd758e98282ebe35a0395ef9f1ed15a0", "0xab59895cdafd33934ceedfc3f0d5d89880482cba6c99a6db93245f9e41987efd76e0640e80aef31782c9a8c7a83fccec", "0xaa22ea63654315e033e09d4d4432331904a6fc5fb1732557987846e3c564668ca67c60a324b4af01663a23af11a9ce4b", "0xb53ba3ef342601467e1f71aa280e100fbabbd38518fa0193e0099505036ee517c1ac78e96e9baeb549bb6879bb698fb0", "0x943fd69fd656f37487cca3605dc7e5a215fddd811caf228595ec428751fc1de484a0cb84c667fe4d7c35599bfa0e5e34", "0x9353128b5ebe0dddc555093cf3e5942754f938173541033e8788d7331fafc56f68d9f97b4131e37963ab7f1c8946f5f1", "0xa76cd3c566691f65cfb86453b5b31dbaf3cab8f84fe1f795dd1e570784b9b01bdd5f0b3c1e233942b1b5838290e00598", "0x983d84b2e53ffa4ae7f3ba29ef2345247ea2377686b74a10479a0ef105ecf90427bf53b74c96dfa346d0f842b6ffb25b", "0x92e0fe9063306894a2c6970c001781cff416c87e87cb5fbac927a3192655c3da4063e6fa93539f6ff58efac6adcc5514", "0xb00a81f03c2b8703acd4e2e4c21e06973aba696415d0ea1a648ace2b0ea19b242fede10e4f9d7dcd61c546ab878bc8f9", "0xb0d08d880f3b456a10bf65cff983f754f545c840c413aea90ce7101a66eb0a0b9b1549d6c4d57725315828607963f15a", "0x90cb64d03534f913b411375cce88a9e8b1329ce67a9f89ca5df8a22b8c1c97707fec727dbcbb9737f20c4cf751359277", "0x8327c2d42590dfcdb78477fc18dcf71608686ad66c49bce64d7ee874668be7e1c17cc1042a754bbc77c9daf50b2dae07", "0x8532171ea13aa7e37178e51a6c775da469d2e26ec854eb16e60f3307db4acec110d2155832c202e9ba525fc99174e3b0", "0x83ca44b15393d021de2a511fa5511c5bd4e0ac7d67259dce5a5328f38a3cce9c3a269405959a2486016bc27bb140f9ff", "0xb1d36e8ca812be545505c8214943b36cabee48112cf0de369957afa796d37f86bf7249d9f36e8e990f26f1076f292b13", "0x9803abf45be5271e2f3164c328d449efc4b8fc92dfc1225d38e09630909fe92e90a5c77618daa5f592d23fc3ad667094", "0xb268ad68c7bf432a01039cd889afae815c3e120f57930d463aece10af4fd330b5bd7d8869ef1bcf6b2e78e4229922edc", "0xa4c91a0d6f16b1553264592b4cbbbf3ca5da32ab053ffbdd3dbb1aed1afb650fb6e0dc5274f71a51d7160856477228db", "0xad89d043c2f0f17806277ffdf3ecf007448e93968663f8a0b674254f36170447b7527d5906035e5e56f4146b89b5af56", "0x8b6964f757a72a22a642e4d69102951897e20c21449184e44717bd0681d75f7c5bfa5ee5397f6e53febf85a1810d6ed1", "0xb08f5cdaabec910856920cd6e836c830b863eb578423edf0b32529488f71fe8257d90aed4a127448204df498b6815d79", "0xaf26bb3358be9d280d39b21d831bb53145c4527a642446073fee5a86215c4c89ff49a3877a7a549486262f6f57a0f476", "0xb4010b37ec4d7c2af20800e272539200a6b623ae4636ecbd0e619484f4ab9240d02bc5541ace3a3fb955dc0a3d774212", "0x82752ab52bdcc3cc2fc405cb05a2e694d3df4a3a68f2179ec0652536d067b43660b96f85f573f26fbd664a9ef899f650", "0x96d392dde067473a81faf2d1fea55b6429126b88b160e39b4210d31d0a82833ffd3a80e07d24d495aea2d96be7251547", "0xa76d8236d6671204d440c33ac5b8deb71fa389f6563d80e73be8b043ec77d4c9b06f9a586117c7f957f4af0331cbc871", "0xb6c90961f68b5e385d85c9830ec765d22a425f506904c4d506b87d8944c2b2c09615e740ed351df0f9321a7b93979cae", "0xa6ec5ea80c7558403485b3b1869cdc63bde239bafdf936d9b62a37031628402a36a2cfa5cfbb8e26ac922cb0a209b3ba", "0x8c3195bbdbf9bc0fc95fa7e3d7f739353c947f7767d1e3cb24d8c8602d8ea0a1790ac30b815be2a2ba26caa5227891e2", "0xa7f8a63d809f1155722c57f375ea00412b00147776ae4444f342550279ef4415450d6f400000a326bf11fea6c77bf941", "0x97fa404df48433a00c85793440e89bb1af44c7267588ae937a1f5d53e01e1c4d4fc8e4a6d517f3978bfdd6c2dfde012f", "0xa984a0a3836de3d8d909c4629a2636aacb85393f6f214a2ef68860081e9db05ad608024762db0dc35e895dc00e2d4cdd", "0x9526cf088ab90335add1db4d3a4ac631b58cbfbe88fa0845a877d33247d1cfeb85994522e1eb8f8874651bfb1df03e2a", "0xac83443fd0afe99ad49de9bf8230158c118e2814c9c89db5ac951c240d6c2ce45e7677221279d9e97848ec466b99aafe", "0xaeeefdbaba612e971697798ceaf63b247949dc823a0ad771ae5b988a5e882b338a98d3d0796230f49d533ec5ba411b39", "0xae3f248b5a7b0f92b7820a6c5ae21e5bd8f4265d4f6e21a22512079b8ee9be06393fd3133ce8ebac0faf23f4f8517e36", "0xa64a831b908eee784b8388b45447d2885ec0551b26b0c2b15e5f417d0a12c79e867fb7bd3d008d0af98b44336f8ec1ad", "0xb242238cd8362b6e440ba21806905714dd55172db25ec7195f3fc4937b2aba146d5cbf3cf691a1384b4752dc3b54d627", "0x819f97f337eea1ffb2a678cc25f556f1aab751c6b048993a1d430fe1a3ddd8bb411c152e12ca60ec6e057c190cd1db9a", "0xb9d7d187407380df54ee9fef224c54eec1bfabf17dc8abf60765b7951f538f59aa26fffd5846cfe05546c35f59b573f4", "0xaa6e3c14efa6a5962812e3f94f8ce673a433f4a82d07a67577285ea0eaa07f8be7115853122d12d6d4e1fdf64c504be1", "0x82268bee9c1662d3ddb5fb785abfae6fb8b774190f30267f1d47091d2cd4b3874db4372625aa36c32f27b0eee986269b", "0xb236459565b7b966166c4a35b2fa71030b40321821b8e96879d95f0e83a0baf33fa25721f30af4a631df209e25b96061", "0x8708d752632d2435d2d5b1db4ad1fa2558d776a013655f88e9a3556d86b71976e7dfe5b8834fdec97682cd94560d0d0d", "0xae1424a68ae2dbfb0f01211f11773732a50510b5585c1fb005cb892b2c6a58f4a55490b5c5b4483c6fce40e9d3236a52", "0xb3f5f722af9dddb07293c871ce97abbccba0093ca98c8d74b1318fa21396fc1b45b69c15084f63d728f9908442024506", "0x9606f3ce5e63886853ca476dc0949e7f1051889d529365c0cb0296fdc02abd088f0f0318ecd2cf36740a3634132d36f6", "0xb11a833a49fa138db46b25ff8cdda665295226595bc212c0931b4931d0a55c99da972c12b4ef753f7e37c6332356e350", "0xafede34e7dab0a9e074bc19a7daddb27df65735581ca24ad70c891c98b1349fcebbcf3ba6b32c2617fe06a5818dabc2d", "0x97993d456e459e66322d01f8eb13918979761c3e8590910453944bdff90b24091bb018ac6499792515c9923be289f99f", "0x977e3e967eff19290a192cd11df3667d511b398fb3ac9a5114a0f3707e25a0edcb56105648b1b85a8b7519fc529fc6f6", "0xb873a7c88bf58731fe1bf61ff6828bf114cf5228f254083304a4570e854e83748fc98683ddba62d978fff7909f2c5c47", "0xad4b2691f6f19da1d123aaa23cca3e876247ed9a4ab23c599afdbc0d3aa49776442a7ceaa996ac550d0313d9b9a36cee", "0xb9210713c78e19685608c6475bfa974b57ac276808a443f8b280945c5d5f9c39da43effa294bfb1a6c6f7b6b9f85bf6c", "0xa65152f376113e61a0e468759de38d742caa260291b4753391ee408dea55927af08a4d4a9918600a3bdf1df462dffe76", "0x8bf8c27ad5140dde7f3d2280fd4cc6b29ab76537e8d7aa7011a9d2796ee3e56e9a60c27b5c2da6c5e14fc866301dc195", "0x92fde8effc9f61393a2771155812b863cff2a0c5423d7d40aa04d621d396b44af94ddd376c28e7d2f53c930aea947484", "0x97a01d1dd9ee30553ce676011aea97fa93d55038ada95f0057d2362ae9437f3ed13de8290e2ff21e3167dd7ba10b9c3f", "0x89affffaa63cb2df3490f76f0d1e1d6ca35c221dd34057176ba739fa18d492355e6d2a5a5ad93a136d3b1fed0bb8aa19", "0x928b8e255a77e1f0495c86d3c63b83677b4561a5fcbbe5d3210f1e0fc947496e426d6bf3b49394a5df796c9f25673fc4", "0x842a0af91799c9b533e79ee081efe2a634cac6c584c2f054fb7d1db67dde90ae36de36cbf712ec9cd1a0c7ee79e151ea", "0xa65b946cf637e090baf2107c9a42f354b390e7316beb8913638130dbc67c918926eb87bec3b1fe92ef72bc77a170fa3b", "0xaafc0f19bfd71ab5ae4a8510c7861458b70ad062a44107b1b1dbacbfa44ba3217028c2824bd7058e2fa32455f624040b", "0x95269dc787653814e0be899c95dba8cfa384f575a25e671c0806fd80816ad6797dc819d30ae06e1d0ed9cb01c3950d47", "0xa1e760f7fa5775a1b2964b719ff961a92083c5c617f637fc46e0c9c20ab233f8686f7f38c3cb27d825c54dd95e93a59b", "0xac3b8a7c2317ea967f229eddc3e23e279427f665c4705c7532ed33443f1243d33453c1088f57088d2ab1e3df690a9cc9", "0xb787beeddfbfe36dd51ec4efd9cf83e59e84d354c3353cc9c447be53ae53d366ed1c59b686e52a92f002142c8652bfe0", "0xb7a64198300cb6716aa7ac6b25621f8bdec46ad5c07a27e165b3f774cdf65bcfdbf31e9bae0c16b44de4b00ada7a4244", "0xb8ae9f1452909e0c412c7a7fe075027691ea8df1347f65a5507bc8848f1d2c833d69748076db1129e5b4fb912f65c86c", "0x9682e41872456b9fa67def89e71f06d362d6c8ca85c9c48536615bc401442711e1c9803f10ab7f8ab5feaec0f9df20a6", "0x88889ff4e271dc1c7e21989cc39f73cde2f0475acd98078281591ff6c944fadeb9954e72334319050205d745d4df73df", "0x8f79b5b8159e7fd0d93b0645f3c416464f39aec353b57d99ecf24f96272df8a068ad67a6c90c78d82c63b40bb73989bb", "0x838c01a009a3d8558a3f0bdd5e22de21af71ca1aefc8423c91dc577d50920e9516880e87dce3e6d086e11cd45c9052d9", "0xb97f1c6eee8a78f137c840667cc288256e39294268a3009419298a04a1d0087c9c9077b33c917c65caf76637702dda8a", "0x972284ce72f96a61c899260203dfa06fc3268981732bef74060641c1a5068ead723e3399431c247ca034b0dae861e8df", "0x945a8d52d6d3db6663dbd3110c6587f9e9c44132045eeffba15621576d178315cb52870fa5861669f84f0bee646183fe", "0xa0a547b5f0967b1c3e5ec6c6a9a99f0578521489180dfdfbb5561f4d166baac43a2f06f950f645ce991664e167537eed", "0xa0592cda5cdddf1340033a745fd13a6eff2021f2e26587116c61c60edead067e0f217bc2bef4172a3c9839b0b978ab35", "0xb9c223b65a3281587fa44ec829e609154b32f801fd1de6950e01eafb07a8324243b960d5735288d0f89f0078b2c42b5b", "0x99ebfc3b8f9f98249f4d37a0023149ed85edd7a5abe062c8fb30c8c84555258b998bdcdd1d400bc0fa2a4aaa8b224466", "0x955b68526e6cb3937b26843270f4e60f9c6c8ece2fa9308fe3e23afa433309c068c66a4bc16ee2cf04220f095e9afce4", "0xb766caeafcc00378135ae53397f8a67ed586f5e30795462c4a35853de6681b1f17401a1c40958de32b197c083b7279c1", "0x921bf87cad947c2c33fa596d819423c10337a76fe5a63813c0a9dc78a728207ae7b339407a402fc4d0f7cba3af6da6fc", "0xa74ba1f3bc3e6c025db411308f49b347ec91da1c916bda9da61e510ec8d71d25e0ac0f124811b7860e5204f93099af27", "0xa29b4d144e0bf17a7e8353f2824cef0ce85621396babe8a0b873ca1e8a5f8d508b87866cf86da348470649fceefd735c", "0xa8040e12ffc3480dd83a349d06741d1572ef91932c46f5cf03aee8454254156ee95786fd013d5654725e674c920cec32", "0x8c4cf34ca60afd33923f219ffed054f90cd3f253ffeb2204a3b61b0183417e366c16c07fae860e362b0f2bfe3e1a1d35", "0x8195eede4ddb1c950459df6c396b2e99d83059f282b420acc34220cadeed16ab65c856f2c52568d86d3c682818ed7b37", "0x91fff19e54c15932260aa990c7fcb3c3c3da94845cc5aa8740ef56cf9f58d19b4c3c55596f8d6c877f9f4d22921d93aa", "0xa3e0bf7e5d02a80b75cf75f2db7e66cb625250c45436e3c136d86297d652590ec97c2311bafe407ad357c79ab29d107b", "0x81917ff87e5ed2ae4656b481a63ced9e6e5ff653b8aa6b7986911b8bc1ee5b8ef4f4d7882c3f250f2238e141b227e510", "0x915fdbe5e7de09c66c0416ae14a8750db9412e11dc576cf6158755fdcaf67abdbf0fa79b554cac4fe91c4ec245be073f", "0x8df27eafb5c3996ba4dc5773c1a45ca77e626b52e454dc1c4058aa94c2067c18332280630cc3d364821ee53bf2b8c130", "0x934f8a17c5cbb827d7868f5c8ca00cb027728a841000a16a3428ab16aa28733f16b52f58c9c4fbf75ccc45df72d9c4df", "0xb83f4da811f9183c25de8958bc73b504cf790e0f357cbe74ef696efa7aca97ad3b7ead1faf76e9f982c65b6a4d888fc2", "0x87188213c8b5c268dc2b6da413f0501c95749e953791b727450af3e43714149c115b596b33b63a2f006a1a271b87efd0", "0x83e9e888ab9c3e30761de635d9aabd31248cdd92f7675fc43e4b21fd96a03ec1dc4ad2ec94fec857ffb52683ac98e360", "0xb4b9a1823fe2d983dc4ec4e3aaea297e581c3fc5ab4b4af5fa1370caa37af2d1cc7fc6bfc5e7da60ad8fdce27dfe4b24", "0x856388bc78aef465dbcdd1f559252e028c9e9a2225c37d645c138e78f008f764124522705822a61326a6d1c79781e189", "0xa6431b36db93c3b47353ba22e7c9592c9cdfb9cbdd052ecf2cc3793f5b60c1e89bc96e6bae117bfd047f2308da00dd2f", "0xb619972d48e7e4291542dcde08f7a9cdc883c892986ded2f23ccb216e245cd8d9ad1d285347b0f9d7611d63bf4cee2bc", "0x8845cca6ff8595955f37440232f8e61d5351500bd016dfadd182b9d39544db77a62f4e0102ff74dd4173ae2c181d24ef", "0xb2f5f7fa26dcd3b6550879520172db2d64ee6aaa213cbef1a12befbce03f0973a22eb4e5d7b977f466ac2bf8323dcedd", "0x858b7f7e2d44bdf5235841164aa8b4f3d33934e8cb122794d90e0c1cac726417b220529e4f896d7b77902ab0ccd35b3a", "0x80b0408a092dae2b287a5e32ea1ad52b78b10e9c12f49282976cd738f5d834e03d1ad59b09c5ccaccc39818b87d06092", "0xb996b0a9c6a2d14d984edcd6ab56bc941674102980d65b3ad9733455f49473d3f587c8cbf661228a7e125ddbe07e3198", "0x90224fcebb36865293bd63af786e0c5ade6b67c4938d77eb0cbae730d514fdd0fe2d6632788e858afd29d46310cf86df", "0xb71351fdfff7168b0a5ec48397ecc27ac36657a8033d9981e97002dcca0303e3715ce6dd3f39423bc8ef286fa2e9e669", "0xae2a3f078b89fb753ce4ed87e0c1a58bb19b4f0cfb6586dedb9fcab99d097d659a489fb40e14651741e1375cfc4b6c5f", "0x8ef476b118e0b868caed297c161f4231bbeb863cdfa5e2eaa0fc6b6669425ce7af50dc374abceac154c287de50c22307", "0x92e46ab472c56cfc6458955270d3c72b7bde563bb32f7d4ab4d959db6f885764a3d864e1aa19802fefaa5e16b0cb0b54", "0x96a3f68323d1c94e73d5938a18a377af31b782f56212de3f489d22bc289cf24793a95b37f1d6776edf88114b5c1fa695", "0x962cc068cfce6faaa27213c4e43e44eeff0dfbb6d25b814e82c7da981fb81d7d91868fa2344f05fb552362f98cfd4a72", "0x895d4e4c4ad670abf66d43d59675b1add7afad7438ada8f42a0360c704cee2060f9ac15b4d27e9b9d0996bb801276fe3", "0xb3ad18d7ece71f89f2ef749b853c45dc56bf1c796250024b39a1e91ed11ca32713864049c9aaaea60cde309b47486bbf", "0x8f05404e0c0258fdbae50e97ccb9b72ee17e0bd2400d9102c0dad981dac8c4c71585f03e9b5d50086d0a2d3334cb55d1", "0x8bd877e9d4591d02c63c6f9fc9976c109de2d0d2df2bfa5f6a3232bab5b0b8b46e255679520480c2d7a318545efa1245", "0x8d4c16b5d98957c9da13d3f36c46f176e64e5be879f22be3179a2c0e624fe4758a82bf8c8027410002f973a3b84cd55a", "0x86e2a8dea86427b424fa8eada881bdff896907084a495546e66556cbdf070b78ba312bf441eb1be6a80006d25d5097a3", "0x8608b0c117fd8652fdab0495b08fadbeba95d9c37068e570de6fddfef1ba4a1773b42ac2be212836141d1bdcdef11a17", "0xa13d6febf5fb993ae76cae08423ca28da8b818d6ef0fde32976a4db57839cd45b085026b28ee5795f10a9a8e3098c683", "0x8e261967fa6de96f00bc94a199d7f72896a6ad8a7bbb1d6187cca8fad824e522880e20f766620f4f7e191c53321d70f9", "0x8b8e8972ac0218d7e3d922c734302803878ad508ca19f5f012bc047babd8a5c5a53deb5fe7c15a4c00fd6d1cb9b1dbd0", "0xb5616b233fb3574a2717d125a434a2682ff68546dccf116dd8a3b750a096982f185614b9fb6c7678107ff40a451f56fa", "0xaa6adf9b0c3334b0d0663f583a4914523b2ac2e7adffdb026ab9109295ff6af003ef8357026dbcf789896d2afded8d73", "0xacb72df56a0b65496cd534448ed4f62950bb1e11e50873b6ed349c088ee364441821294ce0f7c61bd7d38105bea3b442", "0xabae12df83e01ec947249fedd0115dc501d2b03ff7232092979eda531dbbca29ace1d46923427c7dde4c17bdf3fd7708", "0x820b4fc2b63a9fda7964acf5caf19a2fc4965007cb6d6b511fcafcb1f71c3f673a1c0791d3f86e3a9a1eb6955b191cc0", "0xaf277259d78c6b0f4f030a10c53577555df5e83319ddbad91afbd7c30bc58e7671c56d00d66ec3ab5ef56470cd910cee", "0xad4a861c59f1f5ca1beedd488fb3d131dea924fffd8e038741a1a7371fad7370ca5cf80dc01f177fbb9576713bb9a5b3", "0xb67a5162982ce6a55ccfb2f177b1ec26b110043cf18abd6a6c451cf140b5af2d634591eb4f28ad92177d8c7e5cd0a5e8", "0x96176d0a83816330187798072d449cbfccff682561e668faf6b1220c9a6535b32a6e4f852e8abb00f79abb87493df16b", "0xb0afe6e7cb672e18f0206e4423f51f8bd0017bf464c4b186d46332c5a5847647f89ff7fa4801a41c1b0b42f6135bcc92", "0x8fc5e7a95ef20c1278c645892811f6fe3f15c431ebc998a32ec0da44e7213ea934ed2be65239f3f49b8ec471e9914160", "0xb7793e41adda6c82ba1f2a31f656f6205f65bf8a3d50d836ee631bc7ce77c153345a2d0fc5c60edf8b37457c3729c4ec", "0xa504dd7e4d6b2f4379f22cc867c65535079c75ccc575955f961677fa63ecb9f74026fa2f60c9fb6323c1699259e5e9c8", "0xab899d00ae693649cc1afdf30fb80d728973d2177c006e428bf61c7be01e183866614e05410041bc82cb14a33330e69c", "0x8a3bd8b0b1be570b65c4432a0f6dc42f48a2000e30ab089cf781d38f4090467b54f79c0d472fcbf18ef6a00df69cc6f3", "0xb4d7028f7f76a96a3d7803fca7f507ae11a77c5346e9cdfccb120a833a59bda1f4264e425aa588e7a16f8e7638061d84", "0xb9c7511a76ea5fb105de905d44b02edb17008335766ee357ed386b7b3cf19640a98b38785cb14603c1192bee5886c9b6", "0x8563afb12e53aed71ac7103ab8602bfa8371ae095207cb0d59e8fd389b6ad1aff0641147e53cb6a7ca16c7f37c9c5e6b", "0x8e108be614604e09974a9ed90960c28c4ea330a3d9a0cb4af6dd6f193f84ab282b243ecdf549b3131036bebc8905690c", "0xb794d127fbedb9c5b58e31822361706ffac55ce023fbfe55716c3c48c2fd2f2c7660a67346864dfe588812d369cb50b6", "0xb797a3442fc3b44f41baefd30346f9ac7f96e770d010d53c146ce74ce424c10fb62758b7e108b8abfdc5fafd89d745cb", "0x993bb71e031e8096442e6205625e1bfddfe6dd6a83a81f3e2f84fafa9e5082ab4cad80a099f21eff2e81c83457c725c3", "0x8711ab833fc03e37acf2e1e74cfd9133b101ff4144fe30260654398ae48912ab46549d552eb9d15d2ea57760d35ac62e", "0xb21321fd2a12083863a1576c5930e1aecb330391ef83326d9d92e1f6f0d066d1394519284ddab55b2cb77417d4b0292f", "0x877d98f731ffe3ee94b0b5b72d127630fa8a96f6ca4f913d2aa581f67732df6709493693053b3e22b0181632ac6c1e3b", "0xae391c12e0eb8c145103c62ea64f41345973311c3bf7281fa6bf9b7faafac87bcf0998e5649b9ef81e288c369c827e07", "0xb83a2842f36998890492ab1cd5a088d9423d192681b9a3a90ec518d4c541bce63e6c5f4df0f734f31fbfdd87785a2463", "0xa21b6a790011396e1569ec5b2a423857b9bec16f543e63af28024e116c1ea24a3b96e8e4c75c6537c3e4611fd265e896", "0xb4251a9c4aab3a495da7a42e684ba4860dbcf940ad1da4b6d5ec46050cbe8dab0ab9ae6b63b5879de97b905723a41576", "0x8222f70aebfe6ac037f8543a08498f4cadb3edaac00336fc00437eb09f2cba758f6c38e887cc634b4d5b7112b6334836", "0x86f05038e060594c46b5d94621a1d9620aa8ba59a6995baf448734e21f58e23c1ea2993d3002ad5250d6edd5ba59b34f", "0xa7c0c749baef811ab31b973c39ceb1d94750e2bc559c90dc5eeb20d8bb6b78586a2b363c599ba2107d6be65cd435f24e", "0x861d46a5d70b38d6c1cd72817a2813803d9f34c00320c8b62f8b9deb67f5b5687bc0b37c16d28fd017367b92e05da9ca", "0xb3365d3dab639bffbe38e35383686a435c8c88b397b717cd4aeced2772ea1053ceb670f811f883f4e02975e5f1c4ac58", "0xa5750285f61ab8f64cd771f6466e2c0395e01b692fd878f2ef2d5c78bdd8212a73a3b1dfa5e4c8d9e1afda7c84857d3b", "0x835a10809ccf939bc46cf950a33b36d71be418774f51861f1cd98a016ade30f289114a88225a2c11e771b8b346cbe6ef", "0xa4f59473a037077181a0a62f1856ec271028546ca9452b45cedfcb229d0f4d1aabfc13062b07e536cc8a0d4b113156a2", "0x95cd14802180b224d44a73cc1ed599d6c4ca62ddcaa503513ccdc80aaa8be050cc98bd4b4f3b639549beb4587ac6caf9", "0x973b731992a3e69996253d7f36dd7a0af1982b5ed21624b77a7965d69e9a377b010d6dabf88a8a97eec2a476259859cc", "0xaf8a1655d6f9c78c8eb9a95051aa3baaf9c811adf0ae8c944a8d3fcba87b15f61021f3baf6996fa0aa51c81b3cb69de1", "0x835aad5c56872d2a2d6c252507b85dd742bf9b8c211ccb6b25b52d15c07245b6d89b2a40f722aeb5083a47cca159c947", "0xabf4e970b02bef8a102df983e22e97e2541dd3650b46e26be9ee394a3ea8b577019331857241d3d12b41d4eacd29a3ac", "0xa13c32449dbedf158721c13db9539ae076a6ce5aeaf68491e90e6ad4e20e20d1cdcc4a89ed9fd49cb8c0dd50c17633c1", "0x8c8f78f88b7e22dd7e9150ab1c000f10c28e696e21d85d6469a6fe315254740f32e73d81ab1f3c1cf8f544c86df506e8", "0xb4b77f2acfe945abf81f2605f906c10b88fb4d28628487fb4feb3a09f17f28e9780445dfcee4878349d4c6387a9d17d4", "0x8d255c235f3812c6ecc646f855fa3832be5cb4dbb9c9e544989fafdf3f69f05bfd370732eaf954012f0044aa013fc9c6", "0xb982efd3f34b47df37c910148ac56a84e8116647bea24145a49e34e0a6c0176e3284d838dae6230cb40d0be91c078b85", "0x983f365aa09bd85df2a6a2ad8e4318996b1e27d02090755391d4486144e40d80b1fbfe1c798d626db92f52e33aa634da", "0x95fd1981271f3ea3a41d654cf497e6696730d9ff7369f26bc4d7d15c7adb4823dd0c42e4a005a810af12d234065e5390", "0xa9f5219bd4b913c186ef30c02f995a08f0f6f1462614ea5f236964e02bdaa33db9d9b816c4aee5829947840a9a07ba60", "0x9210e6ceb05c09b46fd09d036287ca33c45124ab86315e5d6911ff89054f1101faaa3e83d123b7805056d388bcec6664", "0x8ed9cbf69c6ff3a5c62dd9fe0d7264578c0f826a29e614bc2fb4d621d90c8c9992438accdd7a614b1dca5d1bb73dc315", "0x85cf2a8cca93e00da459e3cecd22c342d697eee13c74d5851634844fc215f60053cf84b0e03c327cb395f48d1c71a8a4", "0x8818a18e9a2ec90a271b784400c1903089ffb0e0b40bc5abbbe12fbebe0f731f91959d98c5519ef1694543e31e2016d4", "0x8dabc130f296fa7a82870bf9a8405aaf542b222ed9276bba9bd3c3555a0f473acb97d655ee7280baff766a827a8993f0", "0xac7952b84b0dc60c4d858f034093b4d322c35959605a3dad2b806af9813a4680cb038c6d7f4485b4d6b2ff502aaeca25", "0xad65cb6d57b48a2602568d2ec8010baed0eb440eec7638c5ec8f02687d764e9de5b5d42ad5582934e592b48471c22d26", "0xa02ab8bd4c3d114ea23aebdd880952f9495912817da8c0c08eabc4e6755439899d635034413d51134c72a6320f807f1c", "0x8319567764b8295402ec1ebef4c2930a138480b37e6d7d01c8b4c9cd1f2fc3f6e9a44ae6e380a0c469b25b06db23305f", "0xafec53b2301dc0caa8034cd9daef78c48905e6068d692ca23d589b84a6fa9ddc2ed24a39480597e19cb3e83eec213b3f", "0xac0b4ffdb5ae08e586a9cdb98f9fe56f4712af3a97065e89e274feacfb52b53c839565aee93c4cfaaccfe51432c4fab0", "0x8972cbf07a738549205b1094c5987818124144bf187bc0a85287c94fdb22ce038c0f11df1aa16ec5992e91b44d1af793", "0xb7267aa6f9e3de864179b7da30319f1d4cb2a3560f2ea980254775963f1523b44c680f917095879bebfa3dc2b603efcf", "0x80f68f4bfc337952e29504ee5149f15093824ea7ab02507efd1317a670f6cbc3611201848560312e3e52e9d9af72eccf", "0x8897fee93ce8fc1e1122e46b6d640bba309384dbd92e46e185e6364aa8210ebf5f9ee7e5e604b6ffba99aa80a10dd7d0", "0xb58ea6c02f2360be60595223d692e82ee64874fda41a9f75930f7d28586f89be34b1083e03bbc1575bbfdda2d30db1ea", "0x85a523a33d903280d70ac5938770453a58293480170c84926457ac2df45c10d5ff34322ab130ef4a38c916e70d81af53", "0xa2cbf045e1bed38937492c1f2f93a5ba41875f1f262291914bc1fc40c60bd0740fb3fea428faf6da38b7c180fe8ac109", "0x8c09328770ed8eb17afc6ac7ddd87bb476de18ed63cab80027234a605806895959990c47bd10d259d7f3e2ecb50074c9", "0xb4b9e19edb4a33bde8b7289956568a5b6b6557404e0a34584b5721fe6f564821091013fbb158e2858c6d398293bb4b59", "0x8a47377df61733a2aa5a0e945fce00267f8e950f37e109d4487d92d878fb8b573317bb382d902de515b544e9e233458d", "0xb5804c9d97efeff5ca94f3689b8088c62422d92a1506fd1d8d3b1b30e8a866ad0d6dad4abfa051dfc4471250cac4c5d9", "0x9084a6ee8ec22d4881e9dcc8a9eb3c2513523d8bc141942370fd191ad2601bf9537a0b1e84316f3209b3d8a54368051e", "0x85447eea2fa26656a649f8519fa67279183044791d61cf8563d0783d46d747d96af31d0a93507bbb2242666aa87d3720", "0x97566a84481027b60116c751aec552adfff2d9038e68d48c4db9811fb0cbfdb3f1d91fc176a0b0d988a765f8a020bce1", "0xae87e5c1b9e86c49a23dceda4ecfd1dcf08567f1db8e5b6ec752ebd45433c11e7da4988573cdaebbb6f4135814fc059e", "0xabee05cf9abdbc52897ac1ce9ed157f5466ed6c383d6497de28616238d60409e5e92619e528af8b62cc552bf09970dc2", "0xae6d31cd7bf9599e5ee0828bab00ceb4856d829bba967278a73706b5f388465367aa8a6c7da24b5e5f1fdd3256ef8e63", "0xac33e7b1ee47e1ee4af472e37ab9e9175260e506a4e5ce449788075da1b53c44cb035f3792d1eea2aa24b1f688cc6ed3", "0x80f65b205666b0e089bb62152251c48c380a831e5f277f11f3ef4f0d52533f0851c1b612267042802f019ec900dc0e8f", "0x858520ad7aa1c9fed738e3b583c84168f2927837ad0e1d326afe9935c26e9b473d7f8c382e82ef1fe37d2b39bb40a1ee", "0xb842dd4af8befe00a97c2d0f0c33c93974761e2cb9e5ab8331b25170318ddd5e4bdbc02d8f90cbfdd5f348f4f371c1f7", "0x8bf2cb79bc783cb57088aae7363320cbeaabd078ffdec9d41bc74ff49e0043d0dad0086a30e5112b689fd2f5a606365d", "0x982eb03bbe563e8850847cd37e6a3306d298ab08c4d63ab6334e6b8c1fa13fce80cf2693b09714c7621d74261a0ff306", "0xb143edb113dec9f1e5105d4a93fbe502b859e587640d3db2f628c09a17060e6aec9e900e2c8c411cda99bc301ff96625", "0xaf472d9befa750dcebc5428fe1a024f18ec1c07bca0f95643ce6b5f4189892a910285afb03fd7ed7068fbe614e80d33c", "0xa97e3bc57ede73ecd1bbf02de8f51b4e7c1a067da68a3cd719f4ba26a0156cbf1cef2169fd35a18c5a4cced50d475998", "0xa862253c937cf3d75d7183e5f5be6a4385d526aeda5171c1c60a8381fea79f88f5f52a4fab244ecc70765d5765e6dfd5", "0x90cb776f8e5a108f1719df4a355bebb04bf023349356382cae55991b31720f0fd03206b895fa10c56c98f52453be8778", "0xa7614e8d0769dccd520ea4b46f7646e12489951efaef5176bc889e9eb65f6e31758df136b5bf1e9107e68472fa9b46ec", "0xac3a9b80a3254c42e5ed3a090a0dd7aee2352f480de96ad187027a3bb6c791eddfc3074b6ffd74eea825188f107cda4d", "0x82a01d0168238ef04180d4b6e0a0e39024c02c2d75b065017c2928039e154d093e1af4503f4d1f3d8a948917abb5d09f", "0x8fab000a2b0eef851a483aec8d2dd85fe60504794411a2f73ed82e116960547ac58766cb73df71aea71079302630258d", "0x872451a35c6db61c63e9b8bb9f16b217f985c20be4451c14282c814adb29d7fb13f201367c664435c7f1d4d9375d7a58", "0x887d9ff54cc96b35d562df4a537ff972d7c4b3fd91ab06354969a4cfede0b9fc68bbffb61d0dbf1a58948dc701e54f5a", "0x8cb5c2a6bd956875d88f41ae24574434f1308514d44057b55c9c70f13a3366ed054150eed0955a38fda3f757be73d55f", "0x89ad0163cad93e24129d63f8e38422b7674632a8d0a9016ee8636184cab177659a676c4ee7efba3abe1a68807c656d60", "0xb9ec01c7cab6d00359b5a0b4a1573467d09476e05ca51a9227cd16b589a9943d161eef62dcc73f0de2ec504d81f4d252", "0x8031d17635d39dfe9705c485d2c94830b6fc9bc67b91300d9d2591b51e36a782e77ab5904662effa9382d9cca201f525", "0x8be5a5f6bc8d680e5092d6f9a6585acbaaaa2ddc671da560dcf5cfa4472f4f184b9597b5b539438accd40dda885687cc", "0xb1fc0f052fae038a2e3de3b3a96b0a1024b009de8457b8b3adb2d315ae68a89af905720108a30038e5ab8d0d97087785", "0x8b8bdc77bd3a6bc7ca5492b6f8c614852c39a70d6c8a74916eaca0aeb4533b11898b8820a4c2620a97bf35e275480029", "0xaf35f4dc538d4ad5cdf710caa38fd1eb496c3fa890a047b6a659619c5ad3054158371d1e88e0894428282eed9f47f76b", "0x8166454a7089cc07758ad78724654f4e7a1a13e305bbf88ddb86f1a4b2904c4fc8ab872d7da364cdd6a6c0365239e2ad", "0xab287c7d3addce74ce40491871c768abe01daaa0833481276ff2e56926b38a7c6d2681ffe837d2cc323045ad1a4414f9", "0xb90317f4505793094d89365beb35537f55a6b5618904236258dd04ca61f21476837624a2f45fef8168acf732cab65579", "0x98ae5ea27448e236b6657ab5ef7b1cccb5372f92ab25f5fa651fbac97d08353a1dae1b280b1cd42b17d2c6a70a63ab9d", "0xadcf54e752d32cbaa6cb98fbca48d8cd087b1db1d131d465705a0d8042c8393c8f4d26b59006eb50129b21e6240f0c06", "0xb591a3e4db18a7345fa935a8dd7994bbac5cc270b8ebd84c8304c44484c7a74afb45471fdbe4ab22156a30fae1149b40", "0x806b53ac049a42f1dcc1d6335505371da0bf27c614f441b03bbf2e356be7b2fb4eed7117eabcce9e427a542eaa2bf7d8", "0x800482e7a772d49210b81c4a907f5ce97f270b959e745621ee293cf8c71e8989363d61f66a98f2d16914439544ca84c7", "0x99de9eafdad3617445312341644f2bb888680ff01ce95ca9276b1d2e5ef83fa02dab5e948ebf66c17df0752f1bd37b70", "0x961ee30810aa4c93ae157fbe9009b8e443c082192bd36a73a6764ff9b2ad8b0948fe9a73344556e01399dd77badb4257", "0xae0a361067c52efbe56c8adf982c00432cd478929459fc7f74052c8ee9531cd031fe1335418fde53f7c2ef34254eb7ac", "0xa3503d16b6b27eb20c1b177bcf90d13706169220523a6271b85b2ce35a9a2b9c5bed088540031c0a4ebfdae3a4c6ab04", "0x909420122c3e723289ca4e7b81c2df5aff312972a2203f4c45821b176e7c862bf9cac7f7df3adf1d59278f02694d06e7", "0x989f42380ae904b982f85d0c6186c1aef5d6bcba29bcfbb658e811b587eb2749c65c6e4a8cc6409c229a107499a4f5d7", "0x8037a6337195c8e26a27ea4ef218c6e7d79a9720aaab43932d343192abc2320fe72955f5e431c109093bda074103330a", "0xb312e168663842099b88445e940249cc508f080ab0c94331f672e7760258dbd86be5267e4cf25ea25facb80bff82a7e9", "0xaaa3ff8639496864fcdbfdda1ac97edc4f08e3c9288b768f6c8073038c9fbbf7e1c4bea169b4d45c31935cdf0680d45e", "0x97dbd3df37f0b481a311dfc5f40e59227720f367912200d71908ef6650f32cc985cb05b981e3eea38958f7e48d10a15d", "0xa89d49d1e267bb452d6cb621b9a90826fe55e9b489c0427b94442d02a16f390eed758e209991687f73f6b5a032321f42", "0x9530dea4e0e19d6496f536f2e75cf7d814d65fde567055eb20db48fd8d20d501cd2a22fb506db566b94c9ee10f413d43", "0x81a7009b9e67f1965fa7da6a57591c307de91bf0cd35ab4348dc4a98a4961e096d004d7e7ad318000011dc4342c1b809", "0x83440a9402b766045d7aca61a58bba2aa29cac1cf718199e472ba086f5d48093d9dda4d135292ba51d049a23964eceae", "0xa06c9ce5e802df14f6b064a3d1a0735d429b452f0e2e276042800b0a4f16df988fd94cf3945921d5dd3802ab2636f867", "0xb1359e358b89936dee9e678a187aad3e9ab14ac40e96a0a68f70ee2583cdcf467ae03bef4215e92893f4e12f902adec8", "0x835304f8619188b4d14674d803103d5a3fa594d48e96d9699e653115dd05fdc2dda6ba3641cf7ad53994d448da155f02", "0x8327cba5a9ff0d3f5cd0ae55e77167448926d5fcf76550c0ad978092a14122723090c51c415e88e42a2b62eb07cc3981", "0xb373dcdaea85f85ce9978b1426a7ef4945f65f2d3467a9f1cc551a99766aac95df4a09e2251d3f89ca8c9d1a7cfd7b0e", "0xab1422dc41af2a227b973a6fd124dfcb2367e2a11a21faa1d381d404f51b7257e5bc82e9cf20cd7fe37d7ae761a2ab37", "0xa93774a03519d2f20fdf2ef46547b0a5b77c137d6a3434b48d56a2cbef9e77120d1b85d0092cf8842909213826699477", "0x8eb967a495a38130ea28711580b7e61bcd1d051cd9e4f2dbf62f1380bd86e0d60e978d72f6f31e909eb97b3b9a2b867c", "0xae8213378da1287ba1fe4242e1acaec19b877b6fe872400013c6eac1084b8d03156792fa3020201725b08228a1e80f49", "0xb143daf6893d674d607772b3b02d8ac48f294237e2f2c87963c0d4e26d9227d94a2a13512457c3d5883544bbc259f0ef", "0xb343bd2aca8973888e42542218924e2dda2e938fd1150d06878af76f777546213912b7c7a34a0f94186817d80ffa185c", "0xb188ebc6a8c3007001aa347ae72cc0b15d09bc6c19a80e386ee4b334734ec0cc2fe8b493c2422f38d1e6d133cc3db6fe", "0xb795f6a8b9b826aaeee18ccd6baf6c5adeeec85f95eb5b6d19450085ec7217e95a2d9e221d77f583b297d0872073ba0e", "0xb1c7dbd998ad32ae57bfa95deafa147024afd57389e98992c36b6e52df915d3d5a39db585141ec2423173e85d212fed8", "0x812bcdeb9fe5f12d0e1df9964798056e1f1c3de3b17b6bd2919b6356c4b86d8e763c01933efbe0224c86a96d5198a4be", "0xb19ebeda61c23d255cbf472ef0b8a441f4c55b70f0d8ed47078c248b1d3c7c62e076b43b95c00a958ec8b16d5a7cb0d7", "0xb02adc9aaa20e0368a989c2af14ff48b67233d28ebee44ff3418bb0473592e6b681af1cc45450bd4b175df9051df63d9", "0x8d87f0714acee522eb58cec00360e762adc411901dba46adc9227124fa70ee679f9a47e91a6306d6030dd4eb8de2f3c1", "0x8be54cec21e74bcc71de29dc621444263737db15f16d0bb13670f64e42f818154e04b484593d19ef95f2ee17e4b3fe21", "0xab8e20546c1db38d31493b5d5f535758afb17e459645c1b70813b1cf7d242fd5d1f4354a7c929e8f7259f6a25302e351", "0x89f035a1ed8a1e302ac893349ba8ddf967580fcb6e73d44af09e3929cde445e97ff60c87dafe489e2c0ab9c9986cfa00", "0x8b2b0851a795c19191a692af55f7e72ad2474efdc5401bc3733cfdd910e34c918aaebe69d5ea951bdddf3c01cabbfc67", "0xa4edb52c2b51495ccd1ee6450fc14b7b3ede8b3d106808929d02fb31475bacb403e112ba9c818d2857651e508b3a7dd1", "0x9569341fded45d19f00bcf3cbf3f20eb2b4d82ef92aba3c8abd95866398438a2387437e580d8b646f17cf6fde8c5af23", "0xaa4b671c6d20f72f2f18a939a6ff21cc37e0084b44b4a717f1be859a80b39fb1be026b3205adec2a66a608ec2bcd578f", "0x94902e980de23c4de394ad8aec91b46f888d18f045753541492bfbb92c59d3daa8de37ae755a6853744af8472ba7b72b", "0xaf651ef1b2a0d30a7884557edfad95b6b5d445a7561caebdc46a485aedd25932c62c0798465c340a76f6feaa196dd712", "0xb7b669b8e5a763452128846dd46b530dca4893ace5cc5881c7ddcd3d45969d7e73fbebdb0e78aa81686e5f7b22ec5759", "0x82507fd4ebe9fa656a7f2e084d64a1fa6777a2b0bc106d686e2d9d2edafc58997e58cb6bfd0453b2bf415704aa82ae62", "0xb40bce2b42b88678400ecd52955bbdadd15f8b9e1b3751a1a3375dc0efb5ca3ee258cf201e1140b3c09ad41217d1d49e", "0xb0210d0cbb3fbf3b8cdb39e862f036b0ff941cd838e7aaf3a8354e24246e64778d22f3de34572e6b2a580614fb6425be", "0x876693cba4301b251523c7d034108831df3ce133d8be5a514e7a2ca494c268ca0556fa2ad8310a1d92a16b55bcd99ea9", "0x8660281406d22a4950f5ef050bf71dd3090edb16eff27fa29ef600cdea628315e2054211ed2cc6eaf8f2a1771ef689fd", "0xa610e7e41e41ab66955b809ba4ade0330b8e9057d8efc9144753caed81995edeb1a42a53f93ce93540feca1fae708dac", "0xa49e2c176a350251daef1218efaccc07a1e06203386ede59c136699d25ca5cb2ac1b800c25b28dd05678f14e78e51891", "0x83e0915aa2b09359604566080d411874af8c993beba97d4547782fdbe1a68e59324b800ff1f07b8db30c71adcbd102a8", "0xa19e84e3541fb6498e9bb8a099c495cbfcad113330e0262a7e4c6544495bb8a754b2208d0c2d895c93463558013a5a32", "0x87f2bd49859a364912023aca7b19a592c60214b8d6239e2be887ae80b69ebdeb59742bdebcfa73a586ab23b2c945586c", "0xb8e8fdddae934a14b57bc274b8dcd0d45ebb95ddbaabef4454e0f6ce7d3a5a61c86181929546b3d60c447a15134d08e1", "0x87e0c31dcb736ea4604727e92dc1d9a3cf00adcff79df3546e02108355260f3dd171531c3c0f57be78d8b28058fcc8c0", "0x9617d74e8f808a4165a8ac2e30878c349e1c3d40972006f0787b31ea62d248c2d9f3fc3da83181c6e57e95feedfd0e8c", "0x8949e2cee582a2f8db86e89785a6e46bc1565c2d8627d5b6bf43ba71ffadfab7e3c5710f88dcb5fb2fc6edf6f4fae216", "0xad3fa7b0edceb83118972a2935a09f409d09a8db3869f30be3a76f67aa9fb379cabb3a3aff805ba023a331cad7d7eb64", "0x8c95718a4112512c4efbd496be38bf3ca6cdcaad8a0d128f32a3f9aae57f3a57bdf295a3b372a8c549fda8f4707cffed", "0x88f3261d1e28a58b2dee3fcc799777ad1c0eb68b3560f9b4410d134672d9533532a91ea7be28a041784872632d3c9d80", "0xb47472a41d72dd2e8b72f5c4f8ad626737dde3717f63d6bc776639ab299e564cbad0a2ad5452a07f02ff49a359c437e5", "0x9896d21dc2e8aad87b76d6df1654f10cd7bceed4884159d50a818bea391f8e473e01e14684814c7780235f28e69dca6e", "0x82d47c332bbd31bbe83b5eb44a23da76d4a7a06c45d7f80f395035822bc27f62f59281d5174e6f8e77cc9b5c3193d6f0", "0x95c74cd46206e7f70c9766117c34c0ec45c2b0f927a15ea167901a160e1530d8522943c29b61e03568aa0f9c55926c53", "0xa89d7757825ae73a6e81829ff788ea7b3d7409857b378ebccd7df73fdbe62c8d9073741cf038314971b39af6c29c9030", "0x8c1cd212d0b010905d560688cfc036ae6535bc334fa8b812519d810b7e7dcf1bb7c5f43deaa40f097158358987324a7f", "0xb86993c383c015ed8d847c6b795164114dd3e9efd25143f509da318bfba89389ea72a420699e339423afd68b6512fafb", "0x8d06bd379c6d87c6ed841d8c6e9d2d0de21653a073725ff74be1934301cc3a79b81ef6dd0aad4e7a9dc6eac9b73019bc", "0x81af4d2d87219985b9b1202d724fe39ef988f14fef07dfe3c3b11714e90ffba2a97250838e8535eb63f107abfe645e96", "0x8c5e0af6330a8becb787e4b502f34f528ef5756e298a77dc0c7467433454347f3a2e0bd2641fbc2a45b95e231c6e1c02", "0x8e2a8f0f04562820dc8e7da681d5cad9fe2e85dd11c785fb6fba6786c57a857e0b3bd838fb849b0376c34ce1665e4837", "0xa39be8269449bfdfc61b1f62077033649f18dae9bef7c6163b9314ca8923691fb832f42776f0160b9e8abd4d143aa4e1", "0x8c154e665706355e1cc98e0a4cabf294ab019545ba9c4c399d666e6ec5c869ca9e1faf8fb06cd9c0a5c2f51a7d51b70a", "0xa046a7d4de879d3ebd4284f08f24398e9e3bf006cd4e25b5c67273ade248689c69affff92ae810c07941e4904296a563", "0xafd94c1cb48758e5917804df03fb38a6da0e48cd9b6262413ea13b26973f9e266690a1b7d9d24bbaf7e82718e0e594b0", "0x859e21080310c8d6a38e12e2ac9f90a156578cdeb4bb2e324700e97d9a5511cd6045dc39d1d0de3f94aeed043a24119d", "0xa219fb0303c379d0ab50893264919f598e753aac9065e1f23ef2949abc992577ab43c636a1d2c089203ec9ddb941e27d", "0xb0fdb639d449588a2ca730afcba59334e7c387342d56defdfb7ef79c493f7fd0e5277eff18e7203e756c7bdda5803047", "0x87f9c3b7ed01f54368aca6dbcf2f6e06bff96e183c4b2c65f8baa23b377988863a0a125d5cdd41a072da8462ced4c070", "0x99ef7a5d5ac2f1c567160e1f8c95f2f38d41881850f30c461a205f7b1b9fb181277311333839b13fb3ae203447e17727", "0xaeaca9b1c2afd24e443326cc68de67b4d9cedb22ad7b501a799d30d39c85bb2ea910d4672673e39e154d699e12d9b3dc", "0xa11675a1721a4ba24dd3d0e4c3c33a6edf4cd1b9f6b471070b4386c61f77452266eae6e3f566a40cfc885eada9a29f23", "0xb228334445e37b9b49cb4f2cc56b454575e92173ddb01370a553bba665adadd52df353ad74470d512561c2c3473c7bb9", "0xa18177087c996572d76f81178d18ed1ceebc8362a396348ce289f1d8bd708b9e99539be6fccd4acb1112381cfc5749b4", "0x8e7b8bf460f0d3c99abb19803b9e43422e91507a1c0c22b29ee8b2c52d1a384da4b87c292e28eff040db5be7b1f8641f", "0xb03d038d813e29688b6e6f444eb56fec3abba64c3d6f890a6bcf2e916507091cdb2b9d2c7484617be6b26552ed1c56cb", "0xa1c88ccd30e934adfc5494b72655f8afe1865a84196abfb376968f22ddc07761210b6a9fb7638f1413d1b4073d430290", "0x961b714faebf172ad2dbc11902461e286e4f24a99a939152a53406117767682a571057044decbeb3d3feef81f4488497", "0xa03dc4059b46effdd786a0a03cc17cfee8585683faa35bb07936ded3fa3f3a097f518c0b8e2db92fd700149db1937789", "0xadf60180c99ca574191cbcc23e8d025b2f931f98ca7dfcebfc380226239b6329347100fcb8b0fcb12db108c6ad101c07", "0x805d4f5ef24d46911cbf942f62cb84b0346e5e712284f82b0db223db26d51aabf43204755eb19519b00e665c7719fcaa", "0x8dea7243e9c139662a7fe3526c6c601eee72fd8847c54c8e1f2ad93ef7f9e1826b170afe58817dac212427164a88e87f", "0xa2ba42356606d651b077983de1ad643650997bb2babb188c9a3b27245bb65d2036e46667c37d4ce02cb1be5ae8547abe", "0xaf2ae50b392bdc013db2d12ce2544883472d72424fc767d3f5cb0ca2d973fc7d1f425880101e61970e1a988d0670c81b", "0x98e6bec0568d3939b31d00eb1040e9b8b2a35db46ddf4369bdaee41bbb63cc84423d29ee510a170fb5b0e2df434ba589", "0x822ff3cd12fbef4f508f3ca813c04a2e0b9b799c99848e5ad3563265979e753ee61a48f6adc2984a850f1b46c1a43d35", "0x891e8b8b92a394f36653d55725ef514bd2e2a46840a0a2975c76c2a935577f85289026aaa74384da0afe26775cbddfb9", "0xb2a3131a5d2fe7c8967047aa66e4524babae941d90552171cc109527f345f42aa0df06dcbb2fa01b33d0043917bbed69", "0x80c869469900431f3eeefafdbe07b8afd8cee7739e659e6d0109b397cacff85a88247698f87dc4e2fe39a592f250ac64", "0x9091594f488b38f9d2bb5df49fd8b4f8829d9c2f11a197dd1431ed5abbc5c954bbde3387088f9ee3a5a834beb7619bce", "0xb472e241e6956146cca57b97a8a204668d050423b4e76f857bad5b47f43b203a04c8391ba9d9c3e95093c071f9d376a1", "0xb7dd2de0284844392f7dfb56fe7ca3ede41e27519753ffc579a0a8d2d65ceb8108d06b6b0d4c3c1a2588951297bd1a1e", "0x902116ce70d0a079ac190321c1f48701318c05f8e69ee09694754885d33a835a849cafe56f499a2f49f6cda413ddf9a7", "0xb18105cc736787fafaf7c3c11c448bce9466e683159dff52723b7951dff429565e466e4841d982e3aaa9ee2066838666", "0x97ab9911f3f659691762d568ae0b7faa1047b0aed1009c319fa79d15d0db8db9f808fc385dc9a68fa388c10224985379", "0xb2a2cba65f5b927e64d2904ba412e2bac1cf18c9c3eda9c72fb70262497ecf505b640827e2afebecf10eebbcf48ccd3e", "0xb36a3fd677baa0d3ef0dac4f1548ff50a1730286b8c99d276a0a45d576e17b39b3cbadd2fe55e003796d370d4be43ce3", "0xa5dfec96ca3c272566e89dc453a458909247e3895d3e44831528130bc47cc9d0a0dac78dd3cad680a4351d399d241967", "0x8029382113909af6340959c3e61db27392531d62d90f92370a432aec3eb1e4c36ae1d4ef2ba8ec6edb4d7320c7a453f6", "0x971d85121ea108e6769d54f9c51299b0381ece8b51d46d49c89f65bedc123bab4d5a8bc14d6f67f4f680077529cbae4c", "0x98ff6afc01d0bec80a278f25912e1b1ebff80117adae72e31d5b9fa4d9624db4ba2065b444df49b489b0607c45e26c4c", "0x8fa29be10fb3ab30ce25920fec0187e6e91e458947009dabb869aade7136c8ba23602682b71e390c251f3743164cbdaa", "0xb3345c89eb1653418fe3940cf3e56a9a9c66526389b98f45ca02dd62bfb37baa69a4baaa7132d7320695f8ea6ad1fd94", "0xb72c7f5541c9ac6b60a7ec9f5415e7fb14da03f7164ea529952a29399f3a071576608dbbcc0d45994f21f92ddbeb1e19", "0xaa3450bb155a5f9043d0ef95f546a2e6ade167280bfb75c9f09c6f9cdb1fffb7ce8181436161a538433afa3681c7a141", "0x92a18fecaded7854b349f441e7102b638ababa75b1b0281dd0bded6541abe7aa37d96693595be0b01fe0a2e2133d50f9", "0x980756ddf9d2253cfe6c94960b516c94889d09e612810935150892627d2ecee9a2517e04968eea295d0106850c04ca44", "0xae68c6ccc454318cdd92f32b11d89116a3b8350207a36d22a0f626718cad671d960090e054c0c77ac3162ae180ecfd4b", "0x99f31f66eaaa551749ad91d48a0d4e3ff4d82ef0e8b28f3184c54e852422ba1bdafd53b1e753f3a070f3b55f3c23b6a2", "0xa44eaeaa6589206069e9c0a45ff9fc51c68da38d4edff1d15529b7932e6f403d12b9387019c44a1488a5d5f27782a51f", "0xb80b5d54d4b344840e45b79e621bd77a3f83fb4ce6d8796b7d6915107b3f3c34d2e7d95bdafd120f285669e5acf2437a", "0xb36c069ec085a612b5908314d6b84c00a83031780261d1c77a0384c406867c9847d5b0845deddfa512cc04a8df2046fb", "0xb09dbe501583220f640d201acea7ee3e39bf9eda8b91aa07b5c50b7641d86d71acb619b38d27835ce97c3759787f08e9", "0x87403d46a2bf63170fff0b857acacf42ee801afe9ccba8e5b4aea967b68eac73a499a65ca46906c2eb4c8f27bc739faa", "0x82b93669f42a0a2aa5e250ffe6097269da06a9c02fcd1801abbad415a7729a64f830754bafc702e64600ba47671c2208", "0x8e3a3029be7edb8dd3ab1f8216664c8dc50d395f603736061d802cef77627db7b859ef287ed850382c13b4d22d6a2d80", "0x968e9ec7194ff424409d182ce0259acd950c384c163c04463bc8700a40b79beba6146d22b7fa7016875a249b7b31c602", "0x8b42c984bbe4996e0c20862059167c6bdc5164b1ffcd928f29512664459212d263e89f0f0e30eed4e672ffa5ed0b01b5", "0x96bac54062110dada905363211133f1f15dc7e4fd80a4c6e4a83bc9a0bcbbaba11cd2c7a13debcf0985e1a954c1da66b", "0xa16dc8a653d67a7cd7ae90b2fffac0bf1ca587005430fe5ba9403edd70ca33e38ba5661d2ed6e9d2864400d997626a62", "0xa68ab11a570a27853c8d67e491591dcba746bfbee08a2e75ae0790399130d027ed387f41ef1d7de8df38b472df309161", "0x92532b74886874447c0300d07eda9bbe4b41ed25349a3da2e072a93fe32c89d280f740d8ff70d5816793d7f2b97373cc", "0x88e35711b471e89218fd5f4d0eadea8a29405af1cd81974427bc4a5fb26ed60798daaf94f726c96e779b403a2cd82820", "0xb5c72aa4147c19f8c4f3a0a62d32315b0f4606e0a7025edc5445571eaf4daff64f4b7a585464821574dd50dbe1b49d08", "0x9305d9b4095258e79744338683fd93f9e657367b3ab32d78080e51d54eec331edbc224fad5093ebf8ee4bd4286757eb8", "0xb2a17abb3f6a05bcb14dc7b98321fa8b46d299626c73d7c6eb12140bf4c3f8e1795250870947af817834f033c88a59d6", "0xb3477004837dbd8ba594e4296f960fc91ab3f13551458445e6c232eb04b326da803c4d93e2e8dcd268b4413305ff84da", "0x924b4b2ebaafdcfdfedb2829a8bf46cd32e1407d8d725a5bd28bdc821f1bafb3614f030ea4352c671076a63494275a3f", "0x8b81b9ef6125c82a9bece6fdcb9888a767ac16e70527753428cc87c56a1236e437da8be4f7ecfe57b9296dc3ae7ba807", "0x906e19ec8b8edd58bdf9ae05610a86e4ea2282b1bbc1e8b00b7021d093194e0837d74cf27ac9916bdb8ec308b00da3da", "0xb41c5185869071760ac786078a57a2ab4e2af60a890037ac0c0c28d6826f15c2cf028fddd42a9b6de632c3d550bfbc14", "0xa646e5dec1b713ae9dfdf7bdc6cd474d5731a320403c7dfcfd666ffc9ae0cff4b5a79530e8df3f4aa9cb80568cb138e9", "0xb0efad22827e562bd3c3e925acbd0d9425d19057868608d78c2209a531cccd0f2c43dc5673acf9822247428ffa2bb821", "0xa94c19468d14b6f99002fc52ac06bbe59e5c472e4a0cdb225144a62f8870b3f10593749df7a2de0bd3c9476ce682e148", "0x803864a91162f0273d49271dafaab632d93d494d1af935aefa522768af058fce52165018512e8d6774976d52bd797e22", "0xa08711c2f7d45c68fb340ac23597332e1bcaec9198f72967b9921204b9d48a7843561ff318f87908c05a44fc35e3cc9d", "0x91c3cad94a11a3197ae4f9461faab91a669e0dddb0371d3cab3ed9aeb1267badc797d8375181130e461eadd05099b2a2", "0x81bdaaf48aae4f7b480fc13f1e7f4dd3023a41439ba231760409ce9292c11128ab2b0bdbbf28b98af4f97b3551f363af", "0x8d60f9df9fd303f625af90e8272c4ecb95bb94e6efc5da17b8ab663ee3b3f673e9f6420d890ccc94acf4d2cae7a860d8", "0xa7b75901520c06e9495ab983f70b61483504c7ff2a0980c51115d11e0744683ce022d76e3e09f4e99e698cbd21432a0d", "0x82956072df0586562fda7e7738226f694e1c73518dd86e0799d2e820d7f79233667192c9236dcb27637e4c65ef19d493", "0xa586beb9b6ffd06ad200957490803a7cd8c9bf76e782734e0f55e04a3dc38949de75dc607822ec405736c576cf83bca3", "0xa179a30d00def9b34a7e85607a447eea0401e32ab5abeee1a281f2acd1cf6ec81a178020666f641d9492b1bdf66f05a3", "0x83e129705c538787ed8e0fdc1275e6466a3f4ee21a1e6abedd239393b1df72244723b92f9d9d9339a0cab6ebf28f5a16", "0x811bd8d1e3722b64cd2f5b431167e7f91456e8bba2cc669d3fbbce7d553e29c3c19f629fcedd2498bc26d33a24891d17", "0xa243c030c858f1f60cccd26b45b024698cc6d9d9e6198c1ed4964a235d9f8d0baf9cde10c8e63dfaa47f8e74e51a6e85", "0xab839eb82e23ca52663281f863b55b0a3d6d4425c33ffb4eeb1d7979488ab068bf99e2a60e82cea4dc42c56c26cbfebe", "0x8b896f9bb21d49343e67aec6ad175b58c0c81a3ca73d44d113ae4354a0065d98eb1a5cafedaf232a2bb9cdc62152f309", "0xaf6230340cc0b66f5bf845540ed4fc3e7d6077f361d60762e488d57834c3e7eb7eacc1b0ed73a7d134f174a01410e50c", "0x88975e1b1af678d1b5179f72300a30900736af580dd748fd9461ef7afccc91ccd9bed33f9da55c8711a7635b800e831f", "0xa97486bb9047391661718a54b8dd5a5e363964e495eae6c692730264478c927cf3e66dd3602413189a3699fbeae26e15", "0xa5973c161ab38732885d1d2785fd74bf156ba34881980cba27fe239caef06b24a533ffe6dbbbeca5e6566682cc00300a", "0xa24776e9a840afda0003fa73b415d5bd6ecd9b5c2cc842b643ee51b8c6087f4eead4d0bfbd987eb174c489a7b952ff2a", "0xa8a6ee06e3af053b705a12b59777267c546f33ba8a0f49493af8e6df4e15cf8dd2d4fb4daf7e84c6b5d3a7363118ff03", "0xa28e59ce6ad02c2ce725067c0123117e12ac5a52c8f5af13eec75f4a9efc4f696777db18a374fa33bcae82e0734ebd16", "0x86dfc3b78e841c708aff677baa8ee654c808e5d257158715097c1025d46ece94993efe12c9d188252ad98a1e0e331fec", "0xa88d0275510f242eab11fdb0410ff6e1b9d7a3cbd3658333539815f1b450a84816e6613d15aa8a8eb15d87cdad4b27a2", "0x8440acea2931118a5b481268ff9f180ee4ede85d14a52c026adc882410825b8275caa44aff0b50c2b88d39f21b1a0696", "0xa7c3182eab25bd6785bacf12079d0afb0a9b165d6ed327814e2177148539f249eb9b5b2554538f54f3c882d37c0a8abe", "0x85291fbe10538d7da38efdd55a7acebf03b1848428a2f664c3ce55367aece60039f4f320b1771c9c89a35941797f717c", "0xa2c6414eeb1234728ab0de94aa98fc06433a58efa646ca3fcbd97dbfb8d98ae59f7ce6d528f669c8149e1e13266f69c9", "0x840c8462785591ee93aee2538d9f1ec44ba2ca61a569ab51d335ac873f5d48099ae8d7a7efa0725d9ff8f9475bfa4f56", "0xa7065a9d02fb3673acf7702a488fbc01aa69580964932f6f40b6c2d1c386b19e50b0e104fcac24ea26c4e723611d0238", "0xb72db6d141267438279e032c95e6106c2ccb3164b842ba857a2018f3a35f4b040da92680881eb17cd61d0920d5b8f006", "0xa8005d6c5960e090374747307ef0be2871a7a43fa4e76a16c35d2baab808e9777b496e9f57a4218b23390887c33a0b55", "0x8e152cea1e00a451ca47c20a1e8875873419700af15a5f38ee2268d3fbc974d4bd5f4be38008fa6f404dbdedd6e6e710", "0xa3391aed1fcd68761f06a7d1008ec62a09b1cb3d0203cd04e300a0c91adfed1812d8bc1e4a3fd7976dc0aae0e99f52f1", "0x967eb57bf2aa503ee0c6e67438098149eac305089c155f1762cf5e84e31f0fbf27c34a9af05621e34645c1ec96afaec8", "0x88af97ddc4937a95ec0dcd25e4173127260f91c8db2f6eac84afb789b363705fb3196235af631c70cafd09411d233589", "0xa32df75b3f2c921b8767638fd289bcfc61e08597170186637a7128ffedd52c798c434485ac2c7de07014f9e895c2c3d8", "0xb0a783832153650aa0d766a3a73ec208b6ce5caeb40b87177ffc035ab03c7705ecdd1090b6456a29f5fb7e90e2fa8930", "0xb59c8e803b4c3486777d15fc2311b97f9ded1602fa570c7b0200bada36a49ee9ef4d4c1474265af8e1c38a93eb66b18b", "0x982f2c85f83e852022998ff91bafbb6ff093ef22cf9d5063e083a48b29175ccbd51b9c6557151409e439096300981a6c", "0x939e3b5989fefebb9d272a954659a4eb125b98c9da6953f5e628d26266bd0525ec38304b8d56f08d65abc4d6da4a8dbb", "0x8898212fe05bc8de7d18503cb84a1c1337cc2c09d1eeef2b475aa79185b7322bf1f8e065f1bf871c0c927dd19faf1f6d", "0x94b0393a41cd00f724aee2d4bc72103d626a5aecb4b5486dd1ef8ac27528398edf56df9db5c3d238d8579af368afeb09", "0x96ac564450d998e7445dd2ea8e3fc7974d575508fa19e1c60c308d83b645864c029f2f6b7396d4ff4c1b24e92e3bac37", "0x8adf6638e18aff3eb3b47617da696eb6c4bdfbecbbc3c45d3d0ab0b12cbad00e462fdfbe0c35780d21aa973fc150285e", "0xb53f94612f818571b5565bbb295e74bada9b5f9794b3b91125915e44d6ddcc4da25510eab718e251a09c99534d6042d9", "0x8b96462508d77ee083c376cd90807aebad8de96bca43983c84a4a6f196d5faf6619a2351f43bfeec101864c3bf255519", "0xaeadf34657083fc71df33bd44af73bf5281c9ca6d906b9c745536e1819ea90b56107c55e2178ebad08f3ba75b3f81c86", "0x9784ba29b2f0057b5af1d3ab2796d439b8753f1f749c73e791037461bdfc3f7097394283105b8ab01788ea5255a96710", "0x8756241bda159d4a33bf74faba0d4594d963c370fb6a18431f279b4a865b070b0547a6d1613cf45b8cfb5f9236bbf831", "0xb03ebfd6b71421dfd49a30460f9f57063eebfe31b9ceaa2a05c37c61522b35bdc09d7db3ad75c76c253c00ba282d3cd2", "0xb34e7e6341fa9d854b2d3153bdda0c4ae2b2f442ab7af6f99a0975d45725aa48e36ae5f7011edd249862e91f499687d4", "0xb462ee09dc3963a14354244313e3444de5cc37ea5ccfbf14cd9aca8027b59c4cb2a949bc30474497cab8123e768460e6", "0xaea753290e51e2f6a21a9a0ee67d3a2713f95c2a5c17fe41116c87d3aa77b1683761264d704df1ac34f8b873bc88ef7b", "0x98430592afd414394f98ddfff9f280fcb1c322dbe3510f45e1e9c4bb8ee306b3e0cf0282c0ee73ebb8ba087d4d9e0858", "0xb95d3b5aaf54ffca11f4be8d57f76e14afdb20afc859dc7c7471e0b42031e8f3d461b726ecb979bdb2f353498dfe95ea", "0x984d17f9b11a683132e0b5a9ee5945e3ff7054c2d5c716be73b29078db1d36f54c6e652fd2f52a19da313112e97ade07", "0xab232f756b3fff3262be418a1af61a7e0c95ceebbc775389622a8e10610508cd6784ab7960441917a83cc191c58829ea", "0xa28f41678d6e60de76b0e36ab10e4516e53e02e9c77d2b5af3cfeee3ce94cfa30c5797bd1daab20c98e1cad83ad0f633", "0xb55395fca84dd3ccc05dd480cb9b430bf8631ff06e24cb51d54519703d667268c2f8afcde4ba4ed16bece8cc7bc8c6e0", "0x8a8a5392a0e2ea3c7a8c51328fab11156004e84a9c63483b64e8f8ebf18a58b6ffa8fe8b9d95af0a2f655f601d096396", "0xab480000fe194d23f08a7a9ec1c392334e9c687e06851f083845121ce502c06b54dda8c43092bcc1035df45cc752fe9b", "0xb265644c29f628d1c7e8e25a5e845cabb21799371814730a41a363e1bda8a7be50fee7c3996a365b7fcba4642add10db", "0xb8a915a3c685c2d4728f6931c4d29487cad764c5ce23c25e64b1a3259ac27235e41b23bfe7ae982921b4cb84463097df", "0x8efa7338442a4b6318145a5440fc213b97869647eeae41b9aa3c0a27ee51285b73e3ae3b4a9423df255e6add58864aa9", "0x9106d65444f74d217f4187dfc8fcf3810b916d1e4275f94f6a86d1c4f3565b131fd6cde1fa708bc05fe183c49f14941a", "0x948252dac8026bbbdb0a06b3c9d66ec4cf9532163bab68076fda1bd2357b69e4b514729c15aaa83b5618b1977bbc60c4", "0xae6596ccfdf5cbbc5782efe3bb0b101bb132dbe1d568854ca24cacc0b2e0e9fabcb2ca7ab42aecec412efd15cf8cb7a2", "0x84a0b6c198ff64fd7958dfd1b40eac9638e8e0b2c4cd8cf5d8cdf80419baee76a05184bce6c5b635f6bf2d30055476a7", "0x8893118be4a055c2b3da593dbca51b1ae2ea2469911acfb27ee42faf3e6c3ad0693d3914c508c0b05b36a88c8b312b76", "0xb097479e967504deb6734785db7e60d1d8034d6ca5ba9552887e937f5e17bb413fccac2c1d1082154ed76609127860ad", "0xa0294e6b9958f244d29943debf24b00b538b3da1116269b6e452bb12dc742226712fd1a15b9c88195afeb5d2415f505c", "0xb3cc15f635080bc038f61b615f62b5b5c6f2870586191f59476e8368a73641d6ac2f7d0c1f54621982defdb318020230", "0x99856f49b9fe1604d917c94d09cc0ed753d13d015d30587a94e6631ffd964b214e607deb8a69a8b5e349a7edf4309206", "0xa8571e113ea22b4b4fce41a094da8c70de37830ae32e62c65c2fa5ad06a9bc29e884b945e73d448c72b176d6ecebfb58", "0xa9e9c6e52beb0013273c29844956b3ce291023678107cdc785f7b44eff5003462841ad8780761b86aefc6b734adde7cf", "0x80a784b0b27edb51ef2bad3aee80e51778dcaa0f3f5d3dcb5dc5d4f4b2cf7ae35b08de6680ea9dac53f8438b92eb09ef", "0x827b543e609ea328e97e373f70ad72d4915a2d1daae0c60d44ac637231070e164c43a2a58db80a64df1c624a042b38f9", "0xb449c65e8195202efdcb9bdb4e869a437313b118fef8b510cbbf8b79a4e99376adb749b37e9c20b51b31ed3310169e27", "0x8ea3028f4548a79a94c717e1ed28ad4d8725b8d6ab18b021063ce46f665c79da3c49440c6577319dab2d036b7e08f387", "0x897798431cfb17fe39f08f5f854005dc37b1c1ec1edba6c24bc8acb3b88838d0534a75475325a5ea98b326ad47dbad75", "0x89cf232e6303b0751561960fd4dea5754a28c594daf930326b4541274ffb03c7dd75938e411eb9a375006a70ce38097f", "0x9727c6ae7f0840f0b6c8bfb3a1a5582ceee705e0b5c59b97def7a7a2283edd4d3f47b7971e902a3a2079e40b53ff69b8", "0xb76ed72b122c48679d221072efc0eeea063cb205cbf5f9ef0101fd10cb1075b8628166c83577cced654e1c001c7882f7", "0xae908c42d208759da5ee9b405df85a6532ea35c6f0f6a1288d22870f59d98edc896841b8ac890a538e6c8d1e8b02d359", "0x809d12fe4039a0ec80dc9be6a89acaab7797e5f7f9b163378f52f9a75a1d73b2e9ae6e3dd49e32ced439783c1cabbef5", "0xa4149530b7f85d1098ba534d69548c6c612c416e8d35992fc1f64f4deeb41e09e49c6cf7aadbed7e846b91299358fe2d", "0xa49342eacd1ec1148b8df1e253b1c015f603c39de11fa0a364ccb86ea32d69c34fd7aa6980a1fadcd8e785a57fa46f60", "0x87d43eff5a006dc4dddcf76cc96c656a1f3a68f19f124181feab86c6cc9a52cb9189cdbb423414defdd9bb0ca8ff1ddc", "0x861367e87a9aa2f0f68296ba50aa5dbc5713008d260cc2c7e62d407c2063064749324c4e8156dc21b749656cfebce26b", "0xb5303c2f72e84e170e66ae1b0fbd51b8c7a6f27476eaf5694b64e8737d5c84b51fe90100b256465a4c4156dd873cddb0", "0xb62849a4f891415d74f434cdc1d23c4a69074487659ca96e1762466b2b7a5d8525b056b891d0feea6fe6845cba8bc7fb", "0x923dd9e0d6590a9307e8c4c23f13bae3306b580e297a937711a8b13e8de85e41a61462f25b7d352b682e8437bf2b4ab3", "0x9147379860cd713cd46c94b8cdf75125d36c37517fbecf81ace9680b98ce6291cd1c3e472f84249cc3b2b445e314b1b6", "0xa808a4f17ac21e3fb5cfef404e61fae3693ca3e688d375f99b6116779696059a146c27b06de3ac36da349b0649befd56", "0x87787e9322e1b75e66c1f0d9ea0915722a232770930c2d2a95e9478c4b950d15ab767e30cea128f9ed65893bfc2d0743", "0x9036a6ee2577223be105defe1081c48ea7319e112fff9110eb9f61110c319da25a6cea0464ce65e858635b079691ef1f", "0xaf5548c7c24e1088c23b57ee14d26c12a83484c9fd9296edf1012d8dcf88243f20039b43c8c548c265ef9a1ffe9c1c88", "0xa0fff520045e14065965fb8accd17e878d3fcaf9e0af2962c8954e50be6683d31fa0bf4816ab68f08630dbac6bfce52a", "0xb4c1b249e079f6ae1781af1d97a60b15855f49864c50496c09c91fe1946266915b799f0406084d7783f5b1039116dd8b", "0x8b0ffa5e7c498cb3879dddca34743b41eee8e2dea3d4317a6e961b58adb699ef0c92400c068d5228881a2b08121226bf", "0x852ae8b19a1d80aa8ae5382e7ee5c8e7670ceb16640871c56b20b96b66b3b60e00015a3dde039446972e57b49a999ddd", "0xa49942f04234a7d8492169da232cfff8051df86e8e1ba3db46aede02422c689c87dc1d99699c25f96cb763f5ca0983e5", "0xb04b597b7760cf5dcf411ef896d1661e6d5b0db3257ac2cf64b20b60c6cc18fa10523bb958a48d010b55bac7b02ab3b1", "0xa494591b51ea8285daecc194b5e5bd45ae35767d0246ac94fae204d674ee180c8e97ff15f71f28b7aeb175b8aea59710", "0x97d2624919e78406e7460730680dea8e71c8571cf988e11441aeea54512b95bd820e78562c99372d535d96f7e200d20d", "0xac693ddb00e48f76e667243b9b6a7008424043fb779e4f2252330285232c3fccac4da25cbd6d95fe9ad959ff305a91f6", "0x8d20ca0a71a64a3f702a0825bb46bd810d03bebfb227683680d474a52f965716ff99e19a165ebaf6567987f4f9ee3c94", "0xa5c516a438f916d1d68ca76996404792e0a66e97b7f18fc54c917bf10cf3211b62387932756e39e67e47b0bd6e88385a", "0xb089614d830abc0afa435034cec7f851f2f095d479cacf1a3fb57272da826c499a52e7dcbc0eb85f4166fb94778e18e9", "0xa8dacc943765d930848288192f4c69e2461c4b9bc6e79e30eeef9a543318cf9ae9569d6986c65c5668a89d49993f8e07", "0xab5a9361fa339eec8c621bdad0a58078983abd8942d4282b22835d7a3a47e132d42414b7c359694986f7db39386c2e19", "0x94230517fb57bd8eb26c6f64129b8b2abd0282323bf7b94b8bac7fab27b4ecc2c4290c294275e1a759de19f2216134f3", "0xb8f158ea5006bc3b90b285246625faaa6ac9b5f5030dc69701b12f3b79a53ec7e92eeb5a63bbd1f9509a0a3469ff3ffc", "0x8b6944fd8cb8540957a91a142fdcda827762aa777a31e8810ca6d026e50370ee1636fc351724767e817ca38804ebe005", "0x82d1ee40fe1569c29644f79fa6c4033b7ed45cd2c3b343881f6eb0de2e79548fded4787fae19bed6ee76ed76ff9f2f11", "0xa8924c7035e99eaed244ca165607e7e568b6c8085510dcdbaf6ebdbed405af2e6c14ee27d94ffef10d30aa52a60bf66d", "0x956f82a6c2ae044635e85812581e4866c5fa2f427b01942047d81f6d79a14192f66fbbe77c9ffeaef4e6147097fdd2b5", "0xb1100255a1bcf5e05b6aff1dfeb6e1d55b5d68d43a7457ba10cc76b61885f67f4d0d5179abda786e037ae95deb8eea45", "0x99510799025e3e5e8fbf06dedb14c060c6548ba2bda824f687d3999dc395e794b1fb6514b9013f3892b6cf65cb0d65aa", "0x8f9091cebf5e9c809aab415942172258f894e66e625d7388a05289183f01b8d994d52e05a8e69f784fba41db9ea357f0", "0xa13d2eeb0776bdee9820ecb6693536720232848c51936bb4ef4fe65588d3f920d08a21907e1fdb881c1ad70b3725e726", "0xa68b8f18922d550284c5e5dc2dda771f24c21965a6a4d5e7a71678178f46df4d8a421497aad8fcb4c7e241aba26378a0", "0x8b7601f0a3c6ad27f03f2d23e785c81c1460d60100f91ea9d1cab978aa03b523150206c6d52ce7c7769c71d2c8228e9e", "0xa8e02926430813caa851bb2b46de7f0420f0a64eb5f6b805401c11c9091d3b6d67d841b5674fa2b1dce0867714124cd8", "0xb7968ecba568b8193b3058400af02c183f0a6df995a744450b3f7e0af7a772454677c3857f99c140bbdb2a09e832e8e0", "0x8f20b1e9ba87d0a3f35309b985f3c18d2e8800f1ca7f0c52cadef773f1496b6070c936eea48c4a1cae83fd2524e9d233", "0x88aef260042db0d641a51f40639dbeeefa9e9811df30bee695f3791f88a2f84d318f04e8926b7f47bf25956cb9e3754f", "0x9725345893b647e9ba4e6a29e12f96751f1ae25fcaec2173e9a259921a1a7edb7a47159b3c8767e44d9e2689f5aa0f72", "0x8c281e6f72752cb11e239e4df9341c45106eb7993c160e54423c2bffe10bc39d42624b45a1f673936ef2e1a02fc92f1a", "0x90aba2f68bddb2fcce6c51430dacdfeec43ea8dc379660c99095df11017691ccf5faa27665cf4b9f0eea7728ae53c327", "0xb7022695c16521c5704f49b7ddbdbec9b5f57ce0ceebe537bc0ebb0906d8196cc855a9afeb8950a1710f6a654464d93f", "0x8fe1b9dd3c6a258116415d36e08374e094b22f0afb104385a5da48be17123e86fb8327baacc4f0d9ebae923d55d99bb5", "0x817e85d8e3d19a4cbc1dec31597142c2daa4871bda89c2177fa719c00eda3344eb08b82eb92d4aa91a9eaacb3fc09783", "0xb59053e1081d2603f1ca0ba553804d6fa696e1fd996631db8f62087b26a40dfef02098b0326bb75f99ec83b9267ca738", "0x990a173d857d3ba81ff3789b931bfc9f5609cde0169b7f055fa3cb56451748d593d62d46ba33f80f9cafffe02b68dd14", "0xb0c538dbba4954b809ab26f9f94a3cf1dcb77ce289eaec1d19f556c0ae4be1fa03af4a9b7057837541c3cc0a80538736", "0xac3ba42f5f44f9e1fc453ce49c4ab79d0e1d5c42d3b30b1e098f3ab3f414c4c262fa12fb2be249f52d4aaf3c5224beb9", "0xaf47467eb152e59870e21f0d4da2f43e093daf40180ab01438030684b114d025326928eaab12c41b81a066d94fce8436", "0x98d1b58ba22e7289b1c45c79a24624f19b1d89e00f778eef327ec4856a9a897278e6f1a9a7e673844b31dde949153000", "0x97ccb15dfadc7c59dca08cfe0d22df2e52c684cf97de1d94bc00d7ba24e020025130b0a39c0f4d46e4fc872771ee7875", "0xb699e4ed9a000ff96ca296b2f09dce278832bc8ac96851ff3cff99ed3f6f752cfc0fea8571be28cd9b5a7ec36f1a08ee", "0xb9f49f0edb7941cc296435ff0a912e3ad16848ee8765ab5f60a050b280d6ea585e5b34051b15f6b8934ef01ceb85f648", "0xac3893df7b4ceab23c6b9054e48e8ba40d6e5beda8fbe90b814f992f52494186969b35d8c4cdc3c99890a222c9c09008", "0xa41293ad22fae81dea94467bc1488c3707f3d4765059173980be93995fa4fcc3c9340796e3eed0beeb0ba0d9bb4fa3aa", "0xa0543e77acd2aeecde13d18d258aeb2c7397b77f17c35a1992e8666ea7abcd8a38ec6c2741bd929abba2f766138618cc", "0x92e79b22bc40e69f6527c969500ca543899105837b6b1075fa1796755c723462059b3d1b028e0b3df2559fa440e09175", "0xa1fa1eac8f41a5197a6fb4aa1eae1a031c89f9c13ff9448338b222780cf9022e0b0925d930c37501a0ef7b2b00fdaf83", "0xb3cb29ff73229f0637335f28a08ad8c5f166066f27c6c175164d0f26766a927f843b987ee9b309ed71cbf0a65d483831", "0x84d4ab787f0ac00f104f4a734dc693d62d48c2aeb03913153da62c2ae2c27d11b1110dcef8980368dd84682ea2c1a308", "0xab6a8e4bbc78d4a7b291ad3e9a8fe2d65f640524ba3181123b09d2d18a9e300e2509ccf7000fe47e75b65f3e992a2e7e", "0xb7805ebe4f1a4df414003dc10bca805f2ab86ca75820012653e8f9b79c405196b0e2cab099f2ab953d67f0d60d31a0f9", "0xb12c582454148338ea605d22bd00a754109063e22617f1f8ac8ddf5502c22a181c50c216c3617b9852aa5f26af56b323", "0x86333ad9f898947e31ce747728dc8c887479e18d36ff3013f69ebef807d82c6981543b5c3788af93c4d912ba084d3cba", "0xb514efa310dc4ad1258add138891e540d8c87142a881b5f46563cc58ecd1488e6d3a2fca54c0b72a929f3364ca8c333e", "0xaa0a30f92843cf2f484066a783a1d75a7aa6f41f00b421d4baf20a6ac7886c468d0eea7ca8b17dd22f4f74631b62b640", "0xb3b7dc63baec9a752e8433c0cdee4d0f9bc41f66f2b8d132faf925eef9cf89aae756fc132c45910f057122462605dc10", "0xb9b8190dac5bfdeb59fd44f4da41a57e7f1e7d2c21faba9da91fa45cbeca06dcf299c9ae22f0c89ece11ac46352d619f", "0x89f8cf36501ad8bdfeab863752a9090e3bfda57cf8fdeca2944864dc05925f501e252c048221bcc57136ab09a64b64b2", "0xb0cbfaf317f05f97be47fc9d69eda2dd82500e00d42612f271a1fe24626408c28881f171e855bd5bd67409f9847502b4", "0xa7c21a8fcede581bfd9847b6835eda62ba250bea81f1bb17372c800a19c732abe03064e64a2f865d974fb636cab4b859", "0x95f9df524ba7a4667351696c4176b505d8ea3659f5ff2701173064acc624af69a0fad4970963736383b979830cb32260", "0x856a74fe8b37a2e3afeac858c8632200485d438422a16ae3b29f359e470e8244995c63ad79c7e007ed063f178d0306fd", "0xb37faa4d78fdc0bb9d403674dbea0176c2014a171c7be8527b54f7d1a32a76883d3422a3e7a5f5fcc5e9b31b57822eeb", "0x8d37234d8594ec3fe75670b5c9cc1ec3537564d4739b2682a75b18b08401869a4264c0f264354219d8d896cded715db4", "0xb5289ee5737f0e0bde485d32096d23387d68dab8f01f47821ab4f06cc79a967afe7355e72dc0c751d96b2747b26f6255", "0x9085e1fdf9f813e9c3b8232d3c8863cd84ab30d45e8e0d3d6a0abd9ebc6fd70cdf749ff4d04390000e14c7d8c6655fc7", "0x93a388c83630331eca4da37ea4a97b3b453238af474817cc0a0727fd3138dcb4a22de38c04783ec829c22cb459cb4e8e", "0xa5377116027c5d061dbe24c240b891c08cdd8cd3f0899e848d682c873aff5b8132c1e7cfe76d2e5ed97ee0eb1d42cb68", "0xa274c84b04338ed28d74683e2a7519c2591a3ce37c294d6f6e678f7d628be2db8eff253ede21823e2df7183e6552f622", "0x8bc201147a842453a50bec3ac97671397bc086d6dfc9377fa38c2124cdc286abda69b7324f47d64da094ae011d98d9d9", "0x9842d0c066c524592b76fbec5132bc628e5e1d21c424bec4555efca8619cc1fd8ea3161febcb8b9e8ab54702f4e815e2", "0xa19191b713a07efe85c266f839d14e25660ee74452e6c691cd9997d85ae4f732052d802d3deb018bdd847caa298a894b", "0xa24f71fc0db504da4e287dd118a4a74301cbcd16033937ba2abc8417956fcb4ae19b8e63b931795544a978137eff51cb", "0xa90eec4a6a3a4b8f9a5b93d978b5026fcf812fe65585b008d7e08c4aaf21195a1d0699f12fc16f79b6a18a369af45771", "0x8b551cf89737d7d06d9b3b9c4c1c73b41f2ea0af4540999c70b82dabff8580797cf0a3caf34c86c59a7069eb2e38f087", "0xb8d312e6c635e7a216a1cda075ae77ba3e1d2fd501dc31e83496e6e81ed5d9c7799f8e578869c2e0e256fb29f5de10a7", "0x8d144bdb8cae0b2cdb5b33d44bbc96984a5925202506a8cc65eb67ac904b466f5a7fe3e1cbf04aa785bbb7348c4bb73c", "0xa101b3d58b7a98659244b88de0b478b3fb87dc5fc6031f6e689b99edf498abd43e151fd32bd4bbd240e0b3e59c440359", "0x907453abca7d8e7151a05cc3d506c988007692fe7401395dc93177d0d07d114ab6cca0cc658eb94c0223fe8658295cad", "0x825329ffbe2147ddb68f63a0a67f32d7f309657b8e5d9ab5bb34b3730bfa2c77a23eaaadb05def7d9f94a9e08fdc1e96", "0x88ee923c95c1dac99ae7ed6067906d734d793c5dc5d26339c1bb3314abe201c5dccb33b9007351885eb2754e9a8ea06c", "0x98bc9798543f5f1adc9f2cfcfa72331989420e9c3f6598c45269f0dc9b7c8607bbeaf03faa0aea2ddde2b8f17fdceff5", "0x8ee87877702a79aef923ab970db6fa81561b3c07d5bf1a072af0a7bad765b4cbaec910afe1a91703feacc7822fa38a94", "0x8060b9584aa294fe8adc2b22f67e988bc6da768eae91e429dcc43ddc53cfcc5d6753fdc1b420b268c7eb2fb50736a970", "0xb344a5524d80a2f051870c7001f74fcf348a70fcf78dbd20c6ff9ca85d81567d2318c8b8089f2c4f195d6aec9fc15fa6", "0x8f5a5d893e1936ed062149d20eb73d98b62b7f50ab5d93a6429c03656b36688d1c80cb5010e4977491e51fa0d7dd35d5", "0x86fa32ebbf97328c5f5f15564e1238297e289ec3219b9a741724e9f3ae8d5c15277008f555863a478b247ba5dc601d44", "0x9557e55377e279f4b6b5e0ffe01eca037cc13aac242d67dfcd0374a1e775c5ed5cb30c25fe21143fee54e3302d34a3ea", "0x8cb6bcbc39372d23464a416ea7039f57ba8413cf3f00d9a7a5b356ab20dcb8ed11b3561f7bce372b8534d2870c7ee270", "0xb5d59075cb5abde5391f64b6c3b8b50adc6e1f654e2a580b6d6d6eff3f4fbdd8fffc92e06809c393f5c8eab37f774c4b", "0xafcfb6903ef13e493a1f7308675582f15af0403b6553e8c37afb8b2808ad21b88b347dc139464367dc260df075fea1ad", "0x810fbbe808375735dd22d5bc7fc3828dc49fdd22cc2d7661604e7ac9c4535c1df578780affb3b895a0831640a945bcad", "0x8056b0c678803b416f924e09a6299a33cf9ad7da6fe1ad7accefe95c179e0077da36815fde3716711c394e2c5ea7127f", "0x8b67403702d06979be19f1d6dc3ec73cc2e81254d6b7d0cc49cd4fdda8cd51ab0835c1d2d26fc0ecab5df90585c2f351", "0x87f97f9e6d4be07e8db250e5dd2bffdf1390665bc5709f2b631a6fa69a7fca958f19bd7cc617183da1f50ee63e9352b5", "0xae151310985940471e6803fcf37600d7fa98830613e381e00dab943aec32c14162d51c4598e8847148148000d6e5af5c", "0x81eb537b35b7602c45441cfc61b27fa9a30d3998fad35a064e05bc9479e9f10b62eba2b234b348219eea3cadcaac64bb", "0x8a441434934180ab6f5bc541f86ebd06eadbee01f438836d797e930fa803a51510e005c9248cecc231a775b74d12b5e9", "0x81f3c250a27ba14d8496a5092b145629eb2c2e6a5298438670375363f57e2798207832c8027c3e9238ad94ecdadfc4df", "0xa6217c311f2f3db02ceaa5b6096849fe92b6f4b6f1491535ef8525f6ccee6130bed2809e625073ecbaddd4a3eb3df186", "0x82d1c396f0388b942cf22b119d7ef1ad03d3dad49a74d9d01649ee284f377c8daddd095d596871669e16160299a210db", "0xa40ddf7043c5d72a7246bd727b07f7fff1549f0e443d611de6f9976c37448b21664c5089c57f20105102d935ab82f27b", "0xb6c03c1c97adf0c4bf4447ec71366c6c1bff401ba46236cd4a33d39291e7a1f0bb34bd078ba3a18d15c98993b153a279", "0x8a94f5f632068399c359c4b3a3653cb6df2b207379b3d0cdace51afdf70d6d5cce6b89a2b0fee66744eba86c98fb21c2", "0xb2f19e78ee85073f680c3bba1f07fd31b057c00b97040357d97855b54a0b5accb0d3b05b2a294568fcd6a4be6f266950", "0xa74632d13bbe2d64b51d7a9c3ae0a5a971c19f51cf7596a807cea053e6a0f3719700976d4e394b356c0329a2dced9aa2", "0xafef616d341a9bc94393b8dfba68ff0581436aa3a3adb7c26a1bbf2cf19fa877066191681f71f17f3cd6f9cf6bf70b5a", "0x8ce96d93ae217408acf7eb0f9cbb9563363e5c7002e19bbe1e80760bc9d449daee2118f3878b955163ed664516b97294", "0x8414f79b496176bc8b8e25f8e4cfee28f4f1c2ddab099d63d2aca1b6403d26a571152fc3edb97794767a7c4686ad557c", "0xb6c61d01fd8ce087ef9f079bf25bf10090db483dd4f88c4a786d31c1bdf52065651c1f5523f20c21e75cea17df69ab73", "0xa5790fd629be70545093631efadddc136661f63b65ec682609c38ef7d3d7fa4e56bdf94f06e263bc055b90cb1c6bcefe", "0xb515a767e95704fb7597bca9e46f1753abacdc0e56e867ee3c6f4cd382643c2a28e65312c05ad040eaa3a8cbe7217a65", "0x8135806a02ead6aa92e9adb6fefb91349837ab73105aaa7be488ef966aa8dfaafdfa64bbae30fcbfa55dd135a036a863", "0x8f22435702716d76b1369750694540742d909d5e72b54d0878245fab7c269953b1c6f2b29c66f08d5e0263ca3a731771", "0x8e0f8a8e8753e077dac95848212aeffd51c23d9b6d611df8b102f654089401954413ecbedc6367561ca599512ae5dda7", "0x815a9084e3e2345f24c5fa559deec21ee1352fb60f4025c0779be65057f2d528a3d91593bd30d3a185f5ec53a9950676", "0x967e6555ccba395b2cc1605f8484c5112c7b263f41ce8439a99fd1c71c5ed14ad02684d6f636364199ca48afbbde13be", "0x8cd0ccf17682950b34c796a41e2ea7dd5367aba5e80a907e01f4cdc611e4a411918215e5aebf4292f8b24765d73314a6", "0xa58bf1bbb377e4b3915df6f058a0f53b8fb8130fdec8c391f6bc82065694d0be59bb67ffb540e6c42cc8b380c6e36359", "0x92af3151d9e6bfb3383d85433e953c0160859f759b0988431ec5893542ba40288f65db43c78a904325ef8d324988f09d", "0x8011bbb05705167afb47d4425065630f54cb86cd462095e83b81dfebf348f846e4d8fbcf1c13208f5de1931f81da40b9", "0x81c743c104fc3cb047885c9fa0fb9705c3a83ee24f690f539f4985509c3dafd507af3f6a2128276f45d5939ef70c167f", "0xa2c9679b151c041aaf5efeac5a737a8f70d1631d931609fca16be1905682f35e291292874cb3b03f14994f98573c6f44", "0xa4949b86c4e5b1d5c82a337e5ce6b2718b1f7c215148c8bfb7e7c44ec86c5c9476048fc5c01f57cb0920876478c41ad6", "0x86c2495088bd1772152e527a1da0ef473f924ea9ab0e5b8077df859c28078f73c4e22e3a906b507fdf217c3c80808b5c", "0x892e0a910dcf162bcea379763c3e2349349e4cda9402949255ac4a78dd5a47e0bf42f5bd0913951576b1d206dc1e536a", "0xa7009b2c6b396138afe4754b7cc10dee557c51c7f1a357a11486b3253818531f781ea8107360c8d4c3b1cd96282353c0", "0x911763ef439c086065cc7b4e57484ed6d693ea44acee4b18c9fd998116da55fbe7dcb8d2a0f0f9b32132fca82d73dff6", "0xa722000b95a4a2d40bed81870793f15ba2af633f9892df507f2842e52452e02b5ea8dea6a043c2b2611d82376e33742a", "0x9387ac49477bd719c2f92240d0bdfcf9767aad247ca93dc51e56106463206bc343a8ec855eb803471629a66fffb565d6", "0x92819a1fa48ab4902939bb72a0a4e6143c058ea42b42f9bc6cea5df45f49724e2530daf3fc4f097cceefa2a8b9db0076", "0x98eac7b04537653bc0f4941aae732e4b1f84bd276c992c64a219b8715eb1fb829b5cbd997d57feb15c7694c468f95f70", "0xb275e7ba848ce21bf7996e12dbeb8dadb5d0e4f1cb5a0248a4f8f9c9fe6c74e3c93f4b61edbcb0a51af5a141e1c14bc7", "0x97243189285aba4d49c53770c242f2faf5fd3914451da4931472e3290164f7663c726cf86020f8f181e568c72fd172d1", "0x839b0b3c25dd412bee3dc24653b873cc65454f8f16186bb707bcd58259c0b6765fa4c195403209179192a4455c95f3b8", "0x8689d1a870514568a074a38232e2ceb4d7df30fabeb76cff0aed5b42bf7f02baea12c5fadf69f4713464dbd52aafa55f", "0x8958ae7b290f0b00d17c3e9fdb4dbf168432b457c7676829299dd428984aba892de1966fc106cfc58a772862ecce3976", "0xa422bc6bd68b8870cfa5bc4ce71781fd7f4368b564d7f1e0917f6013c8bbb5b240a257f89ecfdbecb40fe0f3aa31d310", "0xaa61f78130cebe09bc9a2c0a37f0dd57ed2d702962e37d38b1df7f17dc554b1d4b7a39a44182a452ce4c5eb31fa4cfcc", "0xb7918bd114f37869bf1a459023386825821bfadce545201929d13ac3256d92a431e34f690a55d944f77d0b652cefeffc", "0x819bba35fb6ace1510920d4dcff30aa682a3c9af9022e287751a6a6649b00c5402f14b6309f0aeef8fce312a0402915e", "0x8b7c9ad446c6f63c11e1c24e24014bd570862b65d53684e107ba9ad381e81a2eaa96731b4b33536efd55e0f055071274", "0x8fe79b53f06d33386c0ec7d6d521183c13199498594a46d44a8a716932c3ec480c60be398650bbfa044fa791c4e99b65", "0x9558e10fb81250b9844c99648cf38fa05ec1e65d0ccbb18aa17f2d1f503144baf59d802c25be8cc0879fff82ed5034ad", "0xb538a7b97fbd702ba84645ca0a63725be1e2891c784b1d599e54e3480e4670d0025526674ef5cf2f87dddf2290ba09f0", "0x92eafe2e869a3dd8519bbbceb630585c6eb21712b2f31e1b63067c0acb5f9bdbbcbdb612db4ea7f9cc4e7be83d31973f", "0xb40d21390bb813ab7b70a010dff64c57178418c62685761784e37d327ba3cb9ef62df87ecb84277c325a637fe3709732", "0xb349e6fbf778c4af35fbed33130bd8a7216ed3ba0a79163ebb556e8eb8e1a7dad3456ddd700dad9d08d202491c51b939", "0xa8fdaedecb251f892b66c669e34137f2650509ade5d38fbe8a05d9b9184bb3b2d416186a3640429bd1f3e4b903c159dd", "0xac6167ebfee1dbab338eff7642f5e785fc21ef0b4ddd6660333fe398068cbd6c42585f62e81e4edbb72161ce852a1a4f", "0x874b1fbf2ebe140c683bd7e4e0ab017afa5d4ad38055aaa83ee6bbef77dbc88a6ce8eb0dcc48f0155244af6f86f34c2d", "0x903c58e57ddd9c446afab8256a6bb6c911121e6ccfb4f9b4ed3e2ed922a0e500a5cb7fa379d5285bc16e11dac90d1fda", "0x8dae7a0cffa2fd166859cd1bf10ff82dd1932e488af377366b7efc0d5dec85f85fe5e8150ff86a79a39cefc29631733a", "0xaa047857a47cc4dfc08585f28640420fcf105b881fd59a6cf7890a36516af0644d143b73f3515ab48faaa621168f8c31", "0x864508f7077c266cc0cb3f7f001cb6e27125ebfe79ab57a123a8195f2e27d3799ff98413e8483c533b46a816a3557f1f", "0x8bcd45ab1f9cbab36937a27e724af819838f66dfeb15923f8113654ff877bd8667c54f6307aaf0c35027ca11b6229bfd", "0xb21aa34da9ab0a48fcfdd291df224697ce0c1ebc0e9b022fdee8750a1a4b5ba421c419541ed5c98b461eecf363047471", "0xa9a18a2ab2fae14542dc336269fe612e9c1af6cf0c9ac933679a2f2cb77d3c304114f4d219ca66fe288adde30716775b", "0xb5205989b92c58bdda71817f9a897e84100b5c4e708de1fced5c286f7a6f01ae96b1c8d845f3a320d77c8e2703c0e8b1", "0xa364059412bbcc17b8907d43ac8e5df90bc87fd1724b5f99832d0d24559fae6fa76a74cff1d1eac8cbac6ec80b44af20", "0xae709f2c339886b31450834cf29a38b26eb3b0779bd77c9ac269a8a925d1d78ea3837876c654b61a8fe834b3b6940808", "0x8802581bba66e1952ac4dab36af371f66778958f4612901d95e5cac17f59165e6064371d02de8fb6fccf89c6dc8bd118", "0xa313252df653e29c672cbcfd2d4f775089cb77be1077381cf4dc9533790e88af6cedc8a119158e7da5bf6806ad9b91a1", "0x992a065b4152c7ef11515cd54ba9d191fda44032a01aed954acff3443377ee16680c7248d530b746b8c6dee2d634e68c", "0xb627b683ee2b32c1ab4ccd27b9f6cce2fe097d96386fa0e5c182ad997c4c422ab8dfc03870cd830b8c774feb66537282", "0xb823cf8a9aee03dadd013eb9efe40a201b4b57ef67efaae9f99683005f5d1bf55e950bf4af0774f50859d743642d3fea", "0xb8a7449ffac0a3f206677097baf7ce00ca07a4d2bd9b5356fbcb83f3649b0fda07cfebad220c1066afba89e5a52abf4b", "0xb2dd1a2f986395bb4e3e960fbbe823dbb154f823284ebc9068502c19a7609790ec0073d08bfa63f71e30c7161b6ef966", "0x98e5236de4281245234f5d40a25b503505af140b503a035fc25a26159a9074ec81512b28f324c56ea2c9a5aa7ce90805", "0x89070847dc8bbf5bc4ed073aa2e2a1f699cf0c2ca226f185a0671cecc54e7d3e14cd475c7752314a7a8e7476829da4bc", "0xa9402dc9117fdb39c4734c0688254f23aed3dce94f5f53f5b7ef2b4bf1b71a67f85ab1a38ec224a59691f3bee050aeb3", "0x957288f9866a4bf56a4204218ccc583f717d7ce45c01ea27142a7e245ad04a07f289cc044f8cf1f21d35e67e39299e9c", "0xb2fb31ccb4e69113763d7247d0fc8edaae69b550c5c56aecacfd780c7217dc672f9fb7496edf4aba65dacf3361268e5b", "0xb44a4526b2f1d6eb2aa8dba23bfa385ff7634572ab2afddd0546c3beb630fbfe85a32f42dd287a7fec069041411537f7", "0x8db5a6660c3ac7fd7a093573940f068ee79a82bc17312af900b51c8c439336bc86ca646c6b7ab13aaaa008a24ca508ab", "0x8f9899a6d7e8eb4367beb5c060a1f8e94d8a21099033ae582118477265155ba9e72176a67f7f25d7bad75a152b56e21a", "0xa67de0e91ade8d69a0e00c9ff33ee2909b8a609357095fa12319e6158570c232e5b6f4647522efb7345ce0052aa9d489", "0x82eb2414898e9c3023d57907a2b17de8e7eea5269029d05a94bfd7bf5685ac4a799110fbb375eb5e0e2bd16acf6458ae", "0x94451fc7fea3c5a89ba701004a9693bab555cb622caf0896b678faba040409fdfd14a978979038b2a81e8f0abc4994d2", "0xac879a5bb433998e289809a4a966bd02b4bf6a9c1cc276454e39c886efcf4fc68baebed575826bde577ab5aa71d735a9", "0x880c0f8f49c875dfd62b4ddedde0f5c8b19f5687e693717f7e5c031bc580e58e13ab497d48b4874130a18743c59fdce3", "0xb582af8d8ff0bf76f0a3934775e0b54c0e8fed893245d7d89cae65b03c8125b7237edc29dc45b4fe1a3fe6db45d280ee", "0x89f337882ed3ae060aaee98efa20d79b6822bde9708c1c5fcee365d0ec9297f694cae37d38fd8e3d49717c1e86f078e7", "0x826d2c1faea54061848b484e288a5f4de0d221258178cf87f72e14baaa4acc21322f8c9eab5dde612ef497f2d2e1d60b", "0xa5333d4f227543e9cd741ccf3b81db79f2f03ca9e649e40d6a6e8ff9073e06da83683566d3b3c8d7b258c62970fb24d1", "0xa28f08c473db06aaf4c043a2fae82b3c8cfaa160bce793a4c208e4e168fb1c65115ff8139dea06453c5963d95e922b94", "0x8162546135cc5e124e9683bdfaa45833c18553ff06a0861c887dc84a5b12ae8cd4697f6794c7ef6230492c32faba7014", "0xb23f0d05b74c08d6a7df1760792be83a761b36e3f8ae360f3c363fb196e2a9dd2de2e492e49d36561366e14daa77155c", "0xb6f70d6c546722d3907c708d630dbe289771d2c8bf059c2e32b77f224696d750b4dda9b3a014debda38e7d02c9a77585", "0x83bf4c4a9f3ca022c631017e7a30ea205ba97f7f5927cba8fc8489a4646eac6712cb821c5668c9ffe94d69d524374a27", "0xb0371475425a8076d0dd5f733f55aabbe42d20a7c8ea7da352e736d4d35a327b2beb370dfcb05284e22cfd69c5f6c4cc", "0xa0031ba7522c79211416c2cca3aa5450f96f8fee711552a30889910970ba13608646538781a2c08b834b140aadd7166f", "0x99d273c80c7f2dc6045d4ed355d9fc6f74e93549d961f4a3b73cd38683f905934d359058cd1fc4da8083c7d75070487f", "0xb0e4b0efa3237793e9dcce86d75aafe9879c5fa23f0d628649aef2130454dcf72578f9bf227b9d2b9e05617468e82588", "0xa5ab076fa2e1c5c51f3ae101afdd596ad9d106bba7882b359c43d8548b64f528af19afa76cd6f40da1e6c5fca4def3fa", "0x8ce2299e570331d60f6a6eff1b271097cd5f1c0e1113fc69b89c6a0f685dabea3e5bc2ac6bd789aa492ab189f89be494", "0x91b829068874d911a310a5f9dee001021f97471307b5a3de9ec336870ec597413e1d92010ce320b619f38bed7c4f7910", "0xb14fe91f4b07bf33b046e9285b66cb07927f3a8da0af548ac2569b4c4fb1309d3ced76d733051a20814e90dd5b75ffd1", "0xabaab92ea6152d40f82940277c725aa768a631ee0b37f5961667f82fb990fc11e6d3a6a2752b0c6f94563ed9bb28265c", "0xb7fe28543eca2a716859a76ab9092f135337e28109544f6bd2727728d0a7650428af5713171ea60bfc273d1c821d992c", "0x8a4917b2ab749fc7343fc64bdf51b6c0698ff15d740cc7baf248c030475c097097d5a473bcc00d8c25817563fe0447b4", "0xaa96156d1379553256350a0a3250166add75948fb9cde62aa555a0a9dc0a9cb7f2f7b8428aff66097bf6bfedaf14bbe2", "0xae4ffeb9bdc76830d3eca2b705f30c1bdede6412fa064260a21562c8850c7fb611ec62bc68479fe48f692833e6f66d8d", "0xb96543caaba9d051600a14997765d49e4ab10b07c7a92cccf0c90b309e6da334fdd6d18c96806cbb67a7801024fbd3c7", "0x97b2b9ad76f19f500fcc94ca8e434176249f542ac66e5881a3dccd07354bdab6a2157018b19f8459437a68d8b86ba8e0", "0xa8d206f6c5a14c80005849474fde44b1e7bcf0b2d52068f5f97504c3c035b09e65e56d1cf4b5322791ae2c2fdbd61859", "0x936bad397ad577a70cf99bf9056584a61bd7f02d2d5a6cf219c05d770ae30a5cd902ba38366ce636067fc1dd10108d31", "0xa77e30195ee402b84f3882e2286bf5380c0ed374a112dbd11e16cef6b6b61ab209d4635e6f35cdaaa72c1a1981d5dabe", "0xa46ba4d3947188590a43c180757886a453a0503f79cc435322d92490446f37419c7b999fdf868a023601078070e03346", "0x80d8d4c5542f223d48240b445d4d8cf6a75d120b060bc08c45e99a13028b809d910b534d2ac47fb7068930c54efd8da9", "0x803be9c68c91b42b68e1f55e58917a477a9a6265e679ca44ee30d3eb92453f8c89c64eafc04c970d6831edd33d066902", "0xb14b2b3d0dfe2bb57cee4cd72765b60ac33c1056580950be005790176543826c1d4fbd737f6cfeada6c735543244ab57", "0xa9e480188bba1b8fb7105ff12215706665fd35bf1117bacfb6ab6985f4dbc181229873b82e5e18323c2b8f5de03258e0", "0xa66a0f0779436a9a3999996d1e6d3000f22c2cac8e0b29cddef9636393c7f1457fb188a293b6c875b05d68d138a7cc4a", "0x848397366300ab40c52d0dbbdafbafef6cd3dadf1503bb14b430f52bb9724188928ac26f6292a2412bc7d7aa620763c8", "0x95466cc1a78c9f33a9aaa3829a4c8a690af074916b56f43ae46a67a12bb537a5ac6dbe61590344a25b44e8512355a4a7", "0x8b5f7a959f818e3baf0887f140f4575cac093d0aece27e23b823cf421f34d6e4ff4bb8384426e33e8ec7b5eed51f6b5c", "0x8d5e1368ec7e3c65640d216bcc5d076f3d9845924c734a34f3558ac0f16e40597c1a775a25bf38b187213fbdba17c93b", "0xb4647c1b823516880f60d20c5cc38c7f80b363c19d191e8992226799718ee26b522a12ecb66556ed3d483aa4824f3326", "0xac3abaea9cd283eb347efda4ed9086ea3acf495043e08d0d19945876329e8675224b685612a6badf8fd72fb6274902b1", "0x8eae1ce292d317aaa71bcf6e77e654914edd5090e2e1ebab78b18bb41b9b1bc2e697439f54a44c0c8aa0d436ebe6e1a9", "0x94dc7d1aec2c28eb43d93b111fa59aaa0d77d5a09501220bd411768c3e52208806abf973c6a452fd8292ff6490e0c9e2", "0x8fd8967f8e506fef27d17b435d6b86b232ec71c1036351f12e6fb8a2e12daf01d0ee04451fb944d0f1bf7fd20e714d02", "0x824e6865be55d43032f0fec65b3480ea89b0a2bf860872237a19a54bc186a85d2f8f9989cc837fbb325b7c72d9babe2c", "0x8bd361f5adb27fd6f4e3f5de866e2befda6a8454efeb704aacc606f528c03f0faae888f60310e49440496abd84083ce2", "0xb098a3c49f2aaa28b6b3e85bc40ce6a9cdd02134ee522ae73771e667ad7629c8d82c393fba9f27f5416986af4c261438", "0xb385f5ca285ff2cfe64dcaa32dcde869c28996ed091542600a0b46f65f3f5a38428cca46029ede72b6cf43e12279e3d3", "0x8196b03d011e5be5288196ef7d47137d6f9237a635ab913acdf9c595fa521d9e2df722090ec7eb0203544ee88178fc5f", "0x8ed1270211ef928db18e502271b7edf24d0bbd11d97f2786aee772d70c2029e28095cf8f650b0328cc8a4c38d045316d", "0xa52ab60e28d69b333d597a445884d44fd2a7e1923dd60f763951e1e45f83e27a4dac745f3b9eff75977b3280e132c15d", "0x91e9fe78cdac578f4a4687f71b800b35da54b824b1886dafec073a3c977ce7a25038a2f3a5b1e35c2c8c9d1a7312417c", "0xa42832173f9d9491c7bd93b21497fbfa4121687cd4d2ab572e80753d7edcbb42cfa49f460026fbde52f420786751a138", "0x97b947126d84dcc70c97be3c04b3de3f239b1c4914342fa643b1a4bb8c4fe45c0fcb585700d13a7ed50784790c54bef9", "0x860e407d353eac070e2418ef6cb80b96fc5f6661d6333e634f6f306779651588037be4c2419562c89c61f9aa2c4947f5", "0xb2c9d93c3ba4e511b0560b55d3501bf28a510745fd666b3cb532db051e6a8617841ea2f071dda6c9f15619c7bfd2737f", "0x8596f4d239aeeac78311207904d1bd863ef68e769629cc379db60e019aaf05a9d5cd31dc8e630b31e106a3a93e47cbc5", "0x8b26e14e2e136b65c5e9e5c2022cee8c255834ea427552f780a6ca130a6446102f2a6f334c3f9a0308c53df09e3dba7e", "0xb54724354eb515a3c8bed0d0677ff1db94ac0a07043459b4358cb90e3e1aa38ac23f2caa3072cf9647275d7cd61d0e80", "0xb7ce9fe0e515e7a6b2d7ddcb92bc0196416ff04199326aea57996eef8c5b1548bd8569012210da317f7c0074691d01b7", "0xa1a13549c82c877253ddefa36a29ea6a23695ee401fdd48e65f6f61e5ebd956d5e0edeff99484e9075cb35071fec41e2", "0x838ba0c1e5bd1a6da05611ff1822b8622457ebd019cb065ece36a2d176bd2d889511328120b8a357e44569e7f640c1e6", "0xb916eccff2a95519400bbf76b5f576cbe53cf200410370a19d77734dc04c05b585cfe382e8864e67142d548cd3c4c2f4", "0xa610447cb7ca6eea53a6ff1f5fe562377dcb7f4aaa7300f755a4f5e8eba61e863c51dc2aa9a29b35525b550fbc32a0fe", "0x9620e8f0f0ee9a4719aa9685eeb1049c5c77659ba6149ec4c158f999cfd09514794b23388879931fe26fea03fa471fd3", "0xa9dcf8b679e276583cf5b9360702a185470d09aea463dc474ee9c8aee91ef089dacb073e334e47fbc78ec5417c90465c", "0x8c9adee8410bdd99e5b285744cee61e2593b6300ff31a8a83b0ec28da59475a5c6fb9346fe43aadea2e6c3dad2a8e30a", "0x97d5afe9b3897d7b8bb628b7220cf02d8ee4e9d0b78f5000d500aaf4c1df9251aaaabfd1601626519f9d66f00a821d4e", "0x8a382418157b601ce4c3501d3b8409ca98136a4ef6abcbf62885e16e215b76b035c94d149cc41ff92e42ccd7c43b9b3d", "0xb64b8d11fb3b01abb2646ac99fdb9c02b804ce15d98f9fe0fbf1c9df8440c71417487feb6cdf51e3e81d37104b19e012", "0x849d7d044f9d8f0aab346a9374f0b3a5d14a9d1faa83dbacccbdc629ad1ef903a990940255564770537f8567521d17f0", "0x829dbb0c76b996c2a91b4cbbe93ba455ca0d5729755e5f0c92aaee37dff7f36fcdc06f33aca41f1b609c784127b67d88", "0x85a7c0069047b978422d264d831ab816435f63938015d2e977222b6b5746066c0071b7f89267027f8a975206ed25c1b0", "0x84b9fbc1cfb302df1acdcf3dc5d66fd1edfe7839f7a3b2fb3a0d5548656249dd556104d7c32b73967bccf0f5bdcf9e3b", "0x972220ac5b807f53eac37dccfc2ad355d8b21ea6a9c9b011c09fe440ddcdf7513e0b43d7692c09ded80d7040e26aa28f", "0x855885ed0b21350baeca890811f344c553cf9c21024649c722453138ba29193c6b02c4b4994cd414035486f923472e28", "0x841874783ae6d9d0e59daea03e96a01cbbe4ecaced91ae4f2c8386e0d87b3128e6d893c98d17c59e4de1098e1ad519dd", "0x827e50fc9ce56f97a4c3f2f4cbaf0b22f1c3ce6f844ff0ef93a9c57a09b8bf91ebfbd2ba9c7f83c442920bffdaf288cc", "0xa441f9136c7aa4c08d5b3534921b730e41ee91ab506313e1ba5f7c6f19fd2d2e1594e88c219834e92e6fb95356385aa7", "0x97d75b144471bf580099dd6842b823ec0e6c1fb86dd0da0db195e65524129ea8b6fd4a7a9bbf37146269e938a6956596", "0xa4b6fa87f09d5a29252efb2b3aaab6b3b6ea9fab343132a651630206254a25378e3e9d6c96c3d14c150d01817d375a8e", "0xa31a671876d5d1e95fe2b8858dc69967231190880529d57d3cab7f9f4a2b9b458ac9ee5bdaa3289158141bf18f559efb", "0x90bee6fff4338ba825974021b3b2a84e36d617e53857321f13d2b3d4a28954e6de3b3c0e629d61823d18a9763313b3bf", "0x96b622a63153f393bb419bfcf88272ea8b3560dbd46b0aa07ada3a6223990d0abdd6c2adb356ef4be5641688c8d83941", "0x84c202adeaff9293698022bc0381adba2cd959f9a35a4e8472288fd68f96f6de8be9da314c526d88e291c96b1f3d6db9", "0x8ca01a143b8d13809e5a8024d03e6bc9492e22226073ef6e327edf1328ef4aff82d0bcccee92cb8e212831fa35fe1204", "0xb2f970dbad15bfbefb38903c9bcc043d1367055c55dc1100a850f5eb816a4252c8c194b3132c929105511e14ea10a67d", "0xa5e36556472a95ad57eb90c3b6623671b03eafd842238f01a081997ffc6e2401f76e781d049bb4aa94d899313577a9cf", "0x8d1057071051772f7c8bedce53a862af6fd530dd56ae6321eaf2b9fc6a68beff5ed745e1c429ad09d5a118650bfd420a", "0x8aadc4f70ace4fcb8d93a78610779748dcffc36182d45b932c226dc90e48238ea5daa91f137c65ed532352c4c4d57416", "0xa2ea05ae37e673b4343232ae685ee14e6b88b867aef6dfac35db3589cbcd76f99540fed5c2641d5bb5a4a9f808e9bf0d", "0x947f1abad982d65648ae4978e094332b4ecb90f482c9be5741d5d1cf5a28acf4680f1977bf6e49dd2174c37f11e01296", "0xa27b144f1565e4047ba0e3f4840ef19b5095d1e281eaa463c5358f932114cbd018aa6dcf97546465cf2946d014d8e6d6", "0x8574e1fc3acade47cd4539df578ce9205e745e161b91e59e4d088711a7ab5aa3b410d517d7304b92109924d9e2af8895", "0xa48ee6b86b88015d6f0d282c1ae01d2a5b9e8c7aa3d0c18b35943dceb1af580d08a65f54dc6903cde82fd0d73ce94722", "0x8875650cec543a7bf02ea4f2848a61d167a66c91ffaefe31a9e38dc8511c6a25bde431007eefe27a62af3655aca208dc", "0x999b0a6e040372e61937bf0d68374e230346b654b5a0f591a59d33a4f95bdb2f3581db7c7ccb420cd7699ed709c50713", "0x878c9e56c7100c5e47bbe77dc8da5c5fe706cec94d37fa729633bca63cace7c40102eee780fcdabb655f5fa47a99600e", "0x865006fb5b475ada5e935f27b96f9425fc2d5449a3c106aa366e55ebed3b4ee42adc3c3f0ac19fd129b40bc7d6bc4f63", "0xb7a7da847f1202e7bc1672553e68904715e84fd897d529243e3ecda59faa4e17ba99c649a802d53f6b8dfdd51f01fb74", "0x8b2fb4432c05653303d8c8436473682933a5cb604da10c118ecfcd2c8a0e3132e125afef562bdbcc3df936164e5ce4f2", "0x808d95762d33ddfa5d0ee3d7d9f327de21a994d681a5f372e2e3632963ea974da7f1f9e5bac8ccce24293509d1f54d27", "0x932946532e3c397990a1df0e94c90e1e45133e347a39b6714c695be21aeb2d309504cb6b1dde7228ff6f6353f73e1ca2", "0x9705e7c93f0cdfaa3fa96821f830fe53402ad0806036cd1b48adc2f022d8e781c1fbdab60215ce85c653203d98426da3", "0xaa180819531c3ec1feb829d789cb2092964c069974ae4faad60e04a6afcce5c3a59aec9f11291e6d110a788d22532bc6", "0x88f755097f7e25cb7dd3c449520c89b83ae9e119778efabb54fbd5c5714b6f37c5f9e0346c58c6ab09c1aef2483f895d", "0x99fc03ab7810e94104c494f7e40b900f475fde65bdec853e60807ffd3f531d74de43335c3b2646b5b8c26804a7448898", "0xaf2dea9683086bed1a179110efb227c9c00e76cd00a2015b089ccbcee46d1134aa18bda5d6cab6f82ae4c5cd2461ac21", "0xa500f87ba9744787fdbb8e750702a3fd229de6b8817594348dec9a723b3c4240ddfa066262d002844b9e38240ce55658", "0x924d0e45c780f5bc1c1f35d15dfc3da28036bdb59e4c5440606750ecc991b85be18bc9a240b6c983bc5430baa4c68287", "0x865b11e0157b8bf4c5f336024b016a0162fc093069d44ac494723f56648bc4ded13dfb3896e924959ea11c96321afefc", "0x93672d8607d4143a8f7894f1dcca83fb84906dc8d6dd7dd063bb0049cfc20c1efd933e06ca7bd03ea4cb5a5037990bfe", "0x826891efbdff0360446825a61cd1fa04326dd90dae8c33dfb1ed97b045e165766dd070bd7105560994d0b2044bdea418", "0x93c4a4a8bcbc8b190485cc3bc04175b7c0ed002c28c98a540919effd6ed908e540e6594f6db95cd65823017258fb3b1c", "0xaeb2a0af2d2239fda9aa6b8234b019708e8f792834ff0dd9c487fa09d29800ddceddd6d7929faa9a3edcb9e1b3aa0d6b", "0x87f11de7236d387863ec660d2b04db9ac08143a9a2c4dfff87727c95b4b1477e3bc473a91e5797313c58754905079643", "0x80dc1db20067a844fe8baceca77f80db171a5ca967acb24e2d480eae9ceb91a3343c31ad1c95b721f390829084f0eae6", "0x9825c31f1c18da0de3fa84399c8b40f8002c3cae211fb6a0623c76b097b4d39f5c50058f57a16362f7a575909d0a44a2", "0xa99fc8de0c38dbf7b9e946de83943a6b46a762167bafe2a603fb9b86f094da30d6de7ed55d639aafc91936923ee414b3", "0xad594678b407db5d6ea2e90528121f84f2b96a4113a252a30d359a721429857c204c1c1c4ff71d8bb5768c833f82e80e", "0xb33d985e847b54510b9b007e31053732c8a495e43be158bd2ffcea25c6765bcbc7ca815f7c60b36ad088b955dd6e9350", "0x815f8dfc6f90b3342ca3fbd968c67f324dae8f74245cbf8bc3bef10e9440c65d3a2151f951e8d18959ba01c1b50b0ec1", "0x94c608a362dd732a1abc56e338637c900d59013db8668e49398b3c7a0cae3f7e2f1d1bf94c0299eeafe6af7f76c88618", "0x8ebd8446b23e5adfcc393adc5c52fe172f030a73e63cd2d515245ca0dd02782ceed5bcdd9ccd9c1b4c5953dfac9c340c", "0x820437f3f6f9ad0f5d7502815b221b83755eb8dc56cd92c29e9535eb0b48fb8d08c9e4fcc26945f9c8cca60d89c44710", "0x8910e4e8a56bf4be9cc3bbf0bf6b1182a2f48837a2ed3c2aaec7099bfd7f0c83e14e608876b17893a98021ff4ab2f20d", "0x9633918fde348573eec15ce0ad53ac7e1823aac86429710a376ad661002ae6d049ded879383faaa139435122f64047c6", "0xa1f5e3fa558a9e89318ca87978492f0fb4f6e54a9735c1b8d2ecfb1d1c57194ded6e0dd82d077b2d54251f3bee1279e1", "0xb208e22d04896abfd515a95c429ff318e87ff81a5d534c8ac2c33c052d6ffb73ef1dccd39c0bbe0734b596c384014766", "0x986d5d7d2b5bde6d16336f378bd13d0e671ad23a8ec8a10b3fc09036faeeb069f60662138d7a6df3dfb8e0d36180f770", "0xa2d4e6c5f5569e9cef1cddb569515d4b6ace38c8aed594f06da7434ba6b24477392cc67ba867c2b079545ca0c625c457", "0xb5ac32b1d231957d91c8b7fc43115ce3c5c0d8c13ca633374402fa8000b6d9fb19499f9181844f0c10b47357f3f757ce", "0x96b8bf2504b4d28fa34a4ec378e0e0b684890c5f44b7a6bb6e19d7b3db2ab27b1e2686389d1de9fbd981962833a313ea", "0x953bfd7f6c3a0469ad432072b9679a25486f5f4828092401eff494cfb46656c958641a4e6d0d97d400bc59d92dba0030", "0x876ab3cea7484bbfd0db621ec085b9ac885d94ab55c4bb671168d82b92e609754b86aaf472c55df3d81421d768fd108a", "0x885ff4e67d9ece646d02dd425aa5a087e485c3f280c3471b77532b0db6145b69b0fbefb18aa2e3fa5b64928b43a94e57", "0xb91931d93f806d0b0e6cc62a53c718c099526140f50f45d94b8bbb57d71e78647e06ee7b42aa5714aed9a5c05ac8533f", "0xa0313eeadd39c720c9c27b3d671215331ab8d0a794e71e7e690f06bcd87722b531d6525060c358f35f5705dbb7109ccb", "0x874c0944b7fedc6701e53344100612ddcb495351e29305c00ec40a7276ea5455465ffb7bded898886c1853139dfb1fc7", "0x8dc31701a01ee8137059ca1874a015130d3024823c0576aa9243e6942ec99d377e7715ed1444cd9b750a64b85dcaa3e5", "0x836d2a757405e922ec9a2dfdcf489a58bd48b5f9683dd46bf6047688f778c8dee9bc456de806f70464df0b25f3f3d238", "0xb30b0a1e454a503ea3e2efdec7483eaf20b0a5c3cefc42069e891952b35d4b2c955cf615f3066285ed8fafd9fcfbb8f6", "0x8e6d4044b55ab747e83ec8762ea86845f1785cc7be0279c075dadf08aca3ccc5a096c015bb3c3f738f647a4eadea3ba5", "0xad7735d16ab03cbe09c029610aa625133a6daecfc990b297205b6da98eda8c136a7c50db90f426d35069708510d5ae9c", "0x8d62d858bbb59ec3c8cc9acda002e08addab4d3ad143b3812098f3d9087a1b4a1bb255dcb1635da2402487d8d0249161", "0x805beec33238b832e8530645a3254aeef957e8f7ea24bcfc1054f8b9c69421145ebb8f9d893237e8a001c857fedfc77e", "0xb1005644be4b085e3f5775aa9bd3e09a283e87ddada3082c04e7a62d303dcef3b8cf8f92944c200c7ae6bb6bdf63f832", "0xb4ba0e0790dc29063e577474ffe3b61f5ea2508169f5adc1e394934ebb473e356239413a17962bc3e5d3762d72cce8c2", "0xa157ba9169c9e3e6748d9f1dd67fbe08b9114ade4c5d8fc475f87a764fb7e6f1d21f66d7905cd730f28a1c2d8378682a", "0x913e52b5c93989b5d15e0d91aa0f19f78d592bc28bcfdfddc885a9980c732b1f4debb8166a7c4083c42aeda93a702898", "0x90fbfc1567e7cd4e096a38433704d3f96a2de2f6ed3371515ccc30bc4dd0721a704487d25a97f3c3d7e4344472702d8d", "0x89646043028ffee4b69d346907586fd12c2c0730f024acb1481abea478e61031966e72072ff1d5e65cb8c64a69ad4eb1", "0xb125a45e86117ee11d2fb42f680ab4a7894edd67ff927ae2c808920c66c3e55f6a9d4588eee906f33a05d592e5ec3c04", "0xaad47f5b41eae9be55fb4f67674ff1e4ae2482897676f964a4d2dcb6982252ee4ff56aac49578b23f72d1fced707525e", "0xb9ddff8986145e33851b4de54d3e81faa3352e8385895f357734085a1616ef61c692d925fe62a5ed3be8ca49f5d66306", "0xb3cb0963387ed28c0c0adf7fe645f02606e6e1780a24d6cecef5b7c642499109974c81a7c2a198b19862eedcea2c2d8c", "0xac9c53c885457aaf5cb36c717a6f4077af701e0098eebd7aa600f5e4b14e6c1067255b3a0bc40e4a552025231be7de60", "0x8e1a8d823c4603f6648ec21d064101094f2a762a4ed37dd2f0a2d9aa97b2d850ce1e76f4a4b8cae58819b058180f7031", "0xb268b73bf7a179b6d22bd37e5e8cb514e9f5f8968c78e14e4f6d5700ca0d0ca5081d0344bb73b028970eebde3cb4124e", "0xa7f57d71940f0edbd29ed8473d0149cae71d921dd15d1ff589774003e816b54b24de2620871108cec1ab9fa956ad6ce6", "0x8053e6416c8b120e2b999cc2fc420a6a55094c61ac7f2a6c6f0a2c108a320890e389af96cbe378936132363c0d551277", "0xb3823f4511125e5aa0f4269e991b435a0d6ceb523ebd91c04d7add5534e3df5fc951c504b4fd412a309fd3726b7f940b", "0xae6eb04674d04e982ca9a6add30370ab90e303c71486f43ed3efbe431af1b0e43e9d06c11c3412651f304c473e7dbf39", "0x96ab55e641ed2e677591f7379a3cd126449614181fce403e93e89b1645d82c4af524381ff986cae7f9cebe676878646d", "0xb52423b4a8c37d3c3e2eca8f0ddbf7abe0938855f33a0af50f117fab26415fb0a3da5405908ec5fdc22a2c1f2ca64892", "0x82a69ce1ee92a09cc709d0e3cd22116c9f69d28ea507fe5901f5676000b5179b9abe4c1875d052b0dd42d39925e186bb", "0xa84c8cb84b9d5cfb69a5414f0a5283a5f2e90739e9362a1e8c784b96381b59ac6c18723a4aa45988ee8ef5c1f45cc97d", "0xafd7efce6b36813082eb98257aae22a4c1ae97d51cac7ea9c852d4a66d05ef2732116137d8432e3f117119725a817d24", "0xa0f5fe25af3ce021b706fcff05f3d825384a272284d04735574ce5fb256bf27100fad0b1f1ba0e54ae9dcbb9570ecad3", "0x8751786cb80e2e1ff819fc7fa31c2833d25086534eb12b373d31f826382430acfd87023d2a688c65b5e983927e146336", "0x8cf5c4b17fa4f3d35c78ce41e1dc86988fd1135cd5e6b2bb0c108ee13538d0d09ae7102609c6070f39f937b439b31e33", "0xa9108967a2fedd7c322711eca8159c533dd561bedcb181b646de98bf5c3079449478eab579731bee8d215ae8852c7e21", "0xb54c5171704f42a6f0f4e70767cdb3d96ffc4888c842eece343a01557da405961d53ffdc34d2f902ea25d3e1ed867cad", "0xae8d4b764a7a25330ba205bf77e9f46182cd60f94a336bbd96773cf8064e3d39caf04c310680943dc89ed1fbad2c6e0d", "0xaa5150e911a8e1346868e1b71c5a01e2a4bb8632c195861fb6c3038a0e9b85f0e09b3822e9283654a4d7bb17db2fc5f4", "0x9685d3756ce9069bf8bb716cf7d5063ebfafe37e15b137fc8c3159633c4e006ff4887ddd0ae90360767a25c3f90cba7f", "0x82155fd70f107ab3c8e414eadf226c797e07b65911508c76c554445422325e71af8c9a8e77fd52d94412a6fc29417cd3", "0xabfae52f53a4b6e00760468d973a267f29321997c3dbb5aee36dc1f20619551229c0c45b9d9749f410e7f531b73378e8", "0x81a76d921f8ef88e774fd985e786a4a330d779b93fad7def718c014685ca0247379e2e2a007ad63ee7f729cd9ed6ce1b", "0x81947c84bc5e28e26e2e533af5ae8fe10407a7b77436dbf8f1d5b0bbe86fc659eae10f974659dc7c826c6dabd03e3a4b", "0x92b8c07050d635b8dd4fd09df9054efe4edae6b86a63c292e73cc819a12a21dd7d104ce51fa56af6539dedf6dbe6f7b6", "0xb44c579e3881f32b32d20c82c207307eca08e44995dd2aac3b2692d2c8eb2a325626c80ac81c26eeb38c4137ff95add5", "0x97efab8941c90c30860926dea69a841f2dcd02980bf5413b9fd78d85904588bf0c1021798dbc16c8bbb32cce66c82621", "0x913363012528b50698e904de0588bf55c8ec5cf6f0367cfd42095c4468fcc64954fbf784508073e542fee242d0743867", "0x8ed203cf215148296454012bd10fddaf119203db1919a7b3d2cdc9f80e66729464fdfae42f1f2fc5af1ed53a42b40024", "0xab84312db7b87d711e9a60824f4fe50e7a6190bf92e1628688dfcb38930fe87b2d53f9e14dd4de509b2216856d8d9188", "0x880726def069c160278b12d2258eac8fa63f729cd351a710d28b7e601c6712903c3ac1e7bbd0d21e4a15f13ca49db5aa", "0x980699cd51bac6283959765f5174e543ed1e5f5584b5127980cbc2ef18d984ecabba45042c6773b447b8e694db066028", "0xaeb019cb80dc4cb4207430d0f2cd24c9888998b6f21d9bf286cc638449668d2eec0018a4cf3fe6448673cd6729335e2b", "0xb29852f6aa6c60effdffe96ae88590c88abae732561d35cc19e82d3a51e26cb35ea00986193e07f90060756240f5346e", "0xa0fa855adc5ba469f35800c48414b8921455950a5c0a49945d1ef6e8f2a1881f2e2dfae47de6417270a6bf49deeb091d", "0xb6c7332e3b14813641e7272d4f69ecc7e09081df0037d6dab97ce13a9e58510f5c930d300633f208181d9205c5534001", "0x85a6c050f42fce560b5a8d54a11c3bbb8407abbadd859647a7b0c21c4b579ec65671098b74f10a16245dc779dff7838e", "0x8f3eb34bb68759d53c6677de4de78a6c24dd32c8962a7fb355ed362572ef8253733e6b52bc21c9f92ecd875020a9b8de", "0xa17dd44181e5dab4dbc128e1af93ec22624b57a448ca65d2d9e246797e4af7d079e09c6e0dfb62db3a9957ce92f098d5", "0xa56a1b854c3183082543a8685bb34cae1289f86cfa8123a579049dbd059e77982886bfeb61bf6e05b4b1fe4e620932e7", "0xaedae3033cb2fb7628cb4803435bdd7757370a86f808ae4cecb9a268ad0e875f308c048c80cbcac523de16b609683887", "0x9344905376aa3982b1179497fac5a1d74b14b7038fd15e3b002db4c11c8bfc7c39430db492cdaf58b9c47996c9901f28", "0xa3bfafdae011a19f030c749c3b071f83580dee97dd6f949e790366f95618ca9f828f1daaeabad6dcd664fcef81b6556d", "0x81c03d8429129e7e04434dee2c529194ddb01b414feda3adee2271eb680f6c85ec872a55c9fa9d2096f517e13ed5abcc", "0x98205ef3a72dff54c5a9c82d293c3e45d908946fa74bb749c3aabe1ab994ea93c269bcce1a266d2fe67a8f02133c5985", "0x85a70aeed09fda24412fadbafbbbf5ba1e00ac92885df329e147bfafa97b57629a3582115b780d8549d07d19b7867715", "0xb0fbe81c719f89a57d9ea3397705f898175808c5f75f8eb81c2193a0b555869ba7bd2e6bc54ee8a60cea11735e21c68c", "0xb03a0bd160495ee626ff3a5c7d95bc79d7da7e5a96f6d10116600c8fa20bedd1132f5170f25a22371a34a2d763f2d6d0", "0xa90ab04091fbca9f433b885e6c1d60ab45f6f1daf4b35ec22b09909d493a6aab65ce41a6f30c98239cbca27022f61a8b", "0xb66f92aa3bf2549f9b60b86f99a0bd19cbdd97036d4ae71ca4b83d669607f275260a497208f6476cde1931d9712c2402", "0xb08e1fdf20e6a9b0b4942f14fa339551c3175c1ffc5d0ab5b226b6e6a322e9eb0ba96adc5c8d59ca4259e2bdd04a7eb0", "0xa2812231e92c1ce74d4f5ac3ab6698520288db6a38398bb38a914ac9326519580af17ae3e27cde26607e698294022c81", "0xabfcbbcf1d3b9e84c02499003e490a1d5d9a2841a9e50c7babbef0b2dd20d7483371d4dc629ba07faf46db659459d296", "0xb0fe9f98c3da70927c23f2975a9dc4789194d81932d2ad0f3b00843dd9cbd7fb60747a1da8fe5a79f136a601becf279d", "0xb130a6dba7645165348cb90f023713bed0eefbd90a976b313521c60a36d34f02032e69a2bdcf5361e343ed46911297ec", "0x862f0cffe3020cea7a5fd4703353aa1eb1be335e3b712b29d079ff9f7090d1d8b12013011e1bdcbaa80c44641fd37c9f", "0x8c6f11123b26633e1abb9ed857e0bce845b2b3df91cc7b013b2fc77b477eee445da0285fc6fc793e29d5912977f40916", "0x91381846126ea819d40f84d3005e9fb233dc80071d1f9bb07f102bf015f813f61e5884ffffb4f5cd333c1b1e38a05a58", "0x8add7d908de6e1775adbd39c29a391f06692b936518db1f8fde74eb4f533fc510673a59afb86e3a9b52ade96e3004c57", "0x8780e086a244a092206edcde625cafb87c9ab1f89cc3e0d378bc9ee776313836160960a82ec397bc3800c0a0ec3da283", "0xa6cb4cd9481e22870fdd757fae0785edf4635e7aacb18072fe8dc5876d0bab53fb99ce40964a7d3e8bcfff6f0ab1332f", "0xaf30ff47ecc5b543efba1ba4706921066ca8bb625f40e530fb668aea0551c7647a9d126e8aba282fbcce168c3e7e0130", "0x91b0bcf408ce3c11555dcb80c4410b5bc2386d3c05caec0b653352377efdcb6bab4827f2018671fc8e4a0e90d772acc1", "0xa9430b975ef138b6b2944c7baded8fe102d31da4cfe3bd3d8778bda79189c99d38176a19c848a19e2d1ee0bddd9a13c1", "0xaa5a4eef849d7c9d2f4b018bd01271c1dd83f771de860c4261f385d3bdcc130218495860a1de298f14b703ec32fa235f", "0xb0ce79e7f9ae57abe4ff366146c3b9bfb38b0dee09c28c28f5981a5d234c6810ad4d582751948affb480d6ae1c8c31c4", "0xb75122748560f73d15c01a8907d36d06dc068e82ce22b84b322ac1f727034493572f7907dec34ebc3ddcc976f2f89ed7", "0xb0fc7836369a3e4411d34792d6bd5617c14f61d9bba023dda64e89dc5fb0f423244e9b48ee64869258931daa9753a56f", "0x8956d7455ae9009d70c6e4a0bcd7610e55f37494cf9897a8f9e1b904cc8febc3fd2d642ebd09025cfff4609ad7e3bc52", "0xad741efe9e472026aa49ae3d9914cb9c1a6f37a54f1a6fe6419bebd8c7d68dca105a751c7859f4389505ede40a0de786", "0xb52f418797d719f0d0d0ffb0846788b5cba5d0454a69a2925de4b0b80fa4dd7e8c445e5eac40afd92897ed28ca650566", "0xa0ab65fb9d42dd966cd93b1de01d7c822694669dd2b7a0c04d99cd0f3c3de795f387b9c92da11353412f33af5c950e9a", "0xa0052f44a31e5741a331f7cac515a08b3325666d388880162d9a7b97598fde8b61f9ff35ff220df224eb5c4e40ef0567", "0xa0101cfdc94e42b2b976c0d89612a720e55d145a5ef6ef6f1f78cf6de084a49973d9b5d45915349c34ce712512191e3c", "0xa0dd99fcf3f5cead5aaf08e82212df3a8bb543c407a4d6fab88dc5130c1769df3f147e934a46f291d6c1a55d92b86917", "0xa5939153f0d1931bbda5cf6bdf20562519ea55fbfa978d6dbc6828d298260c0da7a50c37c34f386e59431301a96c2232", "0x9568269f3f5257200f9ca44afe1174a5d3cf92950a7f553e50e279c239e156a9faaa2a67f288e3d5100b4142efe64856", "0xb746b0832866c23288e07f24991bbf687cad794e7b794d3d3b79367566ca617d38af586cdc8d6f4a85a34835be41d54f", "0xa871ce28e39ab467706e32fec1669fda5a4abba2f8c209c6745df9f7a0fa36bbf1919cf14cb89ea26fa214c4c907ae03", "0xa08dacdd758e523cb8484f6bd070642c0c20e184abdf8e2a601f61507e93952d5b8b0c723c34fcbdd70a8485eec29db2", "0x85bdb78d501382bb95f1166b8d032941005661aefd17a5ac32df9a3a18e9df2fc5dc2c1f07075f9641af10353cecc0c9", "0x98d730c28f6fa692a389e97e368b58f4d95382fad8f0baa58e71a3d7baaea1988ead47b13742ce587456f083636fa98e", "0xa557198c6f3d5382be9fb363feb02e2e243b0c3c61337b3f1801c4a0943f18e38ce1a1c36b5c289c8fa2aa9d58742bab", "0x89174f79201742220ac689c403fc7b243eed4f8e3f2f8aba0bf183e6f5d4907cb55ade3e238e3623d9885f03155c4d2b", "0xb891d600132a86709e06f3381158db300975f73ea4c1f7c100358e14e98c5fbe792a9af666b85c4e402707c3f2db321e", "0xb9e5b2529ef1043278c939373fc0dbafe446def52ddd0a8edecd3e4b736de87e63e187df853c54c28d865de18a358bb6", "0x8589b2e9770340c64679062c5badb7bbef68f55476289b19511a158a9a721f197da03ece3309e059fc4468b15ac33aa3", "0xaad8c6cd01d785a881b446f06f1e9cd71bca74ba98674c2dcddc8af01c40aa7a6d469037498b5602e76e9c91a58d3dbd", "0xabaccb1bd918a8465f1bf8dbe2c9ad4775c620b055550b949a399f30cf0d9eb909f3851f5b55e38f9e461e762f88f499", "0xae62339d26db46e85f157c0151bd29916d5cc619bd4b832814b3fd2f00af8f38e7f0f09932ffe5bba692005dab2d9a74", "0x93a6ff30a5c0edf8058c89aba8c3259e0f1b1be1b80e67682de651e5346f7e1b4b4ac3d87cbaebf198cf779524aff6bf", "0x8980a2b1d8f574af45b459193c952400b10a86122b71fca2acb75ee0dbd492e7e1ef5b959baf609a5172115e371f3177", "0x8c2f49f3666faee6940c75e8c7f6f8edc3f704cca7a858bbb7ee5e96bba3b0cf0993996f781ba6be3b0821ef4cb75039", "0xb14b9e348215b278696018330f63c38db100b0542cfc5be11dc33046e3bca6a13034c4ae40d9cef9ea8b34fef0910c4e", "0xb59bc3d0a30d66c16e6a411cb641f348cb1135186d5f69fda8b0a0934a5a2e7f6199095ba319ec87d3fe8f1ec4a06368", "0x8874aca2a3767aa198e4c3fec2d9c62d496bc41ff71ce242e9e082b7f38cdf356089295f80a301a3cf1182bde5308c97", "0xb1820ebd61376d91232423fc20bf008b2ba37e761199f4ef0648ea2bd70282766799b4de814846d2f4d516d525c8daa7", "0xa6b202e5dedc16a4073e04a11af3a8509b23dfe5a1952f899adeb240e75c3f5bde0c424f811a81ea48d343591faffe46", "0xa69becee9c93734805523b92150a59a62eed4934f66056b645728740d42223f2925a1ad38359ba644da24d9414f4cdda", "0xad72f0f1305e37c7e6b48c272323ee883320994cb2e0d850905d6655fafc9f361389bcb9c66b3ff8d2051dbb58c8aa96", "0xb563600bd56fad7c8853af21c6a02a16ed9d8a8bbeea2c31731d63b976d83cb05b9779372d898233e8fd597a75424797", "0xb0abb78ce465bf7051f563c62e8be9c57a2cc997f47c82819300f36e301fefd908894bb2053a9d27ce2d0f8c46d88b5b", "0xa071a85fb8274bac2202e0cb8e0e2028a5e138a82d6e0374d39ca1884a549c7c401312f00071b91f455c3a2afcfe0cda", "0xb931c271513a0f267b9f41444a5650b1918100b8f1a64959c552aff4e2193cc1b9927906c6fa7b8a8c68ef13d79aaa52", "0xa6a1bb9c7d32cb0ca44d8b75af7e40479fbce67d216b48a2bb680d3f3a772003a49d3cd675fc64e9e0f8fabeb86d6d61", "0xb98d609858671543e1c3b8564162ad828808bb50ded261a9f8690ded5b665ed8368c58f947365ed6e84e5a12e27b423d", "0xb3dca58cd69ec855e2701a1d66cad86717ff103ef862c490399c771ad28f675680f9500cb97be48de34bcdc1e4503ffd", "0xb34867c6735d3c49865e246ddf6c3b33baf8e6f164db3406a64ebce4768cb46b0309635e11be985fee09ab7a31d81402", "0xacb966c554188c5b266624208f31fab250b3aa197adbdd14aee5ab27d7fb886eb4350985c553b20fdf66d5d332bfd3fe", "0x943c36a18223d6c870d54c3b051ef08d802b85e9dd6de37a51c932f90191890656c06adfa883c87b906557ae32d09da0", "0x81bca7954d0b9b6c3d4528aadf83e4bc2ef9ea143d6209bc45ae9e7ae9787dbcd8333c41f12c0b6deee8dcb6805e826a", "0xaba176b92256efb68f574e543479e5cf0376889fb48e3db4ebfb7cba91e4d9bcf19dcfec444c6622d9398f06de29e2b9", "0xb9f743691448053216f6ece7cd699871fff4217a1409ceb8ab7bdf3312d11696d62c74b0664ba0a631b1e0237a8a0361", "0xa383c2b6276fa9af346b21609326b53fb14fdf6f61676683076e80f375b603645f2051985706d0401e6fbed7eb0666b6", "0xa9ef2f63ec6d9beb8f3d04e36807d84bda87bdd6b351a3e4a9bf7edcb5618c46c1f58cfbf89e64b40f550915c6988447", "0xa141b2d7a82f5005eaea7ae7d112c6788b9b95121e5b70b7168d971812f3381de8b0082ac1f0a82c7d365922ebd2d26a", "0xb1b76ef8120e66e1535c17038b75255a07849935d3128e3e99e56567b842fb1e8d56ef932d508d2fb18b82f7868fe1a9", "0x8e2e234684c81f21099f5c54f6bbe2dd01e3b172623836c77668a0c49ce1fe218786c3827e4d9ae2ea25c50a8924fb3c", "0xa5caf5ff948bfd3c4ca3ffbdfcd91eec83214a6c6017235f309a0bbf7061d3b0b466307c00b44a1009cf575163898b43", "0x986415a82ca16ebb107b4c50b0c023c28714281db0bcdab589f6cb13d80e473a3034b7081b3c358e725833f6d845cb14", "0xb94836bf406ac2cbacb10e6df5bcdfcc9d9124ae1062767ca4e322d287fd5e353fdcebd0e52407cb3cd68571258a8900", "0x83c6d70a640b33087454a4788dfd9ef3ed00272da084a8d36be817296f71c086b23b576f98178ab8ca6a74f04524b46b", "0xad4115182ad784cfe11bcfc5ce21fd56229cc2ce77ac82746e91a2f0aa53ca6593a22efd2dc4ed8d00f84542643d9c58", "0xab1434c5e5065da826d10c2a2dba0facccab0e52b506ce0ce42fbe47ced5a741797151d9ecc99dc7d6373cfa1779bbf6", "0x8a8b591d82358d55e6938f67ea87a89097ab5f5496f7260adb9f649abb289da12b498c5b2539c2f9614fb4e21b1f66b0", "0x964f355d603264bc1f44c64d6d64debca66f37dff39c971d9fc924f2bc68e6c187b48564a6dc82660a98b035f8addb5d", "0xb66235eaaf47456bc1dc4bde454a028e2ce494ece6b713a94cd6bf27cf18c717fd0c57a5681caaa2ad73a473593cdd7a", "0x9103e3bb74304186fa4e3e355a02da77da4aca9b7e702982fc2082af67127ebb23a455098313c88465bc9b7d26820dd5", "0xb6a42ff407c9dd132670cdb83cbad4b20871716e44133b59a932cd1c3f97c7ac8ff7f61acfaf8628372508d8dc8cad7c", "0x883a9c21c16a167a4171b0f084565c13b6f28ba7c4977a0de69f0a25911f64099e7bbb4da8858f2e93068f4155d04e18", "0x8dbb3220abc6a43220adf0331e3903d3bfd1d5213aadfbd8dfcdf4b2864ce2e96a71f35ecfb7a07c3bbabf0372b50271", "0xb4ad08aee48e176bda390b7d9acf2f8d5eb008f30d20994707b757dc6a3974b2902d29cd9b4d85e032810ad25ac49e97", "0x865bb0f33f7636ec501bb634e5b65751c8a230ae1fa807a961a8289bbf9c7fe8c59e01fbc4c04f8d59b7f539cf79ddd5", "0x86a54d4c12ad1e3605b9f93d4a37082fd26e888d2329847d89afa7802e815f33f38185c5b7292293d788ad7d7da1df97", "0xb26c8615c5e47691c9ff3deca3021714662d236c4d8401c5d27b50152ce7e566266b9d512d14eb63e65bc1d38a16f914", "0x827639d5ce7db43ba40152c8a0eaad443af21dc92636cc8cc2b35f10647da7d475a1e408901cd220552fddad79db74df", "0xa2b79a582191a85dbe22dc384c9ca3de345e69f6aa370aa6d3ff1e1c3de513e30b72df9555b15a46586bd27ea2854d9d", "0xae0d74644aba9a49521d3e9553813bcb9e18f0b43515e4c74366e503c52f47236be92dfbd99c7285b3248c267b1de5a0", "0x80fb0c116e0fd6822a04b9c25f456bdca704e2be7bdc5d141dbf5d1c5eeb0a2c4f5d80db583b03ef3e47517e4f9a1b10", "0xac3a1fa3b4a2f30ea7e0a114cdc479eb51773573804c2a158d603ad9902ae8e39ffe95df09c0d871725a5d7f9ba71a57", "0xb56b2b0d601cba7f817fa76102c68c2e518c6f20ff693aad3ff2e07d6c4c76203753f7f91686b1801e8c4659e4d45c48", "0x89d50c1fc56e656fb9d3915964ebce703cb723fe411ab3c9eaa88ccc5d2b155a9b2e515363d9c600d3c0cee782c43f41", "0xb24207e61462f6230f3cd8ccf6828357d03e725769f7d1de35099ef9ee4dca57dbce699bb49ed994462bee17059d25ce", "0xb886f17fcbcbfcd08ac07f04bb9543ef58510189decaccea4b4158c9174a067cb67d14b6be3c934e6e2a18c77efa9c9c", "0xb9c050ad9cafd41c6e2e192b70d080076eed59ed38ea19a12bd92fa17b5d8947d58d5546aaf5e8e27e1d3b5481a6ce51", "0xaaf7a34d3267e3b1ddbc54c641e3922e89303f7c86ebebc7347ebca4cffad5b76117dac0cbae1a133053492799cd936f", "0xa9ee604ada50adef82e29e893070649d2d4b7136cc24fa20e281ce1a07bd736bf0de7c420369676bcbcecff26fb6e900", "0x9855315a12a4b4cf80ab90b8bd13003223ba25206e52fd4fe6a409232fbed938f30120a3db23eab9c53f308bd8b9db81", "0x8cd488dd7a24f548a3cf03c54dec7ff61d0685cb0f6e5c46c2d728e3500d8c7bd6bba0156f4bf600466fda53e5b20444", "0x890ad4942ebac8f5b16c777701ab80c68f56fa542002b0786f8fea0fb073154369920ac3dbfc07ea598b82f4985b8ced", "0x8de0cf9ddc84c9b92c59b9b044387597799246b30b9f4d7626fc12c51f6e423e08ee4cbfe9289984983c1f9521c3e19d", "0xb474dfb5b5f4231d7775b3c3a8744956b3f0c7a871d835d7e4fd9cc895222c7b868d6c6ce250de568a65851151fac860", "0x86433b6135d9ed9b5ee8cb7a6c40e5c9d30a68774cec04988117302b8a02a11a71a1e03fd8e0264ef6611d219f103007", "0x80b9ed4adbe9538fb1ef69dd44ec0ec5b57cbfea820054d8d445b4261962624b4c70ac330480594bc5168184378379c3", "0x8b2e83562ccd23b7ad2d17f55b1ab7ef5fbef64b3a284e6725b800f3222b8bdf49937f4a873917ada9c4ddfb090938c2", "0xabe78cebc0f5a45d754140d1f685e387489acbfa46d297a8592aaa0d676a470654f417a4f7d666fc0b2508fab37d908e", "0xa9c5f8ff1f8568e252b06d10e1558326db9901840e6b3c26bbd0cd5e850cb5fb3af3f117dbb0f282740276f6fd84126f", "0x975f8dc4fb55032a5df3b42b96c8c0ffecb75456f01d4aef66f973cb7270d4eff32c71520ceefc1adcf38d77b6b80c67", "0xb043306ed2c3d8a5b9a056565afd8b5e354c8c4569fda66b0d797a50a3ce2c08cffbae9bbe292da69f39e89d5dc7911e", "0x8d2afc36b1e44386ba350c14a6c1bb31ff6ea77128a0c5287584ac3584282d18516901ce402b4644a53db1ed8e7fa581", "0x8c294058bed53d7290325c363fe243f6ec4f4ea2343692f4bac8f0cb86f115c069ccb8334b53d2e42c067691ad110dba", "0xb92157b926751aaf7ef82c1aa8c654907dccab6376187ee8b3e8c0c82811eae01242832de953faa13ebaff7da8698b3e", "0xa780c4bdd9e4ba57254b09d745075cecab87feda78c88ffee489625c5a3cf96aa6b3c9503a374a37927d9b78de9bd22b", "0x811f548ef3a2e6a654f7dcb28ac9378de9515ed61e5a428515d9594a83e80b35c60f96a5cf743e6fab0d3cb526149f49", "0x85a4dccf6d90ee8e094731eec53bd00b3887aec6bd81a0740efddf812fd35e3e4fe4f983afb49a8588691c202dabf942", "0xb152c2da6f2e01c8913079ae2b40a09b1f361a80f5408a0237a8131b429677c3157295e11b365b1b1841924b9efb922e", "0x849b9efee8742502ffd981c4517c88ed33e4dd518a330802caff168abae3cd09956a5ee5eda15900243bc2e829016b74", "0x955a933f3c18ec0f1c0e38fa931e4427a5372c46a3906ebe95082bcf878c35246523c23f0266644ace1fa590ffa6d119", "0x911989e9f43e580c886656377c6f856cdd4ff1bd001b6db3bbd86e590a821d34a5c6688a29b8d90f28680e9fdf03ba69", "0xb73b8b4f1fd6049fb68d47cd96a18fcba3f716e0a1061aa5a2596302795354e0c39dea04d91d232aec86b0bf2ba10522", "0x90f87456d9156e6a1f029a833bf3c7dbed98ca2f2f147a8564922c25ae197a55f7ea9b2ee1f81bf7383197c4bad2e20c", "0x903cba8b1e088574cb04a05ca1899ab00d8960580c884bd3c8a4c98d680c2ad11410f2b75739d6050f91d7208cac33a5", "0x9329987d42529c261bd15ecedd360be0ea8966e7838f32896522c965adfc4febf187db392bd441fb43bbd10c38fdf68b", "0x8178ee93acf5353baa349285067b20e9bb41aa32d77b5aeb7384fe5220c1fe64a2461bd7a83142694fe673e8bbf61b7c", "0xa06a8e53abcff271b1394bcc647440f81fb1c1a5f29c27a226e08f961c3353f4891620f2d59b9d1902bf2f5cc07a4553", "0xaaf5fe493b337810889e777980e6bbea6cac39ac66bc0875c680c4208807ac866e9fda9b5952aa1d04539b9f4a4bec57", "0xaa058abb1953eceac14ccfa7c0cc482a146e1232905dcecc86dd27f75575285f06bbae16a8c9fe8e35d8713717f5f19f", "0x8f15dd732799c879ca46d2763453b359ff483ca33adb1d0e0a57262352e0476c235987dc3a8a243c74bc768f93d3014c", "0xa61cc8263e9bc03cce985f1663b8a72928a607121005a301b28a278e9654727fd1b22bc8a949af73929c56d9d3d4a273", "0x98d6dc78502d19eb9f921225475a6ebcc7b44f01a2df6f55ccf6908d65b27af1891be2a37735f0315b6e0f1576c1f8d8", "0x8bd258b883f3b3793ec5be9472ad1ff3dc4b51bc5a58e9f944acfb927349ead8231a523cc2175c1f98e7e1e2b9f363b8", "0xaeacc2ecb6e807ad09bedd99654b097a6f39840e932873ace02eabd64ccfbb475abdcb62939a698abf17572d2034c51e", "0xb8ccf78c08ccd8df59fd6eda2e01de328bc6d8a65824d6f1fc0537654e9bc6bf6f89c422dd3a295cce628749da85c864", "0x8f91fd8cb253ba2e71cc6f13da5e05f62c2c3b485c24f5d68397d04665673167fce1fc1aec6085c69e87e66ec555d3fd", "0xa254baa10cb26d04136886073bb4c159af8a8532e3fd36b1e9c3a2e41b5b2b6a86c4ebc14dbe624ee07b7ccdaf59f9ab", "0x94e3286fe5cd68c4c7b9a7d33ae3d714a7f265cf77cd0e9bc19fc51015b1d1c34ad7e3a5221c459e89f5a043ee84e3a9", "0xa279da8878af8d449a9539bec4b17cea94f0242911f66fab275b5143ab040825f78c89cb32a793930609415cfa3a1078", "0xac846ceb89c9e5d43a2991c8443079dc32298cd63e370e64149cec98cf48a6351c09c856f2632fd2f2b3d685a18bbf8b", "0xa847b27995c8a2e2454aaeb983879fb5d3a23105c33175839f7300b7e1e8ec3efd6450e9fa3f10323609dee7b98c6fd5", "0xa2f432d147d904d185ff4b2de8c6b82fbea278a2956bc406855b44c18041854c4f0ecccd472d1d0dff1d8aa8e281cb1d", "0x94a48ad40326f95bd63dff4755f863a1b79e1df771a1173b17937f9baba57b39e651e7695be9f66a472f098b339364fc", "0xa12a0ccd8f96e96e1bc6494341f7ebce959899341b3a084aa1aa87d1c0d489ac908552b7770b887bb47e7b8cbc3d8e66", "0x81a1f1681bda923bd274bfe0fbb9181d6d164fe738e54e25e8d4849193d311e2c4253614ed673c98af2c798f19a93468", "0xabf71106a05d501e84cc54610d349d7d5eae21a70bd0250f1bebbf412a130414d1c8dbe673ffdb80208fd72f1defa4d4", "0x96266dc2e0df18d8136d79f5b59e489978eee0e6b04926687fe389d4293c14f36f055c550657a8e27be4118b64254901", "0x8df5dcbefbfb4810ae3a413ca6b4bf08619ca53cd50eb1dde2a1c035efffc7b7ac7dff18d403253fd80104bd83dc029e", "0x9610b87ff02e391a43324a7122736876d5b3af2a137d749c52f75d07b17f19900b151b7f439d564f4529e77aa057ad12", "0xa90a5572198b40fe2fcf47c422274ff36c9624df7db7a89c0eb47eb48a73a03c985f4ac5016161c76ca317f64339bce1", "0x98e5e61a6ab6462ba692124dba7794b6c6bde4249ab4fcc98c9edd631592d5bc2fb5e38466691a0970a38e48d87c2e43", "0x918cefb8f292f78d4db81462c633daf73b395e772f47b3a7d2cea598025b1d8c3ec0cbff46cdb23597e74929981cde40", "0xa98918a5dc7cf610fe55f725e4fd24ce581d594cb957bb9b4e888672e9c0137003e1041f83e3f1d7b9caab06462c87d4", "0xb92b74ac015262ca66c33f2d950221e19d940ba3bf4cf17845f961dc1729ae227aa9e1f2017829f2135b489064565c29", "0xa053ee339f359665feb178b4e7ee30a85df37debd17cacc5a27d6b3369d170b0114e67ad1712ed26d828f1df641bcd99", "0x8c3c8bad510b35da5ce5bd84b35c958797fbea024ad1c97091d2ff71d9b962e9222f65a9b776e5b3cc29c36e1063d2ee", "0xaf99dc7330fe7c37e850283eb47cc3257888e7c197cb0d102edf94439e1e02267b6a56306d246c326c4c79f9dc8c6986", "0xafecb2dc34d57a725efbd7eb93d61eb29dbe8409b668ab9ea040791f5b796d9be6d4fc10d7f627bf693452f330cf0435", "0x93334fedf19a3727a81a6b6f2459db859186227b96fe7a391263f69f1a0884e4235de64d29edebc7b99c44d19e7c7d7a", "0x89579c51ac405ad7e9df13c904061670ce4b38372492764170e4d3d667ed52e5d15c7cd5c5991bbfa3a5e4e3fa16363e", "0x9778f3e8639030f7ef1c344014f124e375acb8045bd13d8e97a92c5265c52de9d1ffebaa5bc3e1ad2719da0083222991", "0x88f77f34ee92b3d36791bdf3326532524a67d544297dcf1a47ff00b47c1b8219ff11e34034eab7d23b507caa2fd3c6b9", "0xa699c1e654e7c484431d81d90657892efeb4adcf72c43618e71ca7bd7c7a7ebbb1db7e06e75b75dc4c74efd306b5df3f", "0x81d13153baebb2ef672b5bdb069d3cd669ce0be96b742c94e04038f689ff92a61376341366b286eee6bf3ae85156f694", "0x81efb17de94400fdacc1deec2550cbe3eecb27c7af99d8207e2f9be397e26be24a40446d2a09536bb5172c28959318d9", "0x989b21ebe9ceab02488992673dc071d4d5edec24bff0e17a4306c8cb4b3c83df53a2063d1827edd8ed16d6e837f0d222", "0x8d6005d6536825661b13c5fdce177cb37c04e8b109b7eb2b6d82ea1cb70efecf6a0022b64f84d753d165edc2bba784a3", "0xa32607360a71d5e34af2271211652d73d7756d393161f4cf0da000c2d66a84c6826e09e759bd787d4fd0305e2439d342", "0xaaad8d6f6e260db45d51b2da723be6fa832e76f5fbcb77a9a31e7f090dd38446d3b631b96230d78208cae408c288ac4e", "0xabcfe425255fd3c5cffd3a818af7650190c957b6b07b632443f9e33e970a8a4c3bf79ac9b71f4d45f238a04d1c049857", "0xaeabf026d4c783adc4414b5923dbd0be4b039cc7201219f7260d321f55e9a5b166d7b5875af6129c034d0108fdc5d666", "0xaf49e740c752d7b6f17048014851f437ffd17413c59797e5078eaaa36f73f0017c3e7da020310cfe7d3c85f94a99f203", "0x8854ca600d842566e3090040cd66bb0b3c46dae6962a13946f0024c4a8aca447e2ccf6f240045f1ceee799a88cb9210c", "0xb6c03b93b1ab1b88ded8edfa1b487a1ed8bdce8535244dddb558ffb78f89b1c74058f80f4db2320ad060d0c2a9c351cc", "0xb5bd7d17372faff4898a7517009b61a7c8f6f0e7ed4192c555db264618e3f6e57fb30a472d169fea01bf2bf0362a19a8", "0x96eb1d38319dc74afe7e7eb076fcd230d19983f645abd14a71e6103545c01301b31c47ae931e025f3ecc01fb3d2f31fa", "0xb55a8d30d4403067def9b65e16f867299f8f64c9b391d0846d4780bc196569622e7e5b64ce799b5aefac8f965b2a7a7b", "0x8356d199a991e5cbbff608752b6291731b6b6771aed292f8948b1f41c6543e4ab1bedc82dd26d10206c907c03508df06", "0x97f4137445c2d98b0d1d478049de952610ad698c91c9d0f0e7227d2aae690e9935e914ec4a2ea1fbf3fc1dddfeeacebb", "0xaf5621707e0938320b15ddfc87584ab325fbdfd85c30efea36f8f9bd0707d7ec12c344eff3ec21761189518d192df035", "0x8ac7817e71ea0825b292687928e349da7140285d035e1e1abff0c3704fa8453faaae343a441b7143a74ec56539687cc4", "0x8a5e0a9e4758449489df10f3386029ada828d1762e4fb0a8ffe6b79e5b6d5d713cb64ed95960e126398b0cdb89002bc9", "0x81324be4a71208bbb9bca74b77177f8f1abb9d3d5d9db195d1854651f2cf333cd618d35400da0f060f3e1b025124e4b2", "0x849971d9d095ae067525b3cbc4a7dfae81f739537ade6d6cec1b42fb692d923176197a8770907c58069754b8882822d6", "0x89f830825416802477cc81fdf11084885865ee6607aa15aa4eb28e351c569c49b8a1b9b5e95ddc04fa0ebafe20071313", "0x9240aeeaff37a91af55f860b9badd466e8243af9e8c96a7aa8cf348cd270685ab6301bc135b246dca9eda696f8b0e350", "0xacf74db78cc33138273127599eba35b0fb4e7b9a69fe02dae18fc6692d748ca332bd00b22afa8e654ed587aab11833f3", "0xb091e6d37b157b50d76bd297ad752220cd5c9390fac16dc838f8557aed6d9833fc920b61519df21265406216315e883f", "0xa6446c429ebf1c7793c622250e23594c836b2fbcaf6c5b3d0995e1595a37f50ea643f3e549b0be8bbdadd69044d72ab9", "0x93e675353bd60e996bf1c914d5267eeaa8a52fc3077987ccc796710ef9becc6b7a00e3d82671a6bdfb8145ee3c80245a", "0xa2f731e43251d04ed3364aa2f072d05355f299626f2d71a8a38b6f76cf08c544133f7d72dd0ab4162814b674b9fc7fa6", "0x97a8b791a5a8f6e1d0de192d78615d73d0c38f1e557e4e15d15adc663d649e655bc8da3bcc499ef70112eafe7fb45c7a", "0x98cd624cbbd6c53a94469be4643c13130916b91143425bcb7d7028adbbfede38eff7a21092af43b12d4fab703c116359", "0x995783ce38fd5f6f9433027f122d4cf1e1ff3caf2d196ce591877f4a544ce9113ead60de2de1827eaff4dd31a20d79a8", "0x8cf251d6f5229183b7f3fe2f607a90b4e4b6f020fb4ba2459d28eb8872426e7be8761a93d5413640a661d73e34a5b81f", "0xb9232d99620652a3aa7880cad0876f153ff881c4ed4c0c2e7b4ea81d5d42b70daf1a56b869d752c3743c6d4c947e6641", "0x849716f938f9d37250cccb1bf77f5f9fde53096cdfc6f2a25536a6187029a8f1331cdbed08909184b201f8d9f04b792f", "0x80c7c4de098cbf9c6d17b14eba1805e433b5bc905f6096f8f63d34b94734f2e4ebf4bce8a177efd1186842a61204a062", "0xb790f410cf06b9b8daadceeb4fd5ff40a2deda820c8df2537e0a7554613ae3948e149504e3e79aa84889df50c8678eeb", "0x813aab8bd000299cd37485b73cd7cba06e205f8efb87f1efc0bae8b70f6db2bc7702eb39510ad734854fb65515fe9d0f", "0x94f0ab7388ac71cdb67f6b85dfd5945748afb2e5abb622f0b5ad104be1d4d0062b651f134ba22385c9e32c2dfdcccce1", "0xab6223dca8bd6a4f969e21ccd9f8106fc5251d321f9e90cc42cea2424b3a9c4e5060a47eeef6b23c7976109b548498e8", "0x859c56b71343fce4d5c5b87814c47bf55d581c50fd1871a17e77b5e1742f5af639d0e94d19d909ec7dfe27919e954e0c", "0xaae0d632b6191b8ad71b027791735f1578e1b89890b6c22e37de0e4a6074886126988fe8319ae228ac9ef3b3bcccb730", "0x8ca9f32a27a024c3d595ecfaf96b0461de57befa3b331ab71dc110ec3be5824fed783d9516597537683e77a11d334338", "0xa061df379fb3f4b24816c9f6cd8a94ecb89b4c6dc6cd81e4b8096fa9784b7f97ab3540259d1de9c02eb91d9945af4823", "0x998603102ac63001d63eb7347a4bb2bf4cf33b28079bb48a169076a65c20d511ccd3ef696d159e54cc8e772fb5d65d50", "0x94444d96d39450872ac69e44088c252c71f46be8333a608a475147752dbb99db0e36acfc5198f158509401959c12b709", "0xac1b51b6c09fe055c1d7c9176eea9adc33f710818c83a1fbfa073c8dc3a7eb3513cbdd3f5960b7845e31e3e83181e6ba", "0x803d530523fc9e1e0f11040d2412d02baef3f07eeb9b177fa9bfa396af42eea898a4276d56e1db998dc96ae47b644cb2", "0x85a3c9fc7638f5bf2c3e15ba8c2fa1ae87eb1ceb44c6598c67a2948667a9dfa41e61f66d535b4e7fda62f013a5a8b885", "0xa961cf5654c46a1a22c29baf7a4e77837a26b7f138f410e9d1883480ed5fa42411d522aba32040b577046c11f007388e", "0xad1154142344f494e3061ef45a34fab1aaacf5fdf7d1b26adbb5fbc3d795655fa743444e39d9a4119b4a4f82a6f30441", "0xb1d6c30771130c77806e7ab893b73d4deb590b2ff8f2f8b5e54c2040c1f3e060e2bd99afc668cf706a2df666a508bbf6", "0xa00361fd440f9decabd98d96c575cd251dc94c60611025095d1201ef2dedde51cb4de7c2ece47732e5ed9b3526c2012c", "0xa85c5ab4d17d328bda5e6d839a9a6adcc92ff844ec25f84981e4f44a0e8419247c081530f8d9aa629c7eb4ca21affba6", "0xa4ddd3eab4527a2672cf9463db38bc29f61460e2a162f426b7852b7a7645fbd62084fd39a8e4d60e1958cce436dd8f57", "0x811648140080fe55b8618f4cf17f3c5a250adb0cd53d885f2ddba835d2b4433188e41fc0661faac88e4ff910b16278c0", "0xb85c7f1cfb0ed29addccf7546023a79249e8f15ac2d14a20accbfef4dd9dc11355d599815fa09d2b6b4e966e6ea8cff1", "0xa10b5d8c260b159043b020d5dd62b3467df2671afea6d480ca9087b7e60ed170c82b121819d088315902842d66c8fb45", "0x917e191df1bcf3f5715419c1e2191da6b8680543b1ba41fe84ed07ef570376e072c081beb67b375fca3565a2565bcabb", "0x881fd967407390bfd7badc9ab494e8a287559a01eb07861f527207c127eadea626e9bcc5aa9cca2c5112fbac3b3f0e9c", "0x959fd71149af82cc733619e0e5bf71760ca2650448c82984b3db74030d0e10f8ab1ce1609a6de6f470fe8b5bd90df5b3", "0xa3370898a1c5f33d15adb4238df9a6c945f18b9ada4ce2624fc32a844f9ece4c916a64e9442225b6592afa06d2e015f2", "0x817efb8a791435e4236f7d7b278181a5fa34587578c629dbc14fbf9a5c26772290611395eecd20222a4c58649fc256d8", "0xa04c9876acf2cfdc8ef96de4879742709270fa1d03fe4c8511fbef2d59eb0aaf0336fa2c7dfe41a651157377fa217813", "0x81e15875d7ea7f123e418edf14099f2e109d4f3a6ce0eb65f67fe9fb10d2f809a864a29f60ad3fc949f89e2596b21783", "0xb49f529975c09e436e6bc202fdc16e3fdcbe056db45178016ad6fdece9faad4446343e83aed096209690b21a6910724f", "0x879e8eda589e1a279f7f49f6dd0580788c040d973748ec4942dbe51ea8fbd05983cc919b78f0c6b92ef3292ae29db875", "0x81a2b74b2118923f34139a102f3d95e7eee11c4c2929c2576dee200a5abfd364606158535a6c9e4178a6a83dbb65f3c4", "0x8913f281d8927f2b45fc815d0f7104631cb7f5f7278a316f1327d670d15868daadd2a64e3eb98e1f53fe7e300338cc80", "0xa6f815fba7ef9af7fbf45f93bc952e8b351f5de6568a27c7c47a00cb39a254c6b31753794f67940fc7d2e9cc581529f4", "0xb3722a15c66a0014ce4d082de118def8d39190c15678a472b846225585f3a83756ae1b255b2e3f86a26168878e4773b2", "0x817ae61ab3d0dd5b6e24846b5a5364b1a7dc2e77432d9fed587727520ae2f307264ea0948c91ad29f0aea3a11ff38624", "0xb3db467464415fcad36dc1de2d6ba7686772a577cc2619242ac040d6734881a45d3b40ed4588db124e4289cfeec4bbf6", "0xad66a14f5a54ac69603b16e5f1529851183da77d3cc60867f10aea41339dd5e06a5257982e9e90a352cdd32750f42ee4", "0xadafa3681ef45d685555601a25a55cf23358319a17f61e2179e704f63df83a73bdd298d12cf6cef86db89bd17119e11d", "0xa379dc44cb6dd3b9d378c07b2ec654fec7ca2f272de6ba895e3d00d20c9e4c5550498a843c8ac67e4221db2115bedc1c", "0xb7bf81c267a78efc6b9e5a904574445a6487678d7ef70054e3e93ea6a23f966c2b68787f9164918e3b16d2175459ed92", "0xb41d66a13a4afafd5760062b77f79de7e6ab8ccacde9c6c5116a6d886912fb491dc027af435b1b44aacc6af7b3c887f2", "0x9904d23a7c1c1d2e4bab85d69f283eb0a8e26d46e8b7b30224438015c936729b2f0af7c7c54c03509bb0500acb42d8a4", "0xae30d65e9e20c3bfd603994ae2b175ff691d51f3e24b2d058b3b8556d12ca4c75087809062dddd4aaac81c94d15d8a17", "0x9245162fab42ac01527424f6013310c3eb462982518debef6c127f46ba8a06c705d7dc9f0a41e796ba8d35d60ae6cc64", "0x87fab853638d7a29a20f3ba2b1a7919d023e9415bfa78ebb27973d8cbc7626f584dc5665d2e7ad71f1d760eba9700d88", "0x85aac46ecd330608e5272430970e6081ff02a571e8ea444f1e11785ea798769634a22a142d0237f67b75369d3c484a8a", "0x938c85ab14894cc5dfce3d80456f189a2e98eddbc8828f4ff6b1df1dcb7b42b17ca2ff40226a8a1390a95d63dca698dd", "0xa18ce1f846e3e3c4d846822f60271eecf0f5d7d9f986385ac53c5ace9589dc7c0188910448c19b91341a1ef556652fa9", "0x8611608a9d844f0e9d7584ad6ccf62a5087a64f764caf108db648a776b5390feb51e5120f0ef0e9e11301af3987dd7dc", "0x8106333ba4b4de8d1ae43bc9735d3fea047392e88efd6a2fa6f7b924a18a7a265ca6123c3edc0f36307dd7fb7fe89257", "0xa91426fa500951ff1b051a248c050b7139ca30dde8768690432d597d2b3c4357b11a577be6b455a1c5d145264dcf81fc", "0xb7f9f90e0e450f37b081297f7f651bad0496a8b9afd2a4cf4120a2671aaaa8536dce1af301258bfbfdb122afa44c5048", "0x84126da6435699b0c09fa4032dec73d1fca21d2d19f5214e8b0bea43267e9a8dd1fc44f8132d8315e734c8e2e04d7291", "0xaff064708103884cb4f1a3c1718b3fc40a238d35cf0a7dc24bdf9823693b407c70da50df585bf5bc4e9c07d1c2d203e8", "0xa8b40fc6533752983a5329c31d376c7a5c13ce6879cc7faee648200075d9cd273537001fb4c86e8576350eaac6ba60c2", "0xa02db682bdc117a84dcb9312eb28fcbde12d49f4ce915cc92c610bb6965ec3cc38290f8c5b5ec70afe153956692cda95", "0x86decd22b25d300508472c9ce75d3e465b737e7ce13bc0fcce32835e54646fe12322ba5bc457be18bfd926a1a6ca4a38", "0xa18666ef65b8c2904fd598791f5627207165315a85ee01d5fb0e6b2e10bdd9b00babc447da5bd63445e3337de33b9b89", "0x89bb0c06effadefdaf34ffe4b123e1678a90d4451ee856c863df1e752eef41fd984689ded8f0f878bf8916d5dd8e8024", "0x97cfcba08ebec05d0073992a66b1d7d6fb9d95871f2cdc36db301f78bf8069294d1c259efef5c93d20dc937eedae3a1a", "0xac2643b14ece79dcb2e289c96776a47e2bebd40dd6dc74fd035df5bb727b5596f40e3dd2d2202141e69b0993717ede09", "0xa5e6fd88a2f9174d9bd4c6a55d9c30974be414992f22aa852f552c7648f722ed8077acf5aba030abd47939bb451b2c60", "0x8ad40a612824a7994487731a40b311b7349038c841145865539c6ada75c56de6ac547a1c23df190e0caaafecddd80ccc", "0x953a7cea1d857e09202c438c6108060961f195f88c32f0e012236d7a4b39d840c61b162ec86436e8c38567328bea0246", "0x80d8b47a46dae1868a7b8ccfe7029445bbe1009dad4a6c31f9ef081be32e8e1ac1178c3c8fb68d3e536c84990cc035b1", "0x81ecd99f22b3766ce0aca08a0a9191793f68c754fdec78b82a4c3bdc2db122bbb9ebfd02fc2dcc6e1567a7d42d0cc16a", "0xb1dd0446bccc25846fb95d08c1c9cc52fb51c72c4c5d169ffde56ecfe800f108dc1106d65d5c5bd1087c656de3940b63", "0xb87547f0931e164e96de5c550ca5aa81273648fe34f6e193cd9d69cf729cb432e17aa02e25b1c27a8a0d20a3b795e94e", "0x820a94e69a927e077082aae66f6b292cfbe4589d932edf9e68e268c9bd3d71ef76cf7d169dd445b93967c25db11f58f1", "0xb0d07ddf2595270c39adfa0c8cf2ab1322979b0546aa4d918f641be53cd97f36c879bb75d205e457c011aca3bbd9f731", "0x8700b876b35b4b10a8a9372c5230acecd39539c1bb87515640293ad4464a9e02929d7d6a6a11112e8a29564815ac0de4", "0xa61a601c5bb27dcb97e37c8e2b9ce479c6b192a5e04d9ed5e065833c5a1017ee5f237b77d1a17be5d48f8e7cc0bcacf6", "0x92fb88fe774c1ba1d4a08cae3c0e05467ad610e7a3f1d2423fd47751759235fe0a3036db4095bd6404716aa03820f484", "0xb274f140d77a3ce0796f5e09094b516537ccaf27ae1907099bff172e6368ba85e7c3ef8ea2a07457cac48ae334da95b3", "0xb2292d9181f16581a9a9142490b2bdcdfb218ca6315d1effc8592100d792eb89d5356996c890441f04f2b4a95763503e", "0x8897e73f576d86bc354baa3bd96e553107c48cf5889dcc23c5ba68ab8bcd4e81f27767be2233fdfa13d39f885087e668", "0xa29eac6f0829791c728d71abc49569df95a4446ecbfc534b39f24f56c88fe70301838dfc1c19751e7f3c5c1b8c6af6a0", "0x9346dc3720adc5df500a8df27fd9c75ef38dc5c8f4e8ed66983304750e66d502c3c59b8e955be781b670a0afc70a2167", "0x9566d534e0e30a5c5f1428665590617e95fd05d45f573715f58157854ad596ece3a3cfec61356aee342308d623e029d5", "0xa464fb8bffe6bd65f71938c1715c6e296cc6d0311a83858e4e7eb5873b7f2cf0c584d2101e3407b85b64ca78b2ac93ce", "0xb54088f7217987c87e9498a747569ac5b2f8afd5348f9c45bf3fd9fbf713a20f495f49c8572d087efe778ac7313ad6d3", "0x91fa9f5f8000fe050f5b224d90b59fcce13c77e903cbf98ded752e5b3db16adb2bc1f8c94be48b69f65f1f1ad81d6264", "0x92d04a5b0ac5d8c8e313709b432c9434ecd3e73231f01e9b4e7952b87df60cbfa97b5dedd2200bd033b4b9ea8ba45cc1", "0xa94b90ad3c3d6c4bbe169f8661a790c40645b40f0a9d1c7220f01cf7fc176e04d80bab0ced9323fcafb93643f12b2760", "0x94d86149b9c8443b46196f7e5a3738206dd6f3be7762df488bcbb9f9ee285a64c997ed875b7b16b26604fa59020a8199", "0x82efe4ae2c50a2d7645240c173a047f238536598c04a2c0b69c96e96bd18e075a99110f1206bc213f39edca42ba00cc1", "0xab8667685f831bc14d4610f84a5da27b4ea5b133b4d991741a9e64dceb22cb64a3ce8f1b6e101d52af6296df7127c9ad", "0x83ba433661c05dcc5d562f4a9a261c8110dac44b8d833ae1514b1fc60d8b4ee395b18804baea04cb10adb428faf713c3", "0xb5748f6f660cc5277f1211d2b8649493ed8a11085b871cd33a5aea630abd960a740f08c08be5f9c21574600ac9bf5737", "0xa5c8dd12af48fb710642ad65ebb97ca489e8206741807f7acfc334f8035d3c80593b1ff2090c9bb7bd138f0c48714ca8", "0xa2b382fd5744e3babf454b1d806cc8783efeb4761bc42b6914ea48a46a2eae835efbe0a18262b6bc034379e03cf1262b", "0xb3145ffaf603f69f15a64936d32e3219eea5ed49fdfd2f5bf40ea0dfd974b36fb6ff12164d4c2282d892db4cf3ff3ce1", "0x87a316fb213f4c5e30c5e3face049db66be4f28821bd96034714ec23d3e97849d7b301930f90a4323c7ccf53de23050c", "0xb9de09a919455070fed6220fc179c8b7a4c753062bcd27acf28f5b9947a659c0b364298daf7c85c4ca6fca7f945add1f", "0x806fbd98d411b76979464c40ad88bc07a151628a27fcc1012ba1dfbaf5b5cc9d962fb9b3386008978a12515edce934bc", "0xa15268877fae0d21610ae6a31061ed7c20814723385955fac09fdc9693a94c33dea11db98bb89fdfe68f933490f5c381", "0x8d633fb0c4da86b2e0b37d8fad5972d62bff2ac663c5ec815d095cd4b7e1fe66ebef2a2590995b57eaf941983c7ad7a4", "0x8139e5dd9cf405e8ef65f11164f0440827d98389ce1b418b0c9628be983a9ddd6cf4863036ccb1483b40b8a527acd9ed", "0x88b15fa94a08eac291d2b94a2b30eb851ff24addf2cc30b678e72e32cfcb3424cf4b33aa395d741803f3e578ddf524de", "0xb5eaf0c8506e101f1646bcf049ee38d99ea1c60169730da893fd6020fd00a289eb2f415947e44677af49e43454a7b1be", "0x8489822ad0647a7e06aa2aa5595960811858ddd4542acca419dd2308a8c5477648f4dd969a6740bb78aa26db9bfcc555", "0xb1e9a7b9f3423c220330d45f69e45fa03d7671897cf077f913c252e3e99c7b1b1cf6d30caad65e4228d5d7b80eb86e5e", "0xb28fe9629592b9e6a55a1406903be76250b1c50c65296c10c5e48c64b539fb08fe11f68cf462a6edcbba71b0cee3feb2", "0xa41acf96a02c96cd8744ff6577c244fc923810d17ade133587e4c223beb7b4d99fa56eae311a500d7151979267d0895c", "0x880798938fe4ba70721be90e666dfb62fcab4f3556fdb7b0dc8ec5bc34f6b4513df965eae78527136eb391889fe2caf9", "0x98d4d89d358e0fb7e212498c73447d94a83c1b66e98fc81427ab13acddb17a20f52308983f3a5a8e0aaacec432359604", "0x81430b6d2998fc78ba937a1639c6020199c52da499f68109da227882dc26d005b73d54c5bdcac1a04e8356a8ca0f7017", "0xa8d906a4786455eb74613aba4ce1c963c60095ffb8658d368df9266fdd01e30269ce10bf984e7465f34b4fd83beba26a", "0xaf54167ac1f954d10131d44a8e0045df00d581dd9e93596a28d157543fbe5fb25d213806ed7fb3cba6b8f5b5423562db", "0x8511e373a978a12d81266b9afbd55035d7bc736835cfa921903a92969eeba3624437d1346b55382e61415726ab84a448", "0x8cf43eea93508ae586fa9a0f1354a1e16af659782479c2040874a46317f9e8d572a23238efa318fdfb87cc63932602b7", "0xb0bdd3bacff077173d302e3a9678d1d37936188c7ecc34950185af6b462b7c679815176f3cce5db19aac8b282f2d60ad", "0xa355e9b87f2f2672052f5d4d65b8c1c827d24d89b0d8594641fccfb69aef1b94009105f3242058bb31c8bf51caae5a41", "0xb8baa9e4b950b72ff6b88a6509e8ed1304bc6fd955748b2e59a523a1e0c5e99f52aec3da7fa9ff407a7adf259652466c", "0x840bc3dbb300ea6f27d1d6dd861f15680bd098be5174f45d6b75b094d0635aced539fa03ddbccb453879de77fb5d1fe9", "0xb4bc7e7e30686303856472bae07e581a0c0bfc815657c479f9f5931cff208d5c12930d2fd1ff413ebd8424bcd7a9b571", "0x89b5d514155d7999408334a50822508b9d689add55d44a240ff2bdde2eee419d117031f85e924e2a2c1ca77db9b91eea", "0xa8604b6196f87a04e1350302e8aa745bba8dc162115d22657b37a1d1a98cb14876ddf7f65840b5dbd77e80cd22b4256c", "0x83cb7acdb9e03247515bb2ce0227486ccf803426717a14510f0d59d45e998b245797d356f10abca94f7a14e1a2f0d552", "0xaeb3266a9f16649210ab2df0e1908ac259f34ce1f01162c22b56cf1019096ee4ea5854c36e30bb2feb06c21a71e8a45c", "0x89e72e86edf2aa032a0fc9acf4d876a40865fbb2c8f87cb7e4d88856295c4ac14583e874142fd0c314a49aba68c0aa3c", "0x8c3576eba0583c2a7884976b4ed11fe1fda4f6c32f6385d96c47b0e776afa287503b397fa516a455b4b8c3afeedc76db", "0xa31e5b633bda9ffa174654fee98b5d5930a691c3c42fcf55673d927dbc8d91c58c4e42e615353145431baa646e8bbb30", "0x89f2f3f7a8da1544f24682f41c68114a8f78c86bd36b066e27da13acb70f18d9f548773a16bd8e24789420e17183f137", "0xada27fa4e90a086240c9164544d2528621a415a5497badb79f8019dc3dce4d12eb6b599597e47ec6ac39c81efda43520", "0x90dc1eb21bf21c0187f359566fc4bf5386abea52799306a0e5a1151c0817c5f5bc60c86e76b1929c092c0f3ff48cedd2", "0xb702a53ebcc17ae35d2e735a347d2c700e9cbef8eadbece33cac83df483b2054c126593e1f462cfc00a3ce9d737e2af5", "0x9891b06455ec925a6f8eafffba05af6a38cc5e193acaaf74ffbf199df912c5197106c5e06d72942bbb032ce277b6417f", "0x8c0ee71eb01197b019275bcf96cae94e81d2cdc3115dbf2d8e3080074260318bc9303597e8f72b18f965ad601d31ec43", "0x8aaf580aaf75c1b7a5f99ccf60503506e62058ef43b28b02f79b8536a96be3f019c9f71caf327b4e6730134730d1bef5", "0xae6f9fc21dd7dfa672b25a87eb0a41644f7609fab5026d5cedb6e43a06dbbfd6d6e30322a2598c8dedde88c52eaed626", "0x8159b953ffece5693edadb2e906ebf76ff080ee1ad22698950d2d3bfc36ac5ea78f58284b2ca180664452d55bd54716c", "0xab7647c32ca5e9856ac283a2f86768d68de75ceeba9e58b74c5324f8298319e52183739aba4340be901699d66ac9eb3f", "0xa4d85a5701d89bcfaf1572db83258d86a1a0717603d6f24ac2963ffcf80f1265e5ab376a4529ca504f4396498791253c", "0x816080c0cdbfe61b4d726c305747a9eb58ac26d9a35f501dd32ba43c098082d20faf3ccd41aad24600aa73bfa453dfac", "0x84f3afac024f576b0fd9acc6f2349c2fcefc3f77dbe5a2d4964d14b861b88e9b1810334b908cf3427d9b67a8aee74b18", "0x94b390655557b1a09110018e9b5a14490681ade275bdc83510b6465a1218465260d9a7e2a6e4ec700f58c31dc3659962", "0xa8c66826b1c04a2dd4c682543242e7a57acae37278bd09888a3d17747c5b5fec43548101e6f46d703638337e2fd3277b", "0x86e6f4608a00007fa533c36a5b054c5768ccafe41ad52521d772dcae4c8a4bcaff8f7609be30d8fab62c5988cbbb6830", "0x837da4cf09ae8aa0bceb16f8b3bfcc3b3367aecac9eed6b4b56d7b65f55981ef066490764fb4c108792623ecf8cad383", "0x941ff3011462f9b5bf97d8cbdb0b6f5d37a1b1295b622f5485b7d69f2cb2bcabc83630dae427f0259d0d9539a77d8424", "0xb99e5d6d82aa9cf7d5970e7f710f4039ac32c2077530e4c2779250c6b9b373bc380adb0a03b892b652f649720672fc8c", "0xa791c78464b2d65a15440b699e1e30ebd08501d6f2720adbc8255d989a82fcded2f79819b5f8f201bed84a255211b141", "0x84af7ad4a0e31fcbb3276ab1ad6171429cf39adcf78dc03750dc5deaa46536d15591e26d53e953dfb31e1622bc0743ab", "0xa833e62fe97e1086fae1d4917fbaf09c345feb6bf1975b5cb863d8b66e8d621c7989ab3dbecda36bc9eaffc5eaa6fa66", "0xb4ef79a46a2126f53e2ebe62770feb57fd94600be29459d70a77c5e9cc260fa892be06cd60f886bf48459e48eb50d063", "0xb43b8f61919ea380bf151c294e54d3a3ff98e20d1ee5efbfe38aa2b66fafbc6a49739793bd5cb1c809f8b30466277c3a", "0xab37735af2412d2550e62df9d8b3b5e6f467f20de3890bf56faf1abf2bf3bd1d98dc3fa0ad5e7ab3fce0fa20409eb392", "0x82416b74b1551d484250d85bb151fabb67e29cce93d516125533df585bc80779ab057ea6992801a3d7d5c6dcff87a018", "0x8145d0787f0e3b5325190ae10c1d6bee713e6765fb6a0e9214132c6f78f4582bb2771aaeae40d3dad4bafb56bf7e36d8", "0xb6935886349ecbdd5774e12196f4275c97ec8279fdf28ccf940f6a022ebb6de8e97d6d2173c3fe402cbe9643bed3883b", "0x87ef9b4d3dc71ac86369f8ed17e0dd3b91d16d14ae694bc21a35b5ae37211b043d0e36d8ff07dcc513fb9e6481a1f37f", "0xae1d0ded32f7e6f1dc8fef495879c1d9e01826f449f903c1e5034aeeabc5479a9e323b162b688317d46d35a42d570d86", "0xa40d16497004db4104c6794e2f4428d75bdf70352685944f3fbe17526df333e46a4ca6de55a4a48c02ecf0bde8ba03c0", "0x8d45121efba8cc308a498e8ee39ea6fa5cae9fb2e4aab1c2ff9d448aa8494ccbec9a078f978a86fcd97b5d5e7be7522a", "0xa8173865c64634ba4ac2fa432740f5c05056a9deaf6427cb9b4b8da94ca5ddbc8c0c5d3185a89b8b28878194de9cdfcd", "0xb6ec06a74d690f6545f0f0efba236e63d1fdfba54639ca2617408e185177ece28901c457d02b849fd00f1a53ae319d0a", "0xb69a12df293c014a40070e3e760169b6f3c627caf9e50b35a93f11ecf8df98b2bc481b410eecb7ab210bf213bbe944de", "0x97e7dc121795a533d4224803e591eef3e9008bab16f12472210b73aaf77890cf6e3877e0139403a0d3003c12c8f45636", "0xacdfa6fdd4a5acb7738cc8768f7cba84dbb95c639399b291ae8e4e63df37d2d4096900a84d2f0606bf534a9ccaa4993f", "0x86ee253f3a9446a33e4d1169719b7d513c6b50730988415382faaf751988c10a421020609f7bcdef91be136704b906e2", "0xaac9438382a856caf84c5a8a234282f71b5fc5f65219103b147e7e6cf565522285fbfd7417b513bdad8277a00f652ca1", "0x83f3799d8e5772527930f5dc071a2e0a65471618993ec8990a96ccdeee65270e490bda9d26bb877612475268711ffd80", "0x93f28a81ac8c0ec9450b9d762fae9c7f8feaace87a6ee6bd141ef1d2d0697ef1bbd159fe6e1de640dbdab2b0361fca8a", "0xa0825c95ba69999b90eac3a31a3fd830ea4f4b2b7409bde5f202b61d741d6326852ce790f41de5cb0eccec7af4db30c1", "0x83924b0e66233edd603c3b813d698daa05751fc34367120e3cf384ea7432e256ccee4d4daf13858950549d75a377107d", "0x956fd9fa58345277e06ba2ec72f49ed230b8d3d4ff658555c52d6cddeb84dd4e36f1a614f5242d5ca0192e8daf0543c2", "0x944869912476baae0b114cced4ff65c0e4c90136f73ece5656460626599051b78802df67d7201c55d52725a97f5f29fe", "0x865cb25b64b4531fb6fe4814d7c8cd26b017a6c6b72232ff53defc18a80fe3b39511b23f9e4c6c7249d06e03b2282ed2", "0x81e09ff55214960775e1e7f2758b9a6c4e4cd39edf7ec1adfaad51c52141182b79fe2176b23ddc7df9fd153e5f82d668", "0xb31006896f02bc90641121083f43c3172b1039334501fbaf1672f7bf5d174ddd185f945adf1a9c6cf77be34c5501483d", "0x88b92f6f42ae45e9f05b16e52852826e933efd0c68b0f2418ac90957fd018df661bc47c8d43c2a7d7bfcf669dab98c3c", "0x92fc68f595853ee8683930751789b799f397135d002eda244fe63ecef2754e15849edde3ba2f0cc8b865c9777230b712", "0x99ca06a49c5cd0bb097c447793fcdd809869b216a34c66c78c7e41e8c22f05d09168d46b8b1f3390db9452d91bc96dea", "0xb48b9490a5d65296802431852d548d81047bbefc74fa7dc1d4e2a2878faacdfcb365ae59209cb0ade01901a283cbd15d", "0xaff0fdbef7c188b120a02bc9085d7b808e88f73973773fef54707bf2cd772cd066740b1b6f4127b5c349f657bd97e738", "0x966fd4463b4f43dd8ccba7ad50baa42292f9f8b2e70da23bb6780e14155d9346e275ef03ddaf79e47020dcf43f3738bd", "0x9330c3e1fadd9e08ac85f4839121ae20bbeb0a5103d84fa5aadbd1213805bdcda67bf2fb75fc301349cbc851b5559d20", "0x993bb99867bd9041a71a55ad5d397755cfa7ab6a4618fc526179bfc10b7dc8b26e4372fe9a9b4a15d64f2b63c1052dda", "0xa29b59bcfab51f9b3c490a3b96f0bf1934265c315349b236012adbd64a56d7f6941b2c8cc272b412044bc7731f71e1dc", "0xa65c9cefe1fc35d089fe8580c2e7671ebefdb43014ac291528ff4deefd4883fd4df274af83711dad610dad0d615f9d65", "0x944c78c56fb227ae632805d448ca3884cd3d2a89181cead3d2b7835e63297e6d740aa79a112edb1d4727824991636df5", "0xa73d782da1db7e4e65d7b26717a76e16dd9fab4df65063310b8e917dc0bc24e0d6755df5546c58504d04d9e68c3b474a", "0xaf80f0b87811ae3124f68108b4ca1937009403f87928bbc53480e7c5408d072053ace5eeaf5a5aba814dab8a45502085", "0x88aaf1acfc6e2e19b8387c97da707cb171c69812fefdd4650468e9b2c627bd5ccfb459f4d8e56bdfd84b09ddf87e128f", "0x92c97276ff6f72bab6e9423d02ad6dc127962dbce15a0dd1e4a393b4510c555df6aa27be0f697c0d847033a9ca8b8dfd", "0xa0e07d43d96e2d85b6276b3c60aadb48f0aedf2de8c415756dc597249ea64d2093731d8735231dadc961e5682ac59479", "0xadc9e6718a8f9298957d1da3842a7751c5399bbdf56f8de6c1c4bc39428f4aee6f1ba6613d37bf46b9403345e9d6fc81", "0x951da434da4b20d949b509ceeba02e24da7ed2da964c2fcdf426ec787779c696b385822c7dbea4df3e4a35921f1e912c", "0xa04cbce0d2b2e87bbf038c798a12ec828423ca6aca08dc8d481cf6466e3c9c73d4d4a7fa47df9a7e2e15aae9e9f67208", "0x8f855cca2e440d248121c0469de1f94c2a71b8ee2682bbad3a78243a9e03da31d1925e6760dbc48a1957e040fae9abe8", "0xb642e5b17c1df4a4e101772d73851180b3a92e9e8b26c918050f51e6dd3592f102d20b0a1e96f0e25752c292f4c903ff", "0xa92454c300781f8ae1766dbbb50a96192da7d48ef4cbdd72dd8cbb44c6eb5913c112cc38e9144615fdc03684deb99420", "0x8b74f7e6c2304f8e780df4649ef8221795dfe85fdbdaa477a1542d135b75c8be45bf89adbbb6f3ddf54ca40f02e733e9", "0x85cf66292cbb30cec5fd835ab10c9fcb3aea95e093aebf123e9a83c26f322d76ebc89c4e914524f6c5f6ee7d74fc917d", "0xae0bfe0cdc97c09542a7431820015f2d16067b30dca56288013876025e81daa8c519e5e347268e19aa1a85fa1dc28793", "0x921322fc6a47dc091afa0ad6df18ed14cde38e48c6e71550aa513918b056044983aee402de21051235eecf4ce8040fbe", "0x96c030381e97050a45a318d307dcb3c8377b79b4dd5daf6337cded114de26eb725c14171b9b8e1b3c08fe1f5ea6b49e0", "0x90c23b86b6111818c8baaf53a13eaee1c89203b50e7f9a994bf0edf851919b48edbac7ceef14ac9414cf70c486174a77", "0x8bf6c301240d2d1c8d84c71d33a6dfc6d9e8f1cfae66d4d0f7a256d98ae12b0bcebfa94a667735ee89f810bcd7170cff", "0xa41a4ffbbea0e36874d65c009ee4c3feffff322f6fc0e30d26ee4dbc1f46040d05e25d9d0ecb378cef0d24a7c2c4b850", "0xa8d4cdd423986bb392a0a92c12a8bd4da3437eec6ef6af34cf5310944899287452a2eb92eb5386086d5063381189d10e", "0xa81dd26ec057c4032a4ed7ad54d926165273ed51d09a1267b2e477535cf6966835a257c209e4e92d165d74fa75695fa3", "0x8d7f708c3ee8449515d94fc26b547303b53d8dd55f177bc3b25d3da2768accd9bc8e9f09546090ebb7f15c66e6c9c723", "0x839ba65cffcd24cfffa7ab3b21faabe3c66d4c06324f07b2729c92f15cad34e474b0f0ddb16cd652870b26a756b731d3", "0x87f1a3968afec354d92d77e2726b702847c6afcabb8438634f9c6f7766de4c1504317dc4fa9a4a735acdbf985e119564", "0x91a8a7fd6542f3e0673f07f510d850864b34ac087eb7eef8845a1d14b2b1b651cbdc27fa4049bdbf3fea54221c5c8549", "0xaef3cf5f5e3a2385ead115728d7059e622146c3457d266c612e778324b6e06fbfb8f98e076624d2f3ce1035d65389a07", "0x819915d6232e95ccd7693fdd78d00492299b1983bc8f96a08dcb50f9c0a813ed93ae53c0238345d5bea0beda2855a913", "0x8e9ba68ded0e94935131b392b28218315a185f63bf5e3c1a9a9dd470944509ca0ba8f6122265f8da851b5cc2abce68f1", "0xb28468e9b04ee9d69003399a3cf4457c9bf9d59f36ab6ceeb8e964672433d06b58beeea198fedc7edbaa1948577e9fa2", "0xa633005e2c9f2fd94c8bce2dd5bb708fe946b25f1ec561ae65e54e15cdd88dc339f1a083e01f0d39610c8fe24151aaf0", "0x841d0031e22723f9328dd993805abd13e0c99b0f59435d2426246996b08d00ce73ab906f66c4eab423473b409e972ce0", "0x85758d1b084263992070ec8943f33073a2d9b86a8606672550c17545507a5b3c88d87382b41916a87ee96ff55a7aa535", "0x8581b06b0fc41466ef94a76a1d9fb8ae0edca6d018063acf6a8ca5f4b02d76021902feba58972415691b4bdbc33ae3b4", "0x83539597ff5e327357ee62bc6bf8c0bcaec2f227c55c7c385a4806f0d37fb461f1690bad5066b8a5370950af32fafbef", "0xaee3557290d2dc10827e4791d00e0259006911f3f3fce4179ed3c514b779160613eca70f720bff7804752715a1266ffa", "0xb48d2f0c4e90fc307d5995464e3f611a9b0ef5fe426a289071f4168ed5cc4f8770c9332960c2ca5c8c427f40e6bb389f", "0x847af8973b4e300bb06be69b71b96183fd1a0b9d51b91701bef6fcfde465068f1eb2b1503b07afda380f18d69de5c9e1", "0xa70a6a80ce407f07804c0051ac21dc24d794b387be94eb24e1db94b58a78e1bcfb48cd0006db8fc1f9bedaece7a44fbe", "0xb40e942b8fa5336910ff0098347df716bff9d1fa236a1950c16eeb966b3bc1a50b8f7b0980469d42e75ae13ced53cead", "0xb208fabaa742d7db3148515330eb7a3577487845abdb7bd9ed169d0e081db0a5816595c33d375e56aeac5b51e60e49d3", "0xb7c8194b30d3d6ef5ab66ec88ad7ebbc732a3b8a41731b153e6f63759a93f3f4a537eab9ad369705bd730184bdbbdc34", "0x9280096445fe7394d04aa1bc4620c8f9296e991cc4d6c131bd703cb1cc317510e6e5855ac763f4d958c5edfe7eebeed7", "0xabc2aa4616a521400af1a12440dc544e3c821313d0ab936c86af28468ef8bbe534837e364598396a81cf8d06274ed5a6", "0xb18ca8a3325adb0c8c18a666d4859535397a1c3fe08f95eebfac916a7a99bbd40b3c37b919e8a8ae91da38bc00fa56c0", "0x8a40c33109ecea2a8b3558565877082f79121a432c45ec2c5a5e0ec4d1c203a6788e6b69cb37f1fd5b8c9a661bc5476d", "0x88c47301dd30998e903c84e0b0f2c9af2e1ce6b9f187dab03528d44f834dc991e4c86d0c474a2c63468cf4020a1e24a0", "0x920c832853e6ab4c851eecfa9c11d3acc7da37c823be7aa1ab15e14dfd8beb5d0b91d62a30cec94763bd8e4594b66600", "0x98e1addbe2a6b8edc7f12ecb9be81c3250aeeca54a1c6a7225772ca66549827c15f3950d01b8eb44aecb56fe0fff901a", "0x8cfb0fa1068be0ec088402f5950c4679a2eb9218c729da67050b0d1b2d7079f3ddf4bf0f57d95fe2a8db04bc6bcdb20c", "0xb70f381aafe336b024120453813aeab70baac85b9c4c0f86918797b6aee206e6ed93244a49950f3d8ec9f81f4ac15808", "0xa4c8edf4aa33b709a91e1062939512419711c1757084e46f8f4b7ed64f8e682f4e78b7135920c12f0eb0422fe9f87a6a", "0xb4817e85fd0752d7ebb662d3a51a03367a84bac74ebddfba0e5af5e636a979500f72b148052d333b3dedf9edd2b4031b", "0xa87430169c6195f5d3e314ff2d1c2f050e766fd5d2de88f5207d72dba4a7745bb86d0baca6e9ae156582d0d89e5838c7", "0x991b00f8b104566b63a12af4826b61ce7aa40f4e5b8fff3085e7a99815bdb4471b6214da1e480214fac83f86a0b93cc5", "0xb39966e3076482079de0678477df98578377a094054960ee518ef99504d6851f8bcd3203e8da5e1d4f6f96776e1fe6eb", "0xa448846d9dc2ab7a0995fa44b8527e27f6b3b74c6e03e95edb64e6baa4f1b866103f0addb97c84bef1d72487b2e21796", "0x894bec21a453ae84b592286e696c35bc30e820e9c2fd3e63dd4fbe629e07df16439c891056070faa490155f255bf7187", "0xa9ec652a491b11f6a692064e955f3f3287e7d2764527e58938571469a1e29b5225b9415bd602a45074dfbfe9c131d6ca", "0xb39d37822e6cbe28244b5f42ce467c65a23765bd16eb6447c5b3e942278069793763483dafd8c4dd864f8917aad357fe", "0x88dba51133f2019cb266641c56101e3e5987d3b77647a2e608b5ff9113dfc5f85e2b7c365118723131fbc0c9ca833c9c", "0xb566579d904b54ecf798018efcb824dccbebfc6753a0fd2128ac3b4bd3b038c2284a7c782b5ca6f310eb7ea4d26a3f0a", "0xa97a55c0a492e53c047e7d6f9d5f3e86fb96f3dddc68389c0561515343b66b4bc02a9c0d5722dff1e3445308240b27f7", "0xa044028ab4bcb9e1a2b9b4ca4efbf04c5da9e4bf2fff0e8bd57aa1fc12a71e897999c25d9117413faf2f45395dee0f13", "0xa78dc461decbeaeed8ebd0909369b491a5e764d6a5645a7dac61d3140d7dc0062526f777b0eb866bff27608429ebbdde", "0xb2c2a8991f94c39ca35fea59f01a92cb3393e0eccb2476dfbf57261d406a68bd34a6cff33ed80209991688c183609ef4", "0x84189eefb521aff730a4fd3fd5b10ddfd29f0d365664caef63bb015d07e689989e54c33c2141dd64427805d37a7e546e", "0x85ac80bd734a52235da288ff042dea9a62e085928954e8eacd2c751013f61904ed110e5b3afe1ab770a7e6485efb7b5e", "0x9183a560393dcb22d0d5063e71182020d0fbabb39e32493eeffeb808df084aa243eb397027f150b55a247d1ed0c8513e", "0x81c940944df7ecc58d3c43c34996852c3c7915ed185d7654627f7af62abae7e0048dd444a6c09961756455000bd96d09", "0xaa8c34e164019743fd8284b84f06c3b449aae7996e892f419ee55d82ad548cb300fd651de329da0384243954c0ef6a60", "0x89a7b7bdfc7e300d06a14d463e573d6296d8e66197491900cc9ae49504c4809ff6e61b758579e9091c61085ba1237b83", "0x878d21809ba540f50bd11f4c4d9590fb6f3ab9de5692606e6e2ef4ed9d18520119e385be5e1f4b3f2e2b09c319f0e8fc", "0x8eb248390193189cf0355365e630b782cd15751e672dc478b39d75dc681234dcd9309df0d11f4610dbb249c1e6be7ef9", "0xa1d7fb3aecb896df3a52d6bd0943838b13f1bd039c936d76d03de2044c371d48865694b6f532393b27fd10a4cf642061", "0xa34bca58a24979be442238cbb5ece5bee51ae8c0794dd3efb3983d4db713bc6f28a96e976ac3bd9a551d3ed9ba6b3e22", "0x817c608fc8cacdd178665320b5a7587ca21df8bdd761833c3018b967575d25e3951cf3d498a63619a3cd2ad4406f5f28", "0x86c95707db0495689afd0c2e39e97f445f7ca0edffad5c8b4cacd1421f2f3cc55049dfd504f728f91534e20383955582", "0x99c3b0bb15942c301137765d4e19502f65806f3b126dc01a5b7820c87e8979bce6a37289a8f6a4c1e4637227ad5bf3bf", "0x8aa1518a80ea8b074505a9b3f96829f5d4afa55a30efe7b4de4e5dbf666897fdd2cf31728ca45921e21a78a80f0e0f10", "0x8d74f46361c79e15128ac399e958a91067ef4cec8983408775a87eca1eed5b7dcbf0ddf30e66f51780457413496c7f07", "0xa41cde4a786b55387458a1db95171aca4fd146507b81c4da1e6d6e495527c3ec83fc42fad1dfe3d92744084a664fd431", "0x8c352852c906fae99413a84ad11701f93f292fbf7bd14738814f4c4ceab32db02feb5eb70bc73898b0bc724a39d5d017", "0xa5993046e8f23b71ba87b7caa7ace2d9023fb48ce4c51838813174880d918e9b4d2b0dc21a2b9c6f612338c31a289df8", "0x83576d3324bf2d8afbfb6eaecdc5d767c8e22e7d25160414924f0645491df60541948a05e1f4202e612368e78675de8a", "0xb43749b8df4b15bc9a3697e0f1c518e6b04114171739ef1a0c9c65185d8ec18e40e6954d125cbc14ebc652cf41ad3109", "0xb4eebd5d80a7327a040cafb9ccdb12b2dfe1aa86e6bc6d3ac8a57fadfb95a5b1a7332c66318ff72ba459f525668af056", "0x9198be7f1d413c5029b0e1c617bcbc082d21abe2c60ec8ce9b54ca1a85d3dba637b72fda39dae0c0ae40d047eab9f55a", "0x8d96a0232832e24d45092653e781e7a9c9520766c3989e67bbe86b3a820c4bf621ea911e7cd5270a4bfea78b618411f6", "0x8d7160d0ea98161a2d14d46ef01dff72d566c330cd4fabd27654d300e1bc7644c68dc8eabf2a20a59bfe7ba276545f9b", "0xabb60fce29dec7ba37e3056e412e0ec3e05538a1fc0e2c68877378c867605966108bc5742585ab6a405ce0c962b285b6", "0x8fabffa3ed792f05e414f5839386f6449fd9f7b41a47595c5d71074bd1bb3784cc7a1a7e1ad6b041b455035957e5b2dc", "0x90ff017b4804c2d0533b72461436b10603ab13a55f86fd4ec11b06a70ef8166f958c110519ca1b4cc7beba440729fe2d", "0xb340cfd120f6a4623e3a74cf8c32bfd7cd61a280b59dfd17b15ca8fae4d82f64a6f15fbde4c02f424debc72b7db5fe67", "0x871311c9c7220c932e738d59f0ecc67a34356d1429fe570ca503d340c9996cb5ee2cd188fad0e3bd16e4c468ec1dbebd", "0xa772470262186e7b94239ba921b29f2412c148d6f97c4412e96d21e55f3be73f992f1ad53c71008f0558ec3f84e2b5a7", "0xb2a897dcb7ffd6257f3f2947ec966f2077d57d5191a88840b1d4f67effebe8c436641be85524d0a21be734c63ab5965d", "0xa044f6eacc48a4a061fa149500d96b48cbf14853469aa4d045faf3dca973be1bd4b4ce01646d83e2f24f7c486d03205d", "0x981af5dc2daa73f7fa9eae35a93d81eb6edba4a7f673b55d41f6ecd87a37685d31bb40ef4f1c469b3d72f2f18b925a17", "0x912d2597a07864de9020ac77083eff2f15ceb07600f15755aba61251e8ce3c905a758453b417f04d9c38db040954eb65", "0x9642b7f6f09394ba5e0805734ef6702c3eddf9eea187ba98c676d5bbaec0e360e3e51dc58433aaa1e2da6060c8659cb7", "0x8ab3836e0a8ac492d5e707d056310c4c8e0489ca85eb771bff35ba1d658360084e836a6f51bb990f9e3d2d9aeb18fbb5", "0x879e058e72b73bb1f4642c21ffdb90544b846868139c6511f299aafe59c2d0f0b944dffc7990491b7c4edcd6a9889250", "0xb9e60b737023f61479a4a8fd253ed0d2a944ea6ba0439bbc0a0d3abf09b0ad1f18d75555e4a50405470ae4990626f390", "0xb9c2535d362796dcd673640a9fa2ebdaec274e6f8b850b023153b0a7a30fffc87f96e0b72696f647ebe7ab63099a6963", "0x94aeff145386a087b0e91e68a84a5ede01f978f9dd9fe7bebca78941938469495dc30a96bba9508c0d017873aeea9610", "0x98b179f8a3d9f0d0a983c30682dd425a2ddc7803be59bd626c623c8951a5179117d1d2a68254c95c9952989877d0ee55", "0x889ecf5f0ee56938273f74eb3e9ecfb5617f04fb58e83fe4c0e4aef51615cf345bc56f3f61b17f6eed3249d4afd54451", "0xa0f2b2c39bcea4b50883e2587d16559e246248a66ecb4a4b7d9ab3b51fb39fe98d83765e087eee37a0f86b0ba4144c02", "0xb2a61e247ed595e8a3830f7973b07079cbda510f28ad8c78c220b26cb6acde4fbb5ee90c14a665f329168ee951b08cf0", "0x95bd0fcfb42f0d6d8a8e73d7458498a85bcddd2fb132fd7989265648d82ac2707d6d203fac045504977af4f0a2aca4b7", "0x843e5a537c298666e6cf50fcc044f13506499ef83c802e719ff2c90e85003c132024e04711be7234c04d4b0125512d5d", "0xa46d1797c5959dcd3a5cfc857488f4d96f74277c3d13b98b133620192f79944abcb3a361d939a100187f1b0856eae875", "0xa1c7786736d6707a48515c38660615fcec67eb8a2598f46657855215f804fd72ab122d17f94fcffad8893f3be658dca7", "0xb23dc9e610abc7d8bd21d147e22509a0fa49db5be6ea7057b51aae38e31654b3aa044df05b94b718153361371ba2f622", "0xb00cc8f257d659c22d30e6d641f79166b1e752ea8606f558e4cad6fc01532e8319ea4ee12265ba4140ac45aa4613c004", "0xac7019af65221b0cc736287b32d7f1a3561405715ba9a6a122342e04e51637ba911c41573de53e4781f2230fdcb2475f", "0x81a630bc41b3da8b3eb4bf56cba10cd9f93153c3667f009dc332287baeb707d505fb537e6233c8e53d299ec0f013290c", "0xa6b7aea5c545bb76df0f230548539db92bc26642572cb7dd3d5a30edca2b4c386f44fc8466f056b42de2a452b81aff5b", "0x8271624ff736b7b238e43943c81de80a1612207d32036d820c11fc830c737972ccc9c60d3c2359922b06652311e3c994", "0x8a684106458cb6f4db478170b9ad595d4b54c18bf63b9058f095a2fa1b928c15101472c70c648873d5887880059ed402", "0xa5cc3c35228122f410184e4326cf61a37637206e589fcd245cb5d0cec91031f8f7586b80503070840fdfd8ce75d3c88b", "0x9443fc631aed8866a7ed220890911057a1f56b0afe0ba15f0a0e295ab97f604b134b1ed9a4245e46ee5f9a93aa74f731", "0x984b6f7d79835dffde9558c6bb912d992ca1180a2361757bdba4a7b69dc74b056e303adc69fe67414495dd9c2dd91e64", "0xb15a5c8cba5de080224c274d31c68ed72d2a7126d347796569aef0c4e97ed084afe3da4d4b590b9dda1a07f0c2ff3dfb", "0x991708fe9650a1f9a4e43938b91d45dc68c230e05ee999c95dbff3bf79b1c1b2bb0e7977de454237c355a73b8438b1d9", "0xb4f7edc7468b176a4a7c0273700c444fa95c726af6697028bed4f77eee887e3400f9c42ee15b782c0ca861c4c3b8c98a", "0x8c60dcc16c51087eb477c13e837031d6c6a3dc2b8bf8cb43c23f48006bc7173151807e866ead2234b460c2de93b31956", "0x83ad63e9c910d1fc44bc114accfb0d4d333b7ebe032f73f62d25d3e172c029d5e34a1c9d547273bf6c0fead5c8801007", "0x85de73213cc236f00777560756bdbf2b16841ba4b55902cf2cad9742ecaf5d28209b012ceb41f337456dfeca93010cd7", "0xa7561f8827ccd75b6686ba5398bb8fc3083351c55a589b18984e186820af7e275af04bcd4c28e1dc11be1e8617a0610b", "0x88c0a4febd4068850557f497ea888035c7fc9f404f6cc7794e7cc8722f048ad2f249e7dc62743e7a339eb7473ad3b0cd", "0x932b22b1d3e6d5a6409c34980d176feb85ada1bf94332ef5c9fc4d42b907dabea608ceef9b5595ef3feee195151f18d8", "0xa2867bb3f5ab88fbdae3a16c9143ab8a8f4f476a2643c505bb9f37e5b1fd34d216cab2204c9a017a5a67b7ad2dda10e8", "0xb573d5f38e4e9e8a3a6fd82f0880dc049efa492a946d00283019bf1d5e5516464cf87039e80aef667cb86fdea5075904", "0xb948f1b5ab755f3f5f36af27d94f503b070696d793b1240c1bdfd2e8e56890d69e6904688b5f8ff5a4bdf5a6abfe195f", "0x917eae95ebc4109a2e99ddd8fec7881d2f7aaa0e25fda44dec7ce37458c2ee832f1829db7d2dcfa4ca0f06381c7fe91d", "0x95751d17ed00a3030bce909333799bb7f4ab641acf585807f355b51d6976dceee410798026a1a004ef4dcdff7ec0f5b8", "0xb9b7bd266f449a79bbfe075e429613e76c5a42ac61f01c8f0bbbd34669650682efe01ff9dbbc400a1e995616af6aa278", "0xac1722d097ce9cd7617161f8ec8c23d68f1fb1c9ca533e2a8b4f78516c2fd8fb38f23f834e2b9a03bb06a9d655693ca9", "0xa7ad9e96ffd98db2ecdb6340c5d592614f3c159abfd832fe27ee9293519d213a578e6246aae51672ee353e3296858873", "0x989b8814d5de7937c4acafd000eec2b4cd58ba395d7b25f98cafd021e8efa37029b29ad8303a1f6867923f5852a220eb", "0xa5bfe6282c771bc9e453e964042d44eff4098decacb89aecd3be662ea5b74506e1357ab26f3527110ba377711f3c9f41", "0x8900a7470b656639721d2abbb7b06af0ac4222ab85a1976386e2a62eb4b88bfb5b72cf7921ddb3cf3a395d7eeb192a2e", "0x95a71b55cd1f35a438cf5e75f8ff11c5ec6a2ebf2e4dba172f50bfad7d6d5dca5de1b1afc541662c81c858f7604c1163", "0x82b5d62fea8db8d85c5bc3a76d68dedd25794cf14d4a7bc368938ffca9e09f7e598fdad2a5aac614e0e52f8112ae62b9", "0x997173f07c729202afcde3028fa7f52cefc90fda2d0c8ac2b58154a5073140683e54c49ed1f254481070d119ce0ce02a", "0xaeffb91ccc7a72bbd6ffe0f9b99c9e66e67d59cec2e02440465e9636a613ab3017278cfa72ea8bc4aba9a8dc728cb367", "0x952743b06e8645894aeb6440fc7a5f62dd3acf96dab70a51e20176762c9751ea5f2ba0b9497ccf0114dc4892dc606031", "0x874c63baeddc56fbbca2ff6031f8634b745f6e34ea6791d7c439201aee8f08ef5ee75f7778700a647f3b21068513fce6", "0x85128fec9c750c1071edfb15586435cc2f317e3e9a175bb8a9697bcda1eb9375478cf25d01e7fed113483b28f625122d", "0x85522c9576fd9763e32af8495ae3928ed7116fb70d4378448926bc9790e8a8d08f98cf47648d7da1b6e40d6a210c7924", "0x97d0f37a13cfb723b848099ca1c14d83e9aaf2f7aeb71829180e664b7968632a08f6a85f557d74b55afe6242f2a36e7c", "0xabaa472d6ad61a5fccd1a57c01aa1bc081253f95abbcba7f73923f1f11c4e79b904263890eeb66926de3e2652f5d1c70", "0xb3c04945ba727a141e5e8aec2bf9aa3772b64d8fd0e2a2b07f3a91106a95cbcb249adcd074cbe498caf76fffac20d4ef", "0x82c46781a3d730d9931bcabd7434a9171372dde57171b6180e5516d4e68db8b23495c8ac3ab96994c17ddb1cf249b9fb", "0xa202d8b65613c42d01738ccd68ed8c2dbc021631f602d53f751966e04182743ebc8e0747d600b8a8676b1da9ae7f11ab", "0xae73e7256e9459db04667a899e0d3ea5255211fb486d084e6550b6dd64ca44af6c6b2d59d7aa152de9f96ce9b58d940d", "0xb67d87b176a9722945ec7593777ee461809861c6cfd1b945dde9ee4ff009ca4f19cf88f4bbb5c80c9cbab2fe25b23ac8", "0x8f0b7a317a076758b0dac79959ee4a06c08b07d0f10538a4b53d3da2eda16e2af26922feb32c090330dc4d969cf69bd3", "0x90b36bf56adbd8c4b6cb32febc3a8d5f714370c2ac3305c10fa6d168dffb2a026804517215f9a2d4ec8310cdb6bb459b", "0xaa80c19b0682ead69934bf18cf476291a0beddd8ef4ed75975d0a472e2ab5c70f119722a8574ae4973aceb733d312e57", "0xa3fc9abb12574e5c28dcb51750b4339b794b8e558675eef7d26126edf1de920c35e992333bcbffcbf6a5f5c0d383ce62", "0xa1573ff23ab972acdcd08818853b111fc757fdd35aa070186d3e11e56b172fb49d840bf297ac0dd222e072fc09f26a81", "0x98306f2be4caa92c2b4392212d0cbf430b409b19ff7d5b899986613bd0e762c909fc01999aa94be3bd529d67f0113d7f", "0x8c1fc42482a0819074241746d17dc89c0304a2acdae8ed91b5009e9e3e70ff725ba063b4a3e68fdce05b74f5180c545e", "0xa6c6113ebf72d8cf3163b2b8d7f3fa24303b13f55752522c660a98cd834d85d8c79214d900fa649499365e2e7641f77a", "0xab95eea424f8a2cfd9fb1c78bb724e5b1d71a0d0d1e4217c5d0f98b0d8bbd3f8400a2002abc0a0e4576d1f93f46fefad", "0x823c5a4fd8cf4a75fdc71d5f2dd511b6c0f189b82affeacd2b7cfcad8ad1a5551227dcc9bfdb2e34b2097eaa00efbb51", "0xb97314dfff36d80c46b53d87a61b0e124dc94018a0bb680c32765b9a2d457f833a7c42bbc90b3b1520c33a182580398d", "0xb17566ee3dcc6bb3b004afe4c0136dfe7dd27df9045ae896dca49fb36987501ae069eb745af81ba3fc19ff037e7b1406", "0xb0bdc0f55cfd98d331e3a0c4fbb776a131936c3c47c6bffdc3aaf7d8c9fa6803fbc122c2fefbb532e634228687d52174", "0xaa5d9e60cc9f0598559c28bb9bdd52aa46605ab4ffe3d192ba982398e72cec9a2a44c0d0d938ce69935693cabc0887ea", "0x802b6459d2354fa1d56c592ac1346c428dadea6b6c0a87bf7d309bab55c94e1cf31dd98a7a86bd92a840dd51f218b91b", "0xa526914efdc190381bf1a73dd33f392ecf01350b9d3f4ae96b1b1c3d1d064721c7d6eec5788162c933245a3943f5ee51", "0xb3b8fcf637d8d6628620a1a99dbe619eabb3e5c7ce930d6efd2197e261bf394b74d4e5c26b96c4b8009c7e523ccfd082", "0x8f7510c732502a93e095aba744535f3928f893f188adc5b16008385fb9e80f695d0435bfc5b91cdad4537e87e9d2551c", "0x97b90beaa56aa936c3ca45698f79273a68dd3ccd0076eab48d2a4db01782665e63f33c25751c1f2e070f4d1a8525bf96", "0xb9fb798324b1d1283fdc3e48288e3861a5449b2ab5e884b34ebb8f740225324af86e4711da6b5cc8361c1db15466602f", "0xb6d52b53cea98f1d1d4c9a759c25bf9d8a50b604b144e4912acbdbdc32aab8b9dbb10d64a29aa33a4f502121a6fb481c", "0x9174ffff0f2930fc228f0e539f5cfd82c9368d26b074467f39c07a774367ff6cccb5039ac63f107677d77706cd431680", "0xa33b6250d4ac9e66ec51c063d1a6a31f253eb29bbaed12a0d67e2eccfffb0f3a52750fbf52a1c2aaba8c7692346426e7", "0xa97025fd5cbcebe8ef865afc39cd3ea707b89d4e765ec817fd021d6438e02fa51e3544b1fd45470c58007a08efac6edd", "0xb32a78480edd9ff6ba2f1eec4088db5d6ceb2d62d7e59e904ecaef7bb4a2e983a4588e51692b3be76e6ffbc0b5f911a5", "0xb5ab590ef0bb77191f00495b33d11c53c65a819f7d0c1f9dc4a2caa147a69c77a4fff7366a602d743ee1f395ce934c1e", "0xb3fb0842f9441fb1d0ee0293b6efbc70a8f58d12d6f769b12872db726b19e16f0f65efbc891cf27a28a248b0ef9c7e75", "0x9372ad12856fefb928ccb0d34e198df99e2f8973b07e9d417a3134d5f69e12e79ff572c4e03ccd65415d70639bc7c73e", "0xaa8d6e83d09ce216bfe2009a6b07d0110d98cf305364d5529c170a23e693aabb768b2016befb5ada8dabdd92b4d012bb", "0xa954a75791eeb0ce41c85200c3763a508ed8214b5945a42c79bfdcfb1ec4f86ad1dd7b2862474a368d4ac31911a2b718", "0x8e2081cfd1d062fe3ab4dab01f68062bac802795545fede9a188f6c9f802cb5f884e60dbe866710baadbf55dc77c11a4", "0xa2f06003b9713e7dd5929501ed485436b49d43de80ea5b15170763fd6346badf8da6de8261828913ee0dacd8ff23c0e1", "0x98eecc34b838e6ffd1931ca65eec27bcdb2fdcb61f33e7e5673a93028c5865e0d1bf6d3bec040c5e96f9bd08089a53a4", "0x88cc16019741b341060b95498747db4377100d2a5bf0a5f516f7dec71b62bcb6e779de2c269c946d39040e03b3ae12b7", "0xad1135ccbc3019d5b2faf59a688eef2500697642be8cfbdf211a1ab59abcc1f24483e50d653b55ff1834675ac7b4978f", "0xa946f05ed9972f71dfde0020bbb086020fa35b482cce8a4cc36dd94355b2d10497d7f2580541bb3e81b71ac8bba3c49f", "0xa83aeed488f9a19d8cfd743aa9aa1982ab3723560b1cd337fc2f91ad82f07afa412b3993afb845f68d47e91ba4869840", "0x95eebe006bfc316810cb71da919e5d62c2cebb4ac99d8e8ef67be420302320465f8b69873470982de13a7c2e23516be9", "0xa55f8961295a11e91d1e5deadc0c06c15dacbfc67f04ccba1d069cba89d72aa3b3d64045579c3ea8991b150ac29366ae", "0xb321991d12f6ac07a5de3c492841d1a27b0d3446082fbce93e7e1f9e8d8fe3b45d41253556261c21b70f5e189e1a7a6f", "0xa0b0822f15f652ce7962a4f130104b97bf9529797c13d6bd8e24701c213cc37f18157bd07f3d0f3eae6b7cd1cb40401f", "0x96e2fa4da378aa782cc2d5e6e465fc9e49b5c805ed01d560e9b98abb5c0de8b74a2e7bec3aa5e2887d25cccb12c66f0c", "0x97e4ab610d414f9210ed6f35300285eb3ccff5b0b6a95ed33425100d7725e159708ea78704497624ca0a2dcabce3a2f9", "0x960a375b17bdb325761e01e88a3ea57026b2393e1d887b34b8fa5d2532928079ce88dc9fd06a728b26d2bb41b12b9032", "0x8328a1647398e832aadc05bd717487a2b6fcdaa0d4850d2c4da230c6a2ed44c3e78ec4837b6094f3813f1ee99414713f", "0xaa283834ebd18e6c99229ce4b401eda83f01d904f250fedd4e24f1006f8fa0712a6a89a7296a9bf2ce8de30e28d1408e", "0xb29e097f2caadae3e0f0ae3473c072b0cd0206cf6d2e9b22c1a5ad3e07d433e32bd09ed1f4e4276a2da4268633357b7f", "0x9539c5cbba14538b2fe077ecf67694ef240da5249950baaabea0340718b882a966f66d97f08556b08a4320ceb2cc2629", "0xb4529f25e9b42ae8cf8338d2eface6ba5cd4b4d8da73af502d081388135c654c0b3afb3aa779ffc80b8c4c8f4425dd2b", "0x95be0739c4330619fbe7ee2249c133c91d6c07eab846c18c5d6c85fc21ac5528c5d56dcb0145af68ed0c6a79f68f2ccd", "0xac0c83ea802227bfc23814a24655c9ff13f729619bcffdb487ccbbf029b8eaee709f8bddb98232ef33cd70e30e45ca47", "0xb503becb90acc93b1901e939059f93e671900ca52c6f64ae701d11ac891d3a050b505d89324ce267bc43ab8275da6ffe", "0x98e3811b55b1bacb70aa409100abb1b870f67e6d059475d9f278c751b6e1e2e2d6f2e586c81a9fb6597fda06e7923274", "0xb0b0f61a44053fa6c715dbb0731e35d48dba257d134f851ee1b81fd49a5c51a90ebf5459ec6e489fce25da4f184fbdb1", "0xb1d2117fe811720bb997c7c93fe9e4260dc50fca8881b245b5e34f724aaf37ed970cdad4e8fcb68e05ac8cf55a274a53", "0xa10f502051968f14b02895393271776dee7a06db9de14effa0b3471825ba94c3f805302bdddac4d397d08456f620999d", "0xa3dbad2ef060ae0bb7b02eaa4a13594f3f900450faa1854fc09620b01ac94ab896321dfb1157cf2374c27e5718e8026a", "0xb550fdec503195ecb9e079dcdf0cad559d64d3c30818ef369b4907e813e689da316a74ad2422e391b4a8c2a2bef25fc0", "0xa25ba865e2ac8f28186cea497294c8649a201732ecb4620c4e77b8e887403119910423df061117e5f03fc5ba39042db1", "0xb3f88174e03fdb443dd6addd01303cf88a4369352520187c739fc5ae6b22fa99629c63c985b4383219dab6acc5f6f532", "0x97a7503248e31e81b10eb621ba8f5210c537ad11b539c96dfb7cf72b846c7fe81bd7532c5136095652a9618000b7f8d3", "0xa8bcdc1ce5aa8bfa683a2fc65c1e79de8ff5446695dcb8620f7350c26d2972a23da22889f9e2b1cacb3f688c6a2953dc", "0x8458c111df2a37f5dd91a9bee6c6f4b79f4f161c93fe78075b24a35f9817da8dde71763218d627917a9f1f0c4709c1ed", "0xac5f061a0541152b876cbc10640f26f1cc923c9d4ae1b6621e4bb3bf2cec59bbf87363a4eb72fb0e5b6d4e1c269b52d5", "0xa9a25ca87006e8a9203cbb78a93f50a36694aa4aad468b8d80d3feff9194455ca559fcc63838128a0ab75ad78c07c13a", "0xa450b85f5dfffa8b34dfd8bc985f921318efacf8857cf7948f93884ba09fb831482ee90a44224b1a41e859e19b74962f", "0x8ed91e7f92f5c6d7a71708b6132f157ac226ecaf8662af7d7468a4fa25627302efe31e4620ad28719318923e3a59bf82", "0xab524165fd4c71b1fd395467a14272bd2b568592deafa039d8492e9ef36c6d3f96927c95c72d410a768dc0b6d1fbbc9b", "0xb662144505aa8432c75ffb8d10318526b6d5777ac7af9ebfad87d9b0866c364f7905a6352743bd8fd79ffd9d5dd4f3e6", "0xa48f1677550a5cd40663bb3ba8f84caaf8454f332d0ceb1d94dbea52d0412fe69c94997f7749929712fd3995298572f7", "0x8391cd6e2f6b0c242de1117a612be99776c3dc95cb800b187685ea5bf7e2722275eddb79fd7dfc8be8e389c4524cdf70", "0x875d3acb9af47833b72900bc0a2448999d638f153c5e97e8a14ec02d0c76f6264353a7e275e1f1a5855daced523d243b", "0x91f1823657d30b59b2f627880a9a9cb530f5aca28a9fd217fe6f2f5133690dfe7ad5a897872e400512db2e788b3f7628", "0xad3564332aa56cea84123fc7ca79ea70bb4fef2009fa131cb44e4b15e8613bd11ca1d83b9d9bf456e4b7fee9f2e8b017", "0x8c530b84001936d5ab366c84c0b105241a26d1fb163669f17c8f2e94776895c2870edf3e1bc8ccd04d5e65531471f695", "0x932d01fa174fdb0c366f1230cffde2571cc47485f37f23ba5a1825532190cc3b722aeb1f15aed62cf83ccae9403ba713", "0x88b28c20585aca50d10752e84b901b5c2d58efef5131479fbbe53de7bce2029e1423a494c0298e1497669bd55be97a5d", "0xb914148ca717721144ebb3d3bf3fcea2cd44c30c5f7051b89d8001502f3856fef30ec167174d5b76265b55d70f8716b5", "0x81d0173821c6ddd2a068d70766d9103d1ee961c475156e0cbd67d54e668a796310474ef698c7ab55abe6f2cf76c14679", "0x8f28e8d78e2fe7fa66340c53718e0db4b84823c8cfb159c76eac032a62fb53da0a5d7e24ca656cf9d2a890cb2a216542", "0x8a26360335c73d1ab51cec3166c3cf23b9ea51e44a0ad631b0b0329ef55aaae555420348a544e18d5760969281759b61", "0x94f326a32ed287545b0515be9e08149eb0a565025074796d72387cc3a237e87979776410d78339e23ef3172ca43b2544", "0xa785d2961a2fa5e70bffa137858a92c48fe749fee91b02599a252b0cd50d311991a08efd7fa5e96b78d07e6e66ffe746", "0x94af9030b5ac792dd1ce517eaadcec1482206848bea4e09e55cc7f40fd64d4c2b3e9197027c5636b70d6122c51d2235d", "0x9722869f7d1a3992850fe7be405ec93aa17dc4d35e9e257d2e469f46d2c5a59dbd504056c85ab83d541ad8c13e8bcd54", "0xb13c4088b61a06e2c03ac9813a75ff1f68ffdfee9df6a8f65095179a475e29cc49119cad2ce05862c3b1ac217f3aace9", "0x8c64d51774753623666b10ca1b0fe63ae42f82ed6aa26b81dc1d48c86937c5772eb1402624c52a154b86031854e1fb9f", "0xb47e4df18002b7dac3fee945bf9c0503159e1b8aafcce2138818e140753011b6d09ef1b20894e08ba3006b093559061b", "0x93cb5970076522c5a0483693f6a35ffd4ea2aa7aaf3730c4eccd6af6d1bebfc1122fc4c67d53898ae13eb6db647be7e2", "0xa68873ef80986795ea5ed1a597d1cd99ed978ec25e0abb57fdcc96e89ef0f50aeb779ff46e3dce21dc83ada3157a8498", "0x8cab67f50949cc8eee6710e27358aea373aae3c92849f8f0b5531c080a6300cdf2c2094fe6fecfef6148de0d28446919", "0x993e932bcb616dbaa7ad18a4439e0565211d31071ef1b85a0627db74a05d978c60d507695eaeea5c7bd9868a21d06923", "0xacdadff26e3132d9478a818ef770e9fa0d2b56c6f5f48bd3bd674436ccce9bdfc34db884a73a30c04c5f5e9764cb2218", "0xa0d3e64c9c71f84c0eef9d7a9cb4fa184224b969db5514d678e93e00f98b41595588ca802643ea225512a4a272f5f534", "0x91c9140c9e1ba6e330cb08f6b2ce4809cd0d5a0f0516f70032bf30e912b0ed684d07b413b326ab531ee7e5b4668c799b", "0x87bc2ee7a0c21ba8334cd098e35cb703f9af57f35e091b8151b9b63c3a5b0f89bd7701dbd44f644ea475901fa6d9ef08", "0x9325ccbf64bf5d71b303e31ee85d486298f9802c5e55b2c3d75427097bf8f60fa2ab4fcaffa9b60bf922c3e24fbd4b19", "0x95d0506e898318f3dc8d28d16dfd9f0038b54798838b3c9be2a2ae3c2bf204eb496166353fc042220b0bd4f6673b9285", "0x811de529416331fe9c416726d45df9434c29dcd7e949045eb15740f47e97dde8f31489242200e19922cac2a8b7c6fd1f", "0xade632d04a4c8bbab6ca7df370b2213cb9225023e7973f0e29f4f5e52e8aeaabc65171306bbdd12a67b195dfbb96d48f", "0x88b7f029e079b6ae956042c0ea75d53088c5d0efd750dd018adaeacf46be21bf990897c58578c491f41afd3978d08073", "0x91f477802de507ffd2be3f4319903119225b277ad24f74eb50f28b66c14d32fae53c7edb8c7590704741af7f7f3e3654", "0x809838b32bb4f4d0237e98108320d4b079ee16ed80c567e7548bd37e4d7915b1192880f4812ac0e00476d246aec1dbc8", "0x84183b5fc4a7997a8ae5afedb4d21dce69c480d5966b5cbdafd6dd10d29a9a6377f3b90ce44da0eb8b176ac3af0253bb", "0x8508abbf6d3739a16b9165caf0f95afb3b3ac1b8c38d6d374cf0c91296e2c1809a99772492b539cda184510bce8a0271", "0x8722054e59bab2062e6419a6e45fc803af77fde912ef2cd23055ad0484963de65a816a2debe1693d93c18218d2b8e81a", "0x8e895f80e485a7c4f56827bf53d34b956281cdc74856c21eb3b51f6288c01cc3d08565a11cc6f3e2604775885490e8c5", "0xafc92714771b7aa6e60f3aee12efd9c2595e9659797452f0c1e99519f67c8bc3ac567119c1ddfe82a3e961ee9defea9a", "0x818ff0fd9cefd32db87b259e5fa32967201016fc02ef44116cdca3c63ce5e637756f60477a408709928444a8ad69c471", "0x8251e29af4c61ae806fc5d032347fb332a94d472038149225298389495139ce5678fae739d02dfe53a231598a992e728", "0xa0ea39574b26643f6f1f48f99f276a8a64b5481989cfb2936f9432a3f8ef5075abfe5c067dc5512143ce8bf933984097", "0xaf67a73911b372bf04e57e21f289fc6c3dfac366c6a01409b6e76fea4769bdb07a6940e52e8d7d3078f235c6d2f632c6", "0xb5291484ef336024dd2b9b4cf4d3a6b751133a40656d0a0825bcc6d41c21b1c79cb50b0e8f4693f90c29c8f4358641f9", "0x8bc0d9754d70f2cb9c63f991902165a87c6535a763d5eece43143b5064ae0bcdce7c7a8f398f2c1c29167b2d5a3e6867", "0x8d7faff53579ec8f6c92f661c399614cc35276971752ce0623270f88be937c414eddcb0997e14724a783905a026c8883", "0x9310b5f6e675fdf60796f814dbaa5a6e7e9029a61c395761e330d9348a7efab992e4e115c8be3a43d08e90d21290c892", "0xb5eb4f3eb646038ad2a020f0a42202532d4932e766da82b2c1002bf9c9c2e5336b54c8c0ffcc0e02d19dde2e6a35b6cc", "0x91dabfd30a66710f1f37a891136c9be1e23af4abf8cb751f512a40c022a35f8e0a4fb05b17ec36d4208de02d56f0d53a", "0xb3ded14e82d62ac7a5a036122a62f00ff8308498f3feae57d861babaff5a6628d43f0a0c5fc903f10936bcf4e2758ceb", "0xa88e8348fed2b26acca6784d19ef27c75963450d99651d11a950ea81d4b93acd2c43e0ecce100eaf7e78508263d5baf3", "0xb1f5bbf7c4756877b87bb42163ac570e08c6667c4528bf68b5976680e19beeff7c5effd17009b0718797077e2955457a", "0xad2e7b516243f915d4d1415326e98b1a7390ae88897d0b03b66c2d9bd8c3fba283d7e8fe44ed3333296a736454cef6d8", "0x8f82eae096d5b11f995de6724a9af895f5e1c58d593845ad16ce8fcae8507e0d8e2b2348a0f50a1f66a17fd6fac51a5c", "0x890e4404d0657c6c1ee14e1aac132ecf7a568bb3e04137b85ac0f84f1d333bd94993e8750f88eee033a33fb00f85dcc7", "0x82ac7d3385e035115f1d39a99fc73e5919de44f5e6424579776d118d711c8120b8e5916372c6f27bed4cc64cac170b6c", "0x85ee16d8901c272cfbbe966e724b7a891c1bd5e68efd5d863043ad8520fc409080af61fd726adc680b3f1186fe0ac8b8", "0x86dc564c9b545567483b43a38f24c41c6551a49cabeebb58ce86404662a12dbfafd0778d30d26e1c93ce222e547e3898", "0xa29f5b4522db26d88f5f95f18d459f8feefab02e380c2edb65aa0617a82a3c1a89474727a951cef5f15050bcf7b380fb", "0xa1ce039c8f6cac53352899edb0e3a72c76da143564ad1a44858bd7ee88552e2fe6858d1593bbd74aeee5a6f8034b9b9d", "0x97f10d77983f088286bd7ef3e7fdd8fa275a56bec19919adf33cf939a90c8f2967d2b1b6fc51195cb45ad561202a3ed7", "0xa25e2772e8c911aaf8712bdac1dd40ee061c84d3d224c466cfaae8e5c99604053f940cde259bd1c3b8b69595781dbfec", "0xb31bb95a0388595149409c48781174c340960d59032ab2b47689911d03c68f77a2273576fbe0c2bf4553e330656058c7", "0xb8b2e9287ad803fb185a13f0d7456b397d4e3c8ad5078f57f49e8beb2e85f661356a3392dbd7bcf6a900baa5582b86a1", "0xa3d0893923455eb6e96cc414341cac33d2dbc88fba821ac672708cce131761d85a0e08286663a32828244febfcae6451", "0x82310cb42f647d99a136014a9f881eb0b9791efd2e01fc1841907ad3fc8a9654d3d1dab6689c3607214b4dc2aca01cee", "0x874022d99c16f60c22de1b094532a0bc6d4de700ad01a31798fac1d5088b9a42ad02bef8a7339af7ed9c0d4f16b186ee", "0x94981369e120265aed40910eebc37eded481e90f4596b8d57c3bec790ab7f929784bd33ddd05b7870aad6c02e869603b", "0xa4f1f50e1e2a73f07095e0dd31cb45154f24968dae967e38962341c1241bcd473102fff1ff668b20c6547e9732d11701", "0xae2328f3b0ad79fcda807e69a1b5278145225083f150f67511dafc97e079f860c3392675f1752ae7e864c056e592205b", "0x875d8c971e593ca79552c43d55c8c73b17cd20c81ff2c2fed1eb19b1b91e4a3a83d32df150dbfd5db1092d0aebde1e1f", "0xadd2e80aa46aae95da73a11f130f4bda339db028e24c9b11e5316e75ba5e63bc991d2a1da172c7c8e8fee038baae3433", "0xb46dbe1cb3424002aa7de51e82f600852248e251465c440695d52538d3f36828ff46c90ed77fc1d11534fe3c487df8ef", "0xa5e5045d28b4e83d0055863c30c056628c58d4657e6176fd0536f5933f723d60e851bb726d5bf3c546b8ce4ac4a57ef8", "0x91fec01e86dd1537e498fff7536ea3ca012058b145f29d9ada49370cd7b7193ac380e116989515df1b94b74a55c45df3", "0xa7428176d6918cd916a310bdc75483c72de660df48cac4e6e7478eef03205f1827ea55afc0df5d5fa7567d14bbea7fc9", "0x851d89bef45d9761fe5fdb62972209335193610015e16a675149519f9911373bac0919add226ef118d9f3669cfdf4734", "0xb74acf5c149d0042021cb2422ea022be4c4f72a77855f42393e71ffd12ebb3eec16bdf16f812159b67b79a9706e7156d", "0x99f35dce64ec99aa595e7894b55ce7b5a435851b396e79036ffb249c28206087db4c85379df666c4d95857db02e21ff9", "0xb6b9a384f70db9e298415b8ab394ee625dafff04be2886476e59df8d052ca832d11ac68a9b93fba7ab055b7bc36948a4", "0x898ee4aefa923ffec9e79f2219c7389663eb11eb5b49014e04ed4a336399f6ea1691051d86991f4c46ca65bcd4fdf359", "0xb0f948217b0d65df7599a0ba4654a5e43c84db477936276e6f11c8981efc6eaf14c90d3650107ed4c09af4cc8ec11137", "0xaa6286e27ac54f73e63dbf6f41865dd94d24bc0cf732262fcaff67319d162bb43af909f6f8ee27b1971939cfbba08141", "0x8bca7cdf730cf56c7b2c8a2c4879d61361a6e1dba5a3681a1a16c17a56e168ace0e99cf0d15826a1f5e67e6b8a8a049a", "0xa746d876e8b1ce225fcafca603b099b36504846961526589af977a88c60d31ba2cc56e66a3dec8a77b3f3531bf7524c9", "0xa11e2e1927e6704cdb8874c75e4f1842cef84d7d43d7a38e339e61dc8ba90e61bbb20dd3c12e0b11d2471d58eed245be", "0xa36395e22bc1d1ba8b0459a235203177737397da5643ce54ded3459d0869ff6d8d89f50c73cb62394bf66a959cde9b90", "0x8b49f12ba2fdf9aca7e5f81d45c07d47f9302a2655610e7634d1e4bd16048381a45ef2c95a8dd5b0715e4b7cf42273af", "0x91cffa2a17e64eb7f76bccbe4e87280ee1dd244e04a3c9eac12e15d2d04845d876eb24fe2ec6d6d266cce9efb281077f", "0xa6b8afabf65f2dee01788114e33a2f3ce25376fb47a50b74da7c3c25ff1fdc8aa9f41307534abbf48acb6f7466068f69", "0x8d13db896ccfea403bd6441191995c1a65365cab7d0b97fbe9526da3f45a877bd1f4ef2edef160e8a56838cd1586330e", "0x98c717de9e01bef8842c162a5e757fe8552d53269c84862f4d451e7c656ae6f2ae473767b04290b134773f63be6fdb9d", "0x8c2036ace1920bd13cf018e82848c49eb511fad65fd0ff51f4e4b50cf3bfc294afb63cba682c16f52fb595a98fa84970", "0xa3520fdff05dbad9e12551b0896922e375f9e5589368bcb2cc303bde252743b74460cb5caf99629325d3620f13adc796", "0x8d4f83a5bfec05caf5910e0ce538ee9816ee18d0bd44c1d0da2a87715a23cd2733ad4d47552c6dc0eb397687d611dd19", "0xa7b39a0a6a02823452d376533f39d35029867b3c9a6ad6bca181f18c54132d675613a700f9db2440fb1b4fa13c8bf18a", "0x80bcb114b2544b80f404a200fc36860ed5e1ad31fe551acd4661d09730c452831751baa9b19d7d311600d267086a70bc", "0x90dcce03c6f88fc2b08f2b42771eedde90cc5330fe0336e46c1a7d1b5a6c1641e5fcc4e7b3d5db00bd8afca9ec66ed81", "0xaec15f40805065c98e2965b1ae12a6c9020cfdb094c2d0549acfc7ea2401a5fb48d3ea7d41133cf37c4e096e7ff53eb9", "0x80e129b735dba49fa627a615d6c273119acec8e219b2f2c4373a332b5f98d66cbbdd688dfbe72a8f8bfefaccc02c50c1", "0xa9b596da3bdfe23e6799ece5f7975bf7a1979a75f4f546deeaf8b34dfe3e0d623217cb4cf4ccd504cfa3625b88cd53f1", "0xabcbbb70b16f6e517c0ab4363ab76b46e4ff58576b5f8340e5c0e8cc0e02621b6e23d742d73b015822a238b17cfd7665", "0xa046937cc6ea6a2e1adae543353a9fe929c1ae4ad655be1cc051378482cf88b041e28b1e9a577e6ccff2d3570f55e200", "0x831279437282f315e65a60184ef158f0a3dddc15a648dc552bdc88b3e6fe8288d3cfe9f0031846d81350f5e7874b4b33", "0x993d7916fa213c6d66e7c4cafafc1eaec9a2a86981f91c31eb8a69c5df076c789cbf498a24c84e0ee77af95b42145026", "0x823907a3b6719f8d49b3a4b7c181bd9bb29fcf842d7c70660c4f351852a1e197ca46cf5e879b47fa55f616fa2b87ce5e", "0x8d228244e26132b234930ee14c75d88df0943cdb9c276a8faf167d259b7efc1beec2a87c112a6c608ad1600a239e9aae", "0xab6e55766e5bfb0cf0764ed909a8473ab5047d3388b4f46faeba2d1425c4754c55c6daf6ad4751e634c618b53e549529", "0xab0cab6860e55a84c5ad2948a7e0989e2b4b1fd637605634b118361497332df32d9549cb854b2327ca54f2bcb85eed8f", "0xb086b349ae03ef34f4b25a57bcaa5d1b29bd94f9ebf87e22be475adfe475c51a1230c1ebe13506cb72c4186192451658", "0x8a0b49d8a254ca6d91500f449cbbfbb69bb516c6948ac06808c65595e46773e346f97a5ce0ef7e5a5e0de278af22709c", "0xac49de11edaaf04302c73c578cc0824bdd165c0d6321be1c421c1950e68e4f3589aa3995448c9699e93c6ebae8803e27", "0x884f02d841cb5d8f4c60d1402469216b114ab4e93550b5bc1431756e365c4f870a9853449285384a6fa49e12ce6dc654", "0xb75f3a28fa2cc8d36b49130cb7448a23d73a7311d0185ba803ad55c8219741d451c110f48b786e96c728bc525903a54f", "0x80ae04dbd41f4a35e33f9de413b6ad518af0919e5a30cb0fa1b061b260420780bb674f828d37fd3b52b5a31673cbd803", "0xb9a8011eb5fcea766907029bf743b45262db3e49d24f84503687e838651ed11cb64c66281e20a0ae9f6aa51acc552263", "0x90bfdd75e2dc9cf013e22a5d55d2d2b8a754c96103a17524488e01206e67f8b6d52b1be8c4e3d5307d4fe06d0e51f54c", "0xb4af353a19b06203a815ec43e79a88578cc678c46f5a954b85bc5c53b84059dddba731f3d463c23bfd5273885c7c56a4", "0xaa125e96d4553b64f7140e5453ff5d2330318b69d74d37d283e84c26ad672fa00e3f71e530eb7e28be1e94afb9c4612e", "0xa18e060aee3d49cde2389b10888696436bb7949a79ca7d728be6456a356ea5541b55492b2138da90108bd1ce0e6f5524", "0x93e55f92bdbccc2de655d14b1526836ea2e52dba65eb3f87823dd458a4cb5079bf22ce6ef625cb6d6bfdd0995ab9a874", "0x89f5a683526b90c1c3ceebbb8dc824b21cff851ce3531b164f6626e326d98b27d3e1d50982e507d84a99b1e04e86a915", "0x83d1c38800361633a3f742b1cb2bfc528129496e80232611682ddbe403e92c2ac5373aea0bca93ecb5128b0b2b7a719e", "0x8ecba560ac94905e19ce8d9c7af217bf0a145d8c8bd38e2db82f5e94cc3f2f26f55819176376b51f154b4aab22056059", "0xa7e2a4a002b60291924850642e703232994acb4cfb90f07c94d1e0ecd2257bb583443283c20fc6017c37e6bfe85b7366", "0x93ed7316fa50b528f1636fc6507683a672f4f4403e55e94663f91221cc198199595bd02eef43d609f451acc9d9b36a24", "0xa1220a8ebc5c50ceed76a74bc3b7e0aa77f6884c71b64b67c4310ac29ce5526cb8992d6abc13ef6c8413ce62486a6795", "0xb2f6eac5c869ad7f4a25161d3347093e2f70e66cd925032747e901189355022fab3038bca4d610d2f68feb7e719c110b", "0xb703fa11a4d511ca01c7462979a94acb40b5d933759199af42670eb48f83df202fa0c943f6ab3b4e1cc54673ea3aab1e", "0xb5422912afbfcb901f84791b04f1ddb3c3fbdc76d961ee2a00c5c320e06d3cc5b5909c3bb805df66c5f10c47a292b13d", "0xad0934368da823302e1ac08e3ede74b05dfdbfffca203e97ffb0282c226814b65c142e6e15ec1e754518f221f01b30f7", "0xa1dd302a02e37df15bf2f1147efe0e3c06933a5a767d2d030e1132f5c3ce6b98e216b6145eb39e1e2f74e76a83165b8d", "0xa346aab07564432f802ae44738049a36f7ca4056df2d8f110dbe7fef4a3e047684dea609b2d03dc6bf917c9c2a47608f", "0xb96c5f682a5f5d02123568e50f5d0d186e4b2c4c9b956ec7aabac1b3e4a766d78d19bd111adb5176b898e916e49be2aa", "0x8a96676d56876fc85538db2e806e1cba20fd01aeb9fa3cb43ca6ca94a2c102639f65660db330e5d74a029bb72d6a0b39", "0xab0048336bd5c3def1a4064eadd49e66480c1f2abb4df46e03afbd8a3342c2c9d74ee35d79f08f4768c1646681440984", "0x888427bdf76caec90814c57ee1c3210a97d107dd88f7256f14f883ad0f392334b82be11e36dd8bfec2b37935177c7831", "0xb622b282becf0094a1916fa658429a5292ba30fb48a4c8066ce1ddcefb71037948262a01c95bab6929ed3a76ba5db9fe", "0xb5b9e005c1f456b6a368a3097634fb455723abe95433a186e8278dceb79d4ca2fbe21f8002e80027b3c531e5bf494629", "0xa3c6707117a1e48697ed41062897f55d8119403eea6c2ee88f60180f6526f45172664bfee96bf61d6ec0b7fbae6aa058", "0xb02a9567386a4fbbdb772d8a27057b0be210447348efe6feb935ceec81f361ed2c0c211e54787dc617cdffed6b4a6652", "0xa9b8364e40ef15c3b5902e5534998997b8493064fa2bea99600def58279bb0f64574c09ba11e9f6f669a8354dd79dc85", "0x9998a2e553a9aa9a206518fae2bc8b90329ee59ab23005b10972712389f2ec0ee746033c733092ffe43d73d33abbb8ef", "0x843a4b34d9039bf79df96d79f2d15e8d755affb4d83d61872daf540b68c0a3888cf8fc00d5b8b247b38524bcb3b5a856", "0x84f7128920c1b0bb40eee95701d30e6fc3a83b7bb3709f16d97e72acbb6057004ee7ac8e8f575936ca9dcb7866ab45f7", "0x918d3e2222e10e05edb34728162a899ad5ada0aaa491aeb7c81572a9c0d506e31d5390e1803a91ff3bd8e2bb15d47f31", "0x9442d18e2489613a7d47bb1cb803c8d6f3259d088cd079460976d87f7905ee07dea8f371b2537f6e1d792d36d7e42723", "0xb491976970fe091995b2ed86d629126523ccf3e9daf8145302faca71b5a71a5da92e0e05b62d7139d3efac5c4e367584", "0xaa628006235dc77c14cef4c04a308d66b07ac92d377df3de1a2e6ecfe3144f2219ad6d7795e671e1cb37a3641910b940", "0x99d386adaea5d4981d7306feecac9a555b74ffdc218c907c5aa7ac04abaead0ec2a8237300d42a3fbc464673e417ceed", "0x8f78e8b1556f9d739648ea3cab9606f8328b52877fe72f9305545a73b74d49884044ba9c1f1c6db7d9b7c7b7c661caba", "0x8fb357ae49932d0babdf74fc7aa7464a65d3b6a2b3acf4f550b99601d3c0215900cfd67f2b6651ef94cfc323bac79fae", "0x9906f2fa25c0290775aa001fb6198113d53804262454ae8b83ef371b5271bde189c0460a645829cb6c59f9ee3a55ce4d", "0x8f4379b3ebb50e052325b27655ca6a82e6f00b87bf0d2b680d205dd2c7afdc9ff32a9047ae71a1cdf0d0ce6b9474d878", "0xa85534e88c2bd43c043792eaa75e50914b21741a566635e0e107ae857aed0412035f7576cf04488ade16fd3f35fdbb87", "0xb4ce93199966d3c23251ca7f28ec5af7efea1763d376b0385352ffb2e0a462ef95c69940950278cf0e3dafd638b7bd36", "0xb10cb3d0317dd570aa73129f4acf63c256816f007607c19b423fb42f65133ce21f2f517e0afb41a5378cccf893ae14d0", "0xa9b231c9f739f7f914e5d943ed9bff7eba9e2c333fbd7c34eb1648a362ee01a01af6e2f7c35c9fe962b11152cddf35de", "0x99ff6a899e156732937fb81c0cced80ae13d2d44c40ba99ac183aa246103b31ec084594b1b7feb96da58f4be2dd5c0ed", "0x8748d15d18b75ff2596f50d6a9c4ce82f61ecbcee123a6ceae0e43cab3012a29b6f83cf67b48c22f6f9d757c6caf76b2", "0xb88ab05e4248b7fb634cf640a4e6a945d13e331237410f7217d3d17e3e384ddd48897e7a91e4516f1b9cbd30f35f238b", "0x8d826deaeeb84a3b2d2c04c2300ca592501f992810582d6ae993e0d52f6283a839dba66c6c72278cff5871802b71173b", "0xb36fed027c2f05a5ef625ca00b0364b930901e9e4420975b111858d0941f60e205546474bb25d6bfa6928d37305ae95f", "0xaf2fcfc6b87967567e8b8a13a4ed914478185705724e56ce68fb2df6d1576a0cf34a61e880997a0d35dc2c3276ff7501", "0xac351b919cd1fbf106feb8af2c67692bfcddc84762d18cea681cfa7470a5644839caace27efee5f38c87d3df306f4211", "0x8d6665fb1d4d8d1fa23bd9b8a86e043b8555663519caac214d1e3e3effbc6bee7f2bcf21e645f77de0ced279d69a8a8b", "0xa9fc1c2061756b2a1a169c1b149f212ff7f0d2488acd1c5a0197eba793cffa593fc6d1d1b40718aa75ca3ec77eff10e1", "0xaff64f0fa009c7a6cf0b8d7a22ddb2c8170c3cb3eec082e60d5aadb00b0040443be8936d728d99581e33c22178c41c87", "0x82e0b181adc5e3b1c87ff8598447260e839d53debfae941ebea38265575546c3a74a14b4325a030833a62ff6c52d9365", "0xb7ad43cbb22f6f892c2a1548a41dc120ab1f4e1b8dea0cb6272dd9cb02054c542ecabc582f7e16de709d48f5166cae86", "0x985e0c61094281532c4afb788ecb2dfcba998e974b5d4257a22040a161883908cdd068fe80f8eb49b8953cfd11acf43a", "0xae46895c6d67ea6d469b6c9c07b9e5d295d9ae73b22e30da4ba2c973ba83a130d7eef39717ec9d0f36e81d56bf742671", "0x8600177ea1f7e7ef90514b38b219a37dedfc39cb83297e4c7a5b479817ef56479d48cf6314820960c751183f6edf8b0e", "0xb9208ec1c1d7a1e99b59c62d3e4e61dfb706b0e940d09d3abfc3454c19749083260614d89cfd7e822596c3cdbcc6bb95", "0xa1e94042c796c2b48bc724352d2e9f3a22291d9a34705993357ddb6adabd76da6fc25dac200a8cb0b5bbd99ecddb7af6", "0xb29c3adedd0bcad8a930625bc4dfdc3552a9afd5ca6dd9c0d758f978068c7982b50b711aa0eb5b97f2b84ee784637835", "0xaf0632a238bb1f413c7ea8e9b4c3d68f2827bd2e38cd56024391fba6446ac5d19a780d0cfd4a78fe497d537b766a591a", "0xaaf6e7f7d54f8ef5e2e45dd59774ecbeecf8683aa70483b2a75be6a6071b5981bbaf1627512a65d212817acdfab2e428", "0x8c751496065da2e927cf492aa5ca9013b24f861d5e6c24b30bbf52ec5aaf1905f40f9a28175faef283dd4ed4f2182a09", "0x8952377d8e80a85cf67d6b45499f3bad5fd452ea7bcd99efc1b066c4720d8e5bff1214cea90fd1f972a7f0baac3d29be", "0xa1946ee543d1a6e21f380453be4d446e4130950c5fc3d075794eb8260f6f52d0a795c1ff91d028a648dc1ce7d9ab6b47", "0x89f3fefe37af31e0c17533d2ca1ce0884cc1dc97c15cbfab9c331b8debd94781c9396abef4bb2f163d09277a08d6adf0", "0xa2753f1e6e1a154fb117100a5bd9052137add85961f8158830ac20541ab12227d83887d10acf7fd36dcaf7c2596d8d23", "0x814955b4198933ee11c3883863b06ff98c7eceb21fc3e09df5f916107827ccf3323141983e74b025f46ae00284c9513b", "0x8cc5c6bb429073bfef47cae7b3bfccb0ffa076514d91a1862c6bda4d581e0df87db53cc6c130bf8a7826304960f5a34e", "0x909f22c1f1cdc87f7be7439c831a73484a49acbf8f23d47087d7cf867c64ef61da3bde85dc57d705682b4c3fc710d36e", "0x8048fee7f276fcd504aed91284f28e73693615e0eb3858fa44bcf79d7285a9001c373b3ef71d9a3054817ba293ebe28c", "0x94400e5cf5d2700ca608c5fe35ce14623f71cc24959f2bc27ca3684092850f76b67fb1f07ca9e5b2ca3062cf8ad17bd4", "0x81c2ae7d4d1b17f8b6de6a0430acc0d58260993980fe48dc2129c4948269cdc74f9dbfbf9c26b19360823fd913083d48", "0x8c41fe765128e63f6889d6a979f6a4342300327c8b245a8cfe3ecfbcac1e09c3da30e2a1045b24b78efc6d6d50c8c6ac", "0xa5dd4ae51ae48c8be4b218c312ade226cffce671cf121cb77810f6c0990768d6dd767badecb5c69921d5574d5e8433d3", "0xb7642e325f4ba97ae2a39c1c9d97b35aafd49d53dba36aed3f3cb0ca816480b3394079f46a48252d46596559c90f4d58", "0xae87375b40f35519e7bd4b1b2f73cd0b329b0c2cb9d616629342a71c6c304338445eda069b78ea0fbe44087f3de91e09", "0xb08918cb6f736855e11d3daca1ddfbdd61c9589b203b5493143227bf48e2c77c2e8c94b0d1aa2fab2226e0eae83f2681", "0xac36b84a4ac2ebd4d6591923a449c564e3be8a664c46092c09e875c2998eba16b5d32bfd0882fd3851762868e669f0b1", "0xa44800a3bb192066fa17a3f29029a23697240467053b5aa49b9839fb9b9b8b12bcdcbfc557f024b61f4f51a9aacdefcb", "0x9064c688fec23441a274cdf2075e5a449caf5c7363cc5e8a5dc9747183d2e00a0c69f2e6b3f6a7057079c46014c93b3b", "0xaa367b021469af9f5b764a79bb3afbe2d87fe1e51862221672d1a66f954b165778b7c27a705e0f93841fab4c8468344d", "0xa1a8bfc593d4ab71f91640bc824de5c1380ab2591cfdafcbc78a14b32de3c0e15f9d1b461d85c504baa3d4232c16bb53", "0x97df48da1799430f528184d30b6baa90c2a2f88f34cdfb342d715339c5ebd6d019aa693cea7c4993daafc9849063a3aa", "0xabd923831fbb427e06e0dd335253178a9e5791395c84d0ab1433c07c53c1209161097e9582fb8736f8a60bde62d8693e", "0x84cd1a43f1a438b43dc60ffc775f646937c4f6871438163905a3cebf1115f814ccd38a6ccb134130bff226306e412f32", "0x91426065996b0743c5f689eb3ca68a9f7b9e4d01f6c5a2652b57fa9a03d8dc7cd4bdbdab0ca5a891fee1e97a7f00cf02", "0xa4bee50249db3df7fd75162b28f04e57c678ba142ce4d3def2bc17bcb29e4670284a45f218dad3969af466c62a903757", "0x83141ebcc94d4681404e8b67a12a46374fded6df92b506aff3490d875919631408b369823a08b271d006d5b93136f317", "0xa0ea1c8883d58d5a784da3d8c8a880061adea796d7505c1f903d07c287c5467f71e4563fc0faafbc15b5a5538b0a7559", "0x89d9d480574f201a87269d26fb114278ed2c446328df431dc3556e3500e80e4cd01fcac196a2459d8646361ebda840df", "0x8bf302978973632dd464bec819bdb91304712a3ec859be071e662040620422c6e75eba6f864f764cffa2799272efec39", "0x922f666bc0fd58b6d7d815c0ae4f66d193d32fc8382c631037f59eeaeae9a8ca6c72d08e72944cf9e800b8d639094e77", "0x81ad8714f491cdff7fe4399f2eb20e32650cff2999dd45b9b3d996d54a4aba24cc6c451212e78c9e5550368a1a38fb3f", "0xb58fcf4659d73edb73175bd9139d18254e94c3e32031b5d4b026f2ed37aa19dca17ec2eb54c14340231615277a9d347e", "0xb365ac9c2bfe409b710928c646ea2fb15b28557e0f089d39878e365589b9d1c34baf5566d20bb28b33bb60fa133f6eff", "0x8fcae1d75b53ab470be805f39630d204853ca1629a14158bac2f52632277d77458dec204ff84b7b2d77e641c2045be65", "0xa03efa6bebe84f4f958a56e2d76b5ba4f95dd9ed7eb479edc7cc5e646c8d4792e5b0dfc66cc86aa4b4afe2f7a4850760", "0xaf1c823930a3638975fb0cc5c59651771b2719119c3cd08404fbd4ce77a74d708cefbe3c56ea08c48f5f10e6907f338f", "0x8260c8299b17898032c761c325ac9cabb4c5b7e735de81eacf244f647a45fb385012f4f8df743128888c29aefcaaad16", "0xab2f37a573c82e96a8d46198691cd694dfa860615625f477e41f91b879bc58a745784fccd8ffa13065834ffd150d881d", "0x986c746c9b4249352d8e5c629e8d7d05e716b3c7aab5e529ca969dd1e984a14b5be41528baef4c85d2369a42d7209216", "0xb25e32da1a8adddf2a6080725818b75bc67240728ad1853d90738485d8924ea1e202df0a3034a60ffae6f965ec55cf63", "0xa266e627afcebcefea6b6b44cbc50f5c508f7187e87d047b0450871c2a030042c9e376f3ede0afcf9d1952f089582f71", "0x86c3bbca4c0300606071c0a80dbdec21ce1dd4d8d4309648151c420854032dff1241a1677d1cd5de4e4de4385efda986", "0xb9a21a1fe2d1f3273a8e4a9185abf2ff86448cc98bfa435e3d68306a2b8b4a6a3ea33a155be3cb62a2170a86f77679a5", "0xb117b1ea381adce87d8b342cba3a15d492ff2d644afa28f22424cb9cbc820d4f7693dfc1a4d1b3697046c300e1c9b4c8", "0x9004c425a2e68870d6c69b658c344e3aa3a86a8914ee08d72b2f95c2e2d8a4c7bb0c6e7e271460c0e637cec11117bf8e", "0x86a18aa4783b9ebd9131580c8b17994825f27f4ac427b0929a1e0236907732a1c8139e98112c605488ee95f48bbefbfc", "0x84042243b955286482ab6f0b5df4c2d73571ada00716d2f737ca05a0d2e88c6349e8ee9e67934cfee4a1775dbf7f4800", "0x92c2153a4733a62e4e1d5b60369f3c26777c7d01cd3c8679212660d572bd3bac9b8a8a64e1f10f7dbf5eaa7579c4e423", "0x918454b6bb8e44a2afa144695ba8d48ae08d0cdfef4ad078f67709eddf3bb31191e8b006f04e82ea45a54715ef4d5817", "0xacf0b54f6bf34cf6ed6c2b39cf43194a40d68de6bcf1e4b82c34c15a1343e9ac3737885e1a30b78d01fa3a5125463db8", "0xa7d60dbe4b6a7b054f7afe9ee5cbbfeca0d05dc619e6041fa2296b549322529faddb8a11e949562309aecefb842ac380", "0x91ffb53e6d7e5f11159eaf13e783d6dbdfdb1698ed1e6dbf3413c6ea23492bbb9e0932230a9e2caac8fe899a17682795", "0xb6e8d7be5076ee3565d5765a710c5ecf17921dd3cf555c375d01e958a365ae087d4a88da492a5fb81838b7b92bf01143", "0xa8c6b763de2d4b2ed42102ef64eccfef31e2fb2a8a2776241c82912fa50fc9f77f175b6d109a97ede331307c016a4b1a", "0x99839f86cb700c297c58bc33e28d46b92931961548deac29ba8df91d3e11721b10ea956c8e16984f9e4acf1298a79b37", "0x8c2e2c338f25ea5c25756b7131cde0d9a2b35abf5d90781180a00fe4b8e64e62590dc63fe10a57fba3a31c76d784eb01", "0x9687d7df2f41319ca5469d91978fed0565a5f11f829ebadaa83db92b221755f76c6eacd7700735e75c91e257087512e3", "0x8795fdfb7ff8439c58b9bf58ed53873d2780d3939b902b9ddaaa4c99447224ced9206c3039a23c2c44bcc461e2bb637f", "0xa803697b744d2d087f4e2307218d48fa88620cf25529db9ce71e2e3bbcc65bac5e8bb9be04777ef7bfb5ed1a5b8e6170", "0x80f3d3efbbb9346ddd413f0a8e36b269eb5d7ff6809d5525ff9a47c4bcab2c01b70018b117f6fe05253775612ff70c6b", "0x9050e0e45bcc83930d4c505af35e5e4d7ca01cd8681cba92eb55821aececcebe32bb692ebe1a4daac4e7472975671067", "0x8d206812aac42742dbaf233e0c080b3d1b30943b54b60283515da005de05ea5caa90f91fedcfcba72e922f64d7040189", "0xa2d44faaeb2eff7915c83f32b13ca6f31a6847b1c1ce114ea240bac3595eded89f09b2313b7915ad882292e2b586d5b4", "0x961776c8576030c39f214ea6e0a3e8b3d32f023d2600958c098c95c8a4e374deeb2b9dc522adfbd6bda5949bdc09e2a2", "0x993fa7d8447407af0fbcd9e6d77f815fa5233ab00674efbcf74a1f51c37481445ae291cc7b76db7c178f9cb0e570e0fc", "0xabd5b1c78e05f9d7c8cc99bdaef8b0b6a57f2daf0f02bf492bec48ea4a27a8f1e38b5854da96efff11973326ff980f92", "0x8f15af4764bc275e6ccb892b3a4362cacb4e175b1526a9a99944e692fe6ccb1b4fc19abf312bb2a089cb1f344d91a779", "0xa09b27ccd71855512aba1d0c30a79ffbe7f6707a55978f3ced50e674b511a79a446dbc6d7946add421ce111135a460af", "0x94b2f98ce86a9271fbd4153e1fc37de48421fe3490fb3840c00f2d5a4d0ba8810c6a32880b002f6374b59e0a7952518b", "0x8650ac644f93bbcb88a6a0f49fee2663297fd4bc6fd47b6a89b9d8038d32370438ab3a4775ec9b58cb10aea8a95ef7b6", "0x95e5c2f2e84eed88c6980bbba5a1c0bb375d5a628bff006f7516d45bb7d723da676add4fdd45956f312e7bab0f052644", "0xb3278a3fa377ac93af7cfc9453f8cb594aae04269bbc99d2e0e45472ff4b6a2f97a26c4c57bf675b9d86f5e77a5d55d1", "0xb4bcbe6eb666a206e2ea2f877912c1d3b5bdbd08a989fc4490eb06013e1a69ad1ba08bcdac048bf29192312be399077b", "0xa76d70b78c99fffcbf9bb9886eab40f1ea4f99a309710b660b64cbf86057cbcb644d243f6e341711bb7ef0fedf0435a7", "0xb2093c1ee945dca7ac76ad5aed08eae23af31dd5a77c903fd7b6f051f4ab84425d33a03c3d45bf2907bc93c02d1f3ad8", "0x904b1f7534e053a265b22d20be859912b9c9ccb303af9a8d6f1d8f6ccdc5c53eb4a45a1762b880d8444d9be0cd55e7f9", "0x8f664a965d65bc730c9ef1ec7467be984d4b8eb46bd9b0d64e38e48f94e6e55dda19aeac82cbcf4e1473440e64c4ca18", "0x8bcee65c4cc7a7799353d07b114c718a2aae0cd10a3f22b7eead5185d159dafd64852cb63924bf87627d176228878bce", "0x8c78f2e3675096fef7ebaa898d2615cd50d39ca3d8f02b9bdfb07e67da648ae4be3da64838dffc5935fd72962c4b96c7", "0x8c40afd3701629421fec1df1aac4e849384ef2e80472c0e28d36cb1327acdf2826f99b357f3d7afdbc58a6347fc40b3c", "0xa197813b1c65a8ea5754ef782522a57d63433ef752215ecda1e7da76b0412ee619f58d904abd2e07e0c097048b6ae1dd", "0xa670542629e4333884ad7410f9ea3bd6f988df4a8f8a424ca74b9add2312586900cf9ae8bd50411f9146e82626b4af56", "0xa19875cc07ab84e569d98b8b67fb1dbbdfb59093c7b748fae008c8904a6fd931a63ca8d03ab5fea9bc8d263568125a9b", "0xb57e7f68e4eb1bd04aafa917b1db1bdab759a02aa8a9cdb1cba34ba8852b5890f655645c9b4e15d5f19bf37e9f2ffe9f", "0x8abe4e2a4f6462b6c64b3f10e45db2a53c2b0d3c5d5443d3f00a453e193df771eda635b098b6c8604ace3557514027af", "0x8459e4fb378189b22b870a6ef20183deb816cefbf66eca1dc7e86d36a2e011537db893729f500dc154f14ce24633ba47", "0x930851df4bc7913c0d8c0f7bd3b071a83668987ed7c397d3d042fdc0d9765945a39a3bae83da9c88cb6b686ed8aeeb26", "0x8078c9e5cd05e1a8c932f8a1d835f61a248b6e7133fcbb3de406bf4ffc0e584f6f9f95062740ba6008d98348886cf76b", "0xaddff62bb29430983fe578e3709b0949cdc0d47a13a29bc3f50371a2cb5c822ce53e2448cfaa01bcb6e0aa850d5a380e", "0x9433add687b5a1e12066721789b1db2edf9b6558c3bdc0f452ba33b1da67426abe326e9a34d207bfb1c491c18811bde1", "0x822beda3389963428cccc4a2918fa9a8a51cf0919640350293af70821967108cded5997adae86b33cb917780b097f1ca", "0xa7a9f52bda45e4148ed56dd176df7bd672e9b5ed18888ccdb405f47920fdb0844355f8565cefb17010b38324edd8315f", "0xb35c3a872e18e607b2555c51f9696a17fa18da1f924d503b163b4ec9fe22ed0c110925275cb6c93ce2d013e88f173d6a", "0xadf34b002b2b26ab84fc1bf94e05bd8616a1d06664799ab149363c56a6e0c807fdc473327d25632416e952ea327fcd95", "0xae4a6b9d22a4a3183fac29e2551e1124a8ce4a561a9a2afa9b23032b58d444e6155bb2b48f85c7b6d70393274e230db7", "0xa2ea3be4fc17e9b7ce3110284038d46a09e88a247b6971167a7878d9dcf36925d613c382b400cfa4f37a3ebea3699897", "0x8e5863786b641ce3140fbfe37124d7ad3925472e924f814ebfc45959aaf3f61dc554a597610b5defaecc85b59a99b50f", "0xaefde3193d0f700d0f515ab2aaa43e2ef1d7831c4f7859f48e52693d57f97fa9e520090f3ed700e1c966f4b76048e57f", "0x841a50f772956622798e5cd208dc7534d4e39eddee30d8ce133383d66e5f267e389254a0cdae01b770ecd0a9ca421929", "0x8fbc2bfd28238c7d47d4c03b1b910946c0d94274a199575e5b23242619b1de3497784e646a92aa03e3e24123ae4fcaba", "0x926999579c8eec1cc47d7330112586bdca20b4149c8b2d066f527c8b9f609e61ce27feb69db67eea382649c6905efcf9", "0xb09f31f305efcc65589adf5d3690a76cf339efd67cd43a4e3ced7b839507466e4be72dd91f04e89e4bbef629d46e68c0", "0xb917361f6b95f759642638e0b1d2b3a29c3bdef0b94faa30de562e6078c7e2d25976159df3edbacbf43614635c2640b4", "0x8e7e8a1253bbda0e134d62bfe003a2669d471b47bd2b5cde0ff60d385d8e62279d54022f5ac12053b1e2d3aaa6910b4c", "0xb69671a3c64e0a99d90b0ed108ce1912ff8ed983e4bddd75a370e9babde25ee1f5efb59ec707edddd46793207a8b1fe7", "0x910b2f4ebd37b7ae94108922b233d0920b4aba0bd94202c70f1314418b548d11d8e9caa91f2cd95aff51b9432d122b7f", "0x82f645c90dfb52d195c1020346287c43a80233d3538954548604d09fbab7421241cde8593dbc4acc4986e0ea39a27dd9", "0x8fee895f0a140d88104ce442fed3966f58ff9d275e7373483f6b4249d64a25fb5374bbdc6bce6b5ab0270c2847066f83", "0x84f5bd7aab27b2509397aeb86510dd5ac0a53f2c8f73799bf720f2f87a52277f8d6b0f77f17bc80739c6a7119b7eb062", "0x9903ceced81099d7e146e661bcf01cbaccab5ba54366b85e2177f07e2d8621e19d9c9c3eee14b9266de6b3f9b6ea75ae", "0xb9c16ea2a07afa32dd6c7c06df0dec39bca2067a9339e45475c98917f47e2320f6f235da353fd5e15b477de97ddc68dd", "0x9820a9bbf8b826bec61ebf886de2c4f404c1ebdc8bab82ee1fea816d9de29127ce1852448ff717a3fe8bbfe9e92012e5", "0x817224d9359f5da6f2158c2c7bf9165501424f063e67ba9859a07ab72ee2ee62eb00ca6da821cfa19065c3282ca72c74", "0x94b95c465e6cb00da400558a3c60cfec4b79b27e602ca67cbc91aead08de4b6872d8ea096b0dc06dca4525c8992b8547", "0xa2b539a5bccd43fa347ba9c15f249b417997c6a38c63517ca38394976baa08e20be384a360969ff54e7e721db536b3e5", "0x96caf707e34f62811ee8d32ccf28d8d6ec579bc33e424d0473529af5315c456fd026aa910c1fed70c91982d51df7d3ca", "0x8a77b73e890b644c6a142bdbac59b22d6a676f3b63ddafb52d914bb9d395b8bf5aedcbcc90429337df431ebd758a07a6", "0x8857830a7351025617a08bc44caec28d2fae07ebf5ffc9f01d979ce2a53839a670e61ae2783e138313929129790a51a1", "0xaa3e420321ed6f0aa326d28d1a10f13facec6f605b6218a6eb9cbc074801f3467bf013a456d1415a5536f12599efa3d3", "0x824aed0951957b00ea2f3d423e30328a3527bf6714cf9abbae84cf27e58e5c35452ba89ccc011de7c68c75d6e021d8f1", "0xa2e87cc06bf202e953fb1081933d8b4445527dde20e38ed1a4f440144fd8fa464a2b73e068b140562e9045e0f4bd3144", "0xae3b8f06ad97d7ae3a5e5ca839efff3e4824dc238c0c03fc1a8d2fc8aa546cdfd165b784a31bb4dec7c77e9305b99a4b", "0xb30c3e12395b1fb8b776f3ec9f87c70e35763a7b2ddc68f0f60a4982a84017f27c891a98561c830038deb033698ed7fc", "0x874e507757cd1177d0dff0b0c62ce90130324442a33da3b2c8ee09dbca5d543e3ecfe707e9f1361e7c7db641c72794bb", "0xb53012dd10b5e7460b57c092eaa06d6502720df9edbbe3e3f61a9998a272bf5baaac4a5a732ad4efe35d6fac6feca744", "0x85e6509d711515534d394e6cacbed6c81da710074d16ef3f4950bf2f578d662a494d835674f79c4d6315bced4defc5f0", "0xb6132b2a34b0905dcadc6119fd215419a7971fe545e52f48b768006944b4a9d7db1a74b149e2951ea48c083b752d0804", "0x989867da6415036d19b4bacc926ce6f4df7a556f50a1ba5f3c48eea9cefbb1c09da81481c8009331ee83f0859185e164", "0x960a6c36542876174d3fbc1505413e29f053ed87b8d38fef3af180491c7eff25200b45dd5fe5d4d8e63c7e8c9c00f4c8", "0x9040b59bd739d9cc2e8f6e894683429e4e876a8106238689ff4c22770ae5fdae1f32d962b30301fa0634ee163b524f35", "0xaf3fcd0a45fe9e8fe256dc7eab242ef7f582dd832d147444483c62787ac820fafc6ca55d639a73f76bfa5e7f5462ab8f", "0xb934c799d0736953a73d91e761767fdb78454355c4b15c680ce08accb57ccf941b13a1236980001f9e6195801cffd692", "0x8871e8e741157c2c326b22cf09551e78da3c1ec0fc0543136f581f1550f8bab03b0a7b80525c1e99812cdbf3a9698f96", "0xa8a977f51473a91d178ee8cfa45ffef8d6fd93ab1d6e428f96a3c79816d9c6a93cd70f94d4deda0125fd6816e30f3bea", "0xa7688b3b0a4fc1dd16e8ba6dc758d3cfe1b7cf401c31739484c7fa253cce0967df1b290769bcefc9d23d3e0cb19e6218", "0x8ae84322662a57c6d729e6ff9d2737698cc2da2daeb1f39e506618750ed23442a6740955f299e4a15dda6db3e534d2c6", "0xa04a961cdccfa4b7ef83ced17ab221d6a043b2c718a0d6cc8e6f798507a31f10bf70361f70a049bc8058303fa7f96864", "0xb463e39732a7d9daec8a456fb58e54b30a6e160aa522a18b9a9e836488cce3342bcbb2e1deab0f5e6ec0a8796d77197d", "0xb1434a11c6750f14018a2d3bcf94390e2948f4f187e93bb22070ca3e5393d339dc328cbfc3e48815f51929465ffe7d81", "0x84ff81d73f3828340623d7e3345553610aa22a5432217ef0ebd193cbf4a24234b190c65ca0873c22d10ea7b63bd1fbed", "0xb6fe2723f0c47757932c2ddde7a4f8434f665612f7b87b4009c2635d56b6e16b200859a8ade49276de0ef27a2b6c970a", "0x9742884ed7cd52b4a4a068a43d3faa02551a424136c85a9313f7cb58ea54c04aa83b0728fd741d1fe39621e931e88f8f", "0xb7d2d65ea4d1ad07a5dee39e40d6c03a61264a56b1585b4d76fc5b2a68d80a93a42a0181d432528582bf08d144c2d6a9", "0x88c0f66bada89f8a43e5a6ead2915088173d106c76f724f4a97b0f6758aed6ae5c37c373c6b92cdd4aea8f6261f3a374", "0x81f9c43582cb42db3900747eb49ec94edb2284999a499d1527f03315fd330e5a509afa3bff659853570e9886aab5b28b", "0x821f9d27d6beb416abf9aa5c79afb65a50ed276dbda6060103bc808bcd34426b82da5f23e38e88a55e172f5c294b4d40", "0x8ba307b9e7cb63a6c4f3851b321aebfdb6af34a5a4c3bd949ff7d96603e59b27ff4dc4970715d35f7758260ff942c9e9", "0xb142eb6c5f846de33227d0bda61d445a7c33c98f0a8365fe6ab4c1fabdc130849be597ef734305894a424ea715372d08", "0xa732730ae4512e86a741c8e4c87fee8a05ee840fec0e23b2e037d58dba8dde8d10a9bc5191d34d00598941becbbe467f", "0xadce6f7c30fd221f6b10a0413cc76435c4bb36c2d60bca821e5c67409fe9dbb2f4c36ef85eb3d734695e4be4827e9fd3", "0xa74f00e0f9b23aff7b2527ce69852f8906dab9d6abe62ecd497498ab21e57542e12af9918d4fd610bb09e10b0929c510", "0xa593b6b0ef26448ce4eb3ab07e84238fc020b3cb10d542ff4b16d4e2be1bcde3797e45c9cf753b8dc3b0ffdb63984232", "0xaed3913afccf1aa1ac0eb4980eb8426d0baccebd836d44651fd72af00d09fac488a870223c42aca3ceb39752070405ae", "0xb2c44c66a5ea7fde626548ba4cef8c8710191343d3dadfd3bb653ce715c0e03056a5303a581d47dde66e70ea5a2d2779", "0x8e5029b2ccf5128a12327b5103f7532db599846e422531869560ceaff392236434d87159f597937dbf4054f810c114f4", "0x82beed1a2c4477e5eb39fc5b0e773b30cfec77ef2b1bf17eadaf60eb35b6d0dd9d8cf06315c48d3546badb3f21cd0cca", "0x90077bd6cc0e4be5fff08e5d07a5a158d36cebd1d1363125bc4fae0866ffe825b26f933d4ee5427ba5cd0c33c19a7b06", "0xa7ec0d8f079970e8e34f0ef3a53d3e0e45428ddcef9cc776ead5e542ef06f3c86981644f61c5a637e4faf001fb8c6b3e", "0xae6d4add6d1a6f90b22792bc9d40723ee6850c27d0b97eefafd5b7fd98e424aa97868b5287cc41b4fbd7023bca6a322c", "0x831aa917533d077da07c01417feaa1408846363ba2b8d22c6116bb858a95801547dd88b7d7fa1d2e3f0a02bdeb2e103d", "0x96511b860b07c8a5ed773f36d4aa9d02fb5e7882753bf56303595bcb57e37ccc60288887eb83bef08c657ec261a021a2", "0x921d2a3e7e9790f74068623de327443666b634c8443aba80120a45bba450df920b2374d96df1ce3fb1b06dd06f8cf6e3", "0xaa74451d51fe82b4581ead8e506ec6cd881010f7e7dd51fc388eb9a557db5d3c6721f81c151d08ebd9c2591689fbc13e", "0xa972bfbcf4033d5742d08716c927c442119bdae336bf5dff914523b285ccf31953da2733759aacaa246a9af9f698342c", "0xad1fcd0cae0e76840194ce4150cb8a56ebed728ec9272035f52a799d480dfc85840a4d52d994a18b6edb31e79be6e8ad", "0xa2c69fe1d36f235215432dad48d75887a44c99dfa0d78149acc74087da215a44bdb5f04e6eef88ff7eff80a5a7decc77", "0xa94ab2af2b6ee1bc6e0d4e689ca45380d9fbd3c5a65b9bd249d266a4d4c07bf5d5f7ef2ae6000623aee64027892bf8fe", "0x881ec1fc514e926cdc66480ac59e139148ff8a2a7895a49f0dff45910c90cdda97b66441a25f357d6dd2471cddd99bb3", "0x884e6d3b894a914c8cef946a76d5a0c8351843b2bffa2d1e56c6b5b99c84104381dd1320c451d551c0b966f4086e60f9", "0x817c6c10ce2677b9fc5223500322e2b880583254d0bb0d247d728f8716f5e05c9ff39f135854342a1afecd9fbdcf7c46", "0xaaf4a9cb686a14619aa1fc1ac285dd3843ac3dd99f2b2331c711ec87b03491c02f49101046f3c5c538dc9f8dba2a0ac2", "0x97ecea5ce53ca720b5d845227ae61d70269a2f53540089305c86af35f0898bfd57356e74a8a5e083fa6e1ea70080bd31", "0xa22d811e1a20a75feac0157c418a4bfe745ccb5d29466ffa854dca03e395b6c3504a734341746b2846d76583a780b32e", "0x940cbaa0d2b2db94ae96b6b9cf2deefbfd059e3e5745de9aec4a25f0991b9721e5cd37ef71c631575d1a0c280b01cd5b", "0xae33cb4951191258a11044682de861bf8d92d90ce751b354932dd9f3913f542b6a0f8a4dc228b3cd9244ac32c4582832", "0xa580df5e58c4274fe0f52ac2da1837e32f5c9db92be16c170187db4c358f43e5cfdda7c5911dcc79d77a5764e32325f5", "0x81798178cb9d8affa424f8d3be67576ba94d108a28ccc01d330c51d5a63ca45bb8ca63a2f569b5c5fe1303cecd2d777f", "0x89975b91b94c25c9c3660e4af4047a8bacf964783010820dbc91ff8281509379cb3b24c25080d5a01174dd9a049118d5", "0xa7327fcb3710ed3273b048650bde40a32732ef40a7e58cf7f2f400979c177944c8bc54117ba6c80d5d4260801dddab79", "0x92b475dc8cb5be4b90c482f122a51bcb3b6c70593817e7e2459c28ea54a7845c50272af38119406eaadb9bcb993368d0", "0x9645173e9ecefc4f2eae8363504f7c0b81d85f8949a9f8a6c01f2d49e0a0764f4eacecf3e94016dd407fc14494fce9f9", "0x9215fd8983d7de6ae94d35e6698226fc1454977ae58d42d294be9aad13ac821562ad37d5e7ee5cdfe6e87031d45cd197", "0x810360a1c9b88a9e36f520ab5a1eb8bed93f52deefbe1312a69225c0a08edb10f87cc43b794aced9c74220cefcc57e7d", "0xad7e810efd61ed4684aeda9ed8bb02fb9ae4b4b63fda8217d37012b94ff1b91c0087043bfa4e376f961fff030c729f3b", "0x8b07c95c6a06db8738d10bb03ec11b89375c08e77f0cab7e672ce70b2685667ca19c7e1c8b092821d31108ea18dfd4c7", "0x968825d025ded899ff7c57245250535c732836f7565eab1ae23ee7e513201d413c16e1ba3f5166e7ac6cf74de8ceef4f", "0x908243370c5788200703ade8164943ad5f8c458219186432e74dbc9904a701ea307fd9b94976c866e6c58595fd891c4b", "0x959969d16680bc535cdc6339e6186355d0d6c0d53d7bbfb411641b9bf4b770fd5f575beef5deec5c4fa4d192d455c350", "0xad177f4f826a961adeac76da40e2d930748effff731756c797eddc4e5aa23c91f070fb69b19221748130b0961e68a6bb", "0x82f8462bcc25448ef7e0739425378e9bb8a05e283ce54aae9dbebaf7a3469f57833c9171672ad43a79778366c72a5e37", "0xa28fb275b1845706c2814d9638573e9bc32ff552ebaed761fe96fdbce70395891ca41c400ae438369264e31a2713b15f", "0x8a9c613996b5e51dadb587a787253d6081ea446bf5c71096980bf6bd3c4b69905062a8e8a3792de2d2ece3b177a71089", "0x8d5aefef9f60cb27c1db2c649221204dda48bb9bf8bf48f965741da051340e8e4cab88b9d15c69f3f84f4c854709f48a", "0x93ebf2ca6ad85ab6deace6de1a458706285b31877b1b4d7dcb9d126b63047efaf8c06d580115ec9acee30c8a7212fa55", "0xb3ee46ce189956ca298057fa8223b7fd1128cf52f39159a58bca03c71dd25161ac13f1472301f72aef3e1993fe1ab269", "0xa24d7a8d066504fc3f5027ccb13120e2f22896860e02c45b5eba1dbd512d6a17c28f39155ea581619f9d33db43a96f92", "0xae9ceacbfe12137db2c1a271e1b34b8f92e4816bad1b3b9b6feecc34df0f8b3b0f7ed0133acdf59c537d43d33fc8d429", "0x83967e69bf2b361f86361bd705dce0e1ad26df06da6c52b48176fe8dfcbeb03c462c1a4c9e649eff8c654b18c876fdef", "0x9148e6b814a7d779c19c31e33a068e97b597de1f8100513db3c581190513edc4d544801ce3dd2cf6b19e0cd6daedd28a", "0x94ccdafc84920d320ed22de1e754adea072935d3c5f8c2d1378ebe53d140ea29853f056fb3fb1e375846061a038cc9bc", "0xafb43348498c38b0fa5f971b8cdd3a62c844f0eb52bc33daf2f67850af0880fce84ecfb96201b308d9e6168a0d443ae3", "0x86d5736520a83538d4cd058cc4b4e84213ed00ebd6e7af79ae787adc17a92ba5359e28ba6c91936d967b4b28d24c3070", "0xb5210c1ff212c5b1e9ef9126e08fe120a41e386bb12c22266f7538c6d69c7fd8774f11c02b81fd4e88f9137b020801fe", "0xb78cfd19f94d24e529d0f52e18ce6185cb238edc6bd43086270fd51dd99f664f43dd4c7d2fe506762fbd859028e13fcf", "0xa6e7220598c554abdcc3fdc587b988617b32c7bb0f82c06205467dbedb58276cc07cae317a190f19d19078773f4c2bbb", "0xb88862809487ee430368dccd85a5d72fa4d163ca4aad15c78800e19c1a95be2192719801e315d86cff7795e0544a77e4", "0x87ecb13a03921296f8c42ceb252d04716f10e09c93962239fcaa0a7fef93f19ab3f2680bc406170108bc583e9ff2e721", "0xa810cd473832b6581c36ec4cb403f2849357ba2d0b54df98ef3004b8a530c078032922a81d40158f5fb0043d56477f6e", "0xa247b45dd85ca7fbb718b328f30a03f03c84aef2c583fbdc9fcc9eb8b52b34529e8c8f535505c10598b1b4dac3d7c647", "0x96ee0b91313c68bac4aa9e065ce9e1d77e51ca4cff31d6a438718c58264dee87674bd97fc5c6b8008be709521e4fd008", "0x837567ad073e42266951a9a54750919280a2ac835a73c158407c3a2b1904cf0d17b7195a393c71a18ad029cbd9cf79ee", "0xa6a469c44b67ebf02196213e7a63ad0423aab9a6e54acc6fcbdbb915bc043586993454dc3cd9e4be8f27d67c1050879b", "0x8712d380a843b08b7b294f1f06e2f11f4ad6bcc655fdde86a4d8bc739c23916f6fad2b902fe47d6212f03607907e9f0e", "0x920adfb644b534789943cdae1bdd6e42828dda1696a440af2f54e6b97f4f97470a1c6ea9fa6a2705d8f04911d055acd1", "0xa161c73adf584a0061e963b062f59d90faac65c9b3a936b837a10d817f02fcabfa748824607be45a183dd40f991fe83f", "0x874f4ecd408c76e625ea50bc59c53c2d930ee25baf4b4eca2440bfbffb3b8bc294db579caa7c68629f4d9ec24187c1ba", "0x8bff18087f112be7f4aa654e85c71fef70eee8ae480f61d0383ff6f5ab1a0508f966183bb3fc4d6f29cb7ca234aa50d3", "0xb03b46a3ca3bc743a173cbc008f92ab1aedd7466b35a6d1ca11e894b9482ea9dc75f8d6db2ddd1add99bfbe7657518b7", "0x8b4f3691403c3a8ad9e097f02d130769628feddfa8c2b3dfe8cff64e2bed7d6e5d192c1e2ba0ac348b8585e94acd5fa1", "0xa0d9ca4a212301f97591bf65d5ef2b2664766b427c9dd342e23cb468426e6a56be66b1cb41fea1889ac5d11a8e3c50a5", "0x8c93ed74188ca23b3df29e5396974b9cc135c91fdefdea6c0df694c8116410e93509559af55533a3776ac11b228d69b1", "0x82dd331fb3f9e344ebdeeb557769b86a2cc8cc38f6c298d7572a33aea87c261afa9dbd898989139b9fc16bc1e880a099", "0xa65faedf326bcfd8ef98a51410c78b021d39206704e8291cd1f09e096a66b9b0486be65ff185ca224c45918ac337ddeb", "0xa188b37d363ac072a766fd5d6fa27df07363feff1342217b19e3c37385e42ffde55e4be8355aceaa2f267b6d66b4ac41", "0x810fa3ba3e96d843e3bafd3f2995727f223d3567c8ba77d684c993ba1773c66551eb5009897c51b3fe9b37196984f5ec", "0x87631537541852da323b4353af45a164f68b304d24c01183bf271782e11687f3fcf528394e1566c2a26cb527b3148e64", "0xb721cb2b37b3c477a48e3cc0044167d51ff568a5fd2fb606e5aec7a267000f1ddc07d3db919926ae12761a8e017c767c", "0x904dfad4ba2cc1f6e60d1b708438a70b1743b400164cd981f13c064b8328d5973987d4fb9cf894068f29d3deaf624dfb", "0xa70491538893552c20939fae6be2f07bfa84d97e2534a6bbcc0f1729246b831103505e9f60e97a8fa7d2e6c1c2384579", "0x8726cf1b26b41f443ff7485adcfddc39ace2e62f4d65dd0bb927d933e262b66f1a9b367ded5fbdd6f3b0932553ac1735", "0xae8a11cfdf7aa54c08f80cb645e3339187ab3886babe9fae5239ba507bb3dd1c0d161ca474a2df081dcd3d63e8fe445e", "0x92328719e97ce60e56110f30a00ac5d9c7a2baaf5f8d22355d53c1c77941e3a1fec7d1405e6fbf8959665fe2ba7a8cad", "0x8d9d6255b65798d0018a8cccb0b6343efd41dc14ff2058d3eed9451ceaad681e4a0fa6af67b0a04318aa628024e5553d", "0xb70209090055459296006742d946a513f0cba6d83a05249ee8e7a51052b29c0ca9722dc4af5f9816a1b7938a5dac7f79", "0xaab7b766b9bf91786dfa801fcef6d575dc6f12b77ecc662eb4498f0312e54d0de9ea820e61508fc8aeee5ab5db529349", "0xa8104b462337748b7f086a135d0c3f87f8e51b7165ca6611264b8fb639d9a2f519926cb311fa2055b5fadf03da70c678", "0xb0d2460747d5d8b30fc6c6bd0a87cb343ddb05d90a51b465e8f67d499cfc5e3a9e365da05ae233bbee792cdf90ec67d5", "0xaa55f5bf3815266b4a149f85ed18e451c93de9163575e3ec75dd610381cc0805bb0a4d7c4af5b1f94d10231255436d2c", "0x8d4c6a1944ff94426151909eb5b99cfd92167b967dabe2bf3aa66bb3c26c449c13097de881b2cfc1bf052862c1ef7b03", "0x8862296162451b9b6b77f03bf32e6df71325e8d7485cf3335d66fd48b74c2a8334c241db8263033724f26269ad95b395", "0x901aa96deb26cda5d9321190ae6624d357a41729d72ef1abfd71bebf6139af6d690798daba53b7bc5923462115ff748a", "0x96c195ec4992728a1eb38cdde42d89a7bce150db43adbc9e61e279ea839e538deec71326b618dd39c50d589f78fc0614", "0xb6ff8b8aa0837b99a1a8b46fb37f20ad4aecc6a98381b1308697829a59b8442ffc748637a88cb30c9b1f0f28a926c4f6", "0x8d807e3dca9e7bef277db1d2cfb372408dd587364e8048b304eff00eacde2c723bfc84be9b98553f83cba5c7b3cba248", "0x8800c96adb0195c4fc5b24511450dee503c32bf47044f5e2e25bd6651f514d79a2dd9b01cd8c09f3c9d3859338490f57", "0x89fe366096097e38ec28dd1148887112efa5306cc0c3da09562aafa56f4eb000bf46ff79bf0bdd270cbde6bf0e1c8957", "0xaf409a90c2776e1e7e3760b2042507b8709e943424606e31e791d42f17873a2710797f5baaab4cc4a19998ef648556b0", "0x8d761863c9b6edbd232d35ab853d944f5c950c2b643f84a1a1327ebb947290800710ff01dcfa26dc8e9828481240e8b1", "0x90b95e9be1e55c463ed857c4e0617d6dc3674e99b6aa62ed33c8e79d6dfcf7d122f4f4cc2ee3e7c5a49170cb617d2e2e", "0xb3ff381efefabc4db38cc4727432e0301949ae4f16f8d1dea9b4f4de611cf5a36d84290a0bef160dac4e1955e516b3b0", "0xa8a84564b56a9003adcadb3565dc512239fc79572762cda7b5901a255bc82656bb9c01212ad33d6bef4fbbce18dacc87", "0x90a081890364b222eef54bf0075417f85e340d2fec8b7375995f598aeb33f26b44143ebf56fca7d8b4ebb36b5747b0eb", "0xade6ee49e1293224ddf2d8ab7f14bb5be6bc6284f60fd5b3a1e0cf147b73cff57cf19763b8a36c5083badc79c606b103", "0xb2fa99806dd2fa3de09320b615a2570c416c9bcdb052e592b0aead748bbe407ec9475a3d932ae48b71c2627eb81986a6", "0x91f3b7b73c8ccc9392542711c45fe6f236057e6efad587d661ad5cb4d6e88265f86b807bb1151736b1009ab74fd7acb4", "0x8800e2a46af96696dfbdcbf2ca2918b3dcf28ad970170d2d1783b52b8d945a9167d052beeb55f56c126da7ffa7059baa", "0x9862267a1311c385956b977c9aa08548c28d758d7ba82d43dbc3d0a0fd1b7a221d39e8399997fea9014ac509ff510ac4", "0xb7d24f78886fd3e2d283e18d9ad5a25c1a904e7d9b9104bf47da469d74f34162e27e531380dbbe0a9d051e6ffd51d6e7", "0xb0f445f9d143e28b9df36b0f2c052da87ee2ca374d9d0fbe2eff66ca6fe5fe0d2c1951b428d58f7314b7e74e45d445ea", "0xb63fc4083eabb8437dafeb6a904120691dcb53ce2938b820bb553da0e1eecd476f72495aacb72600cf9cad18698fd3db", "0xb9ffd8108eaebd582d665f8690fe8bb207fd85185e6dd9f0b355a09bac1bbff26e0fdb172bc0498df025414e88fe2eda", "0x967ed453e1f1a4c5b7b6834cc9f75c13f6889edc0cc91dc445727e9f408487bbf05c337103f61397a10011dfbe25d61d", "0x98ceb673aff36e1987d5521a3984a07079c3c6155974bb8b413e8ae1ce84095fe4f7862fba7aefa14753eb26f2a5805f", "0x85f01d28603a8fdf6ce6a50cb5c44f8a36b95b91302e3f4cd95c108ce8f4d212e73aec1b8d936520d9226802a2bd9136", "0x88118e9703200ca07910345fbb789e7a8f92bd80bbc79f0a9e040e8767d33df39f6eded403a9b636eabf9101e588482a", "0x90833a51eef1b10ed74e8f9bbd6197e29c5292e469c854eed10b0da663e2bceb92539710b1858bbb21887bd538d28d89", "0xb513b905ec19191167c6193067b5cfdf5a3d3828375360df1c7e2ced5815437dfd37f0c4c8f009d7fb29ff3c8793f560", "0xb1b6d405d2d18f9554b8a358cc7e2d78a3b34269737d561992c8de83392ac9a2857be4bf15de5a6c74e0c9d0f31f393c", "0xb828bd3e452b797323b798186607849f85d1fb20c616833c0619360dfd6b3e3aa000fd09dafe4b62d74abc41072ff1a9", "0x8efde67d0cca56bb2c464731879c9ac46a52e75bac702a63200a5e192b4f81c641f855ca6747752b84fe469cb7113b6c", "0xb2762ba1c89ac3c9a983c242e4d1c2610ff0528585ed5c0dfc8a2c0253551142af9b59f43158e8915a1da7cc26b9df67", "0x8a3f1157fb820d1497ef6b25cd70b7e16bb8b961b0063ad340d82a79ee76eb2359ca9e15e6d42987ed7f154f5eeaa2da", "0xa75e29f29d38f09c879f971c11beb5368affa084313474a5ecafa2896180b9e47ea1995c2733ec46f421e395a1d9cffe", "0x8e8c3dd3e7196ef0b4996b531ec79e4a1f211db5d5635e48ceb80ff7568b2ff587e845f97ee703bb23a60945ad64314a", "0x8e7f32f4a3e3c584af5e3d406924a0aa34024c42eca74ef6cc2a358fd3c9efaf25f1c03aa1e66bb94b023a2ee2a1cace", "0xab7dce05d59c10a84feb524fcb62478906b3fa045135b23afbede3bb32e0c678d8ebe59feabccb5c8f3550ea76cae44b", "0xb38bb4b44d827f6fd3bd34e31f9186c59e312dbfadd4a7a88e588da10146a78b1f8716c91ad8b806beb8da65cab80c4c", "0x9490ce9442bbbd05438c7f5c4dea789f74a7e92b1886a730544b55ba377840740a3ae4f2f146ee73f47c9278b0e233bc", "0x83c003fab22a7178eed1a668e0f65d4fe38ef3900044e9ec63070c23f2827d36a1e73e5c2b883ec6a2afe2450171b3b3", "0x9982f02405978ddc4fca9063ebbdb152f524c84e79398955e66fe51bc7c1660ec1afc3a86ec49f58d7b7dde03505731c", "0xab337bd83ccdd2322088ffa8d005f450ced6b35790f37ab4534313315ee84312adc25e99cce052863a8bedee991729ed", "0x8312ce4bec94366d88f16127a17419ef64285cd5bf9e5eda010319b48085966ed1252ed2f5a9fd3e0259b91bb65f1827", "0xa60d5a6327c4041b0c00a1aa2f0af056520f83c9ce9d9ccd03a0bd4d9e6a1511f26a422ea86bd858a1f77438adf07e6c", "0xb84a0a0b030bdad83cf5202aa9afe58c9820e52483ab41f835f8c582c129ee3f34aa096d11c1cd922eda02ea1196a882", "0x8077d105317f4a8a8f1aadeb05e0722bb55f11abcb490c36c0904401107eb3372875b0ac233144829e734f0c538d8c1d", "0x9202503bd29a6ec198823a1e4e098f9cfe359ed51eb5174d1ca41368821bfeebcbd49debfd02952c41359d1c7c06d2b1", "0xabc28c155e09365cb77ffead8dc8f602335ef93b2f44e4ef767ce8fc8ef9dd707400f3a722e92776c2e0b40192c06354", "0xb0f6d1442533ca45c9399e0a63a11f85ff288d242cea6cb3b68c02e77bd7d158047cae2d25b3bcd9606f8f66d9b32855", "0xb01c3d56a0db84dc94575f4b6ee2de4beca3230e86bed63e2066beb22768b0a8efb08ebaf8ac3dedb5fe46708b084807", "0x8c8634b0432159f66feaabb165842d1c8ac378f79565b1b90c381aa8450eb4231c3dad11ec9317b9fc2b155c3a771e32", "0x8e67f623d69ecd430c9ee0888520b6038f13a2b6140525b056dc0951f0cfed2822e62cf11d952a483107c5c5acac4826", "0x9590bb1cba816dd6acd5ac5fba5142c0a19d53573e422c74005e0bcf34993a8138c83124cad35a3df65879dba6134edd", "0x801cd96cde0749021a253027118d3ea135f3fcdbe895db08a6c145641f95ebd368dd6a1568d995e1d0084146aebe224a", "0x848b5d196427f6fc1f762ee3d36e832b64a76ec1033cfedc8b985dea93932a7892b8ef1035c653fb9dcd9ab2d9a44ac8", "0xa1017eb83d5c4e2477e7bd2241b2b98c4951a3b391081cae7d75965cadc1acaec755cf350f1f3d29741b0828e36fedea", "0x8d6d2785e30f3c29aad17bd677914a752f831e96d46caf54446d967cb2432be2c849e26f0d193a60bee161ea5c6fe90a", "0x935c0ba4290d4595428e034b5c8001cbd400040d89ab00861108e8f8f4af4258e41f34a7e6b93b04bc253d3b9ffc13bf", "0xaac02257146246998477921cef2e9892228590d323b839f3e64ea893b991b463bc2f47e1e5092ddb47e70b2f5bce7622", "0xb921fde9412970a5d4c9a908ae8ce65861d06c7679af577cf0ad0d5344c421166986bee471fd6a6cecb7d591f06ec985", "0x8ef4c37487b139d6756003060600bb6ebac7ea810b9c4364fc978e842f13ac196d1264fbe5af60d76ff6d9203d8e7d3f", "0x94b65e14022b5cf6a9b95f94be5ace2711957c96f4211c3f7bb36206bd39cfbd0ea82186cab5ad0577a23214a5c86e9e", "0xa31c166d2a2ca1d5a75a5920fef7532681f62191a50d8555fdaa63ba4581c3391cc94a536fc09aac89f64eafceec3f90", "0x919a8cc128de01e9e10f5d83b08b52293fdd41bde2b5ae070f3d95842d4a16e5331cf2f3d61c765570c8022403610fa4", "0xb23d6f8331eef100152d60483cfa14232a85ee712c8538c9b6417a5a7c5b353c2ac401390c6c215cb101f5cee6b5f43e", "0xab357160c08a18319510a571eafff154298ce1020de8e1dc6138a09fcb0fcbcdd8359f7e9386bda00b7b9cdea745ffdc", "0xab55079aea34afa5c0bd1124b9cdfe01f325b402fdfa017301bf87812eaa811ea5798c3aaf818074d420d1c782b10ada", "0xade616010dc5009e7fc4f8d8b00dc716686a5fa0a7816ad9e503e15839d3b909b69d9dd929b7575376434ffec0d2bea8", "0x863997b97ed46898a8a014599508fa3079f414b1f4a0c4fdc6d74ae8b444afa350f327f8bfc2a85d27f9e2d049c50135", "0x8d602ff596334efd4925549ed95f2aa762b0629189f0df6dbb162581657cf3ea6863cd2287b4d9c8ad52813d87fcd235", "0xb70f68c596dcdeed92ad5c6c348578b26862a51eb5364237b1221e840c47a8702f0fbc56eb520a22c0eed99795d3903e", "0x9628088f8e0853cefadee305a8bf47fa990c50fa96a82511bbe6e5dc81ef4b794e7918a109070f92fc8384d77ace226f", "0x97e26a46e068b605ce96007197ecd943c9a23881862f4797a12a3e96ba2b8d07806ad9e2a0646796b1889c6b7d75188c", "0xb1edf467c068cc163e2d6413cc22b16751e78b3312fe47b7ea82b08a1206d64415b2c8f2a677fa89171e82cc49797150", "0xa44d15ef18745b251429703e3cab188420e2d974de07251501799b016617f9630643fcd06f895634d8ecdd579e1bf000", "0xabd126df3917ba48c618ee4dbdf87df506193462f792874439043fa1b844466f6f4e0ff2e42516e63b5b23c0892b2695", "0xa2a67f57c4aa3c2aa1eeddbfd5009a89c26c2ce8fa3c96a64626aba19514beb125f27df8559506f737de3eae0f1fc18f", "0xa633e0132197e6038197304b296ab171f1d8e0d0f34dcf66fe9146ac385b0239232a8470b9205a4802ab432389f4836d", "0xa914b3a28509a906c3821463b936455d58ff45dcbe158922f9efb2037f2eb0ce8e92532d29b5d5a3fcd0d23fa773f272", "0xa0e1412ce4505daf1a2e59ce4f0fc0e0023e335b50d2b204422f57cd65744cc7a8ed35d5ef131a42c70b27111d3115b7", "0xa2339e2f2b6072e88816224fdd612c04d64e7967a492b9f8829db15367f565745325d361fd0607b0def1be384d010d9e", "0xa7309fc41203cb99382e8193a1dcf03ac190a7ce04835304eb7e341d78634e83ea47cb15b885601956736d04cdfcaa01", "0x81f3ccd6c7f5b39e4e873365f8c37b214e8ab122d04a606fbb7339dc3298c427e922ec7418002561d4106505b5c399ee", "0x92c121cf914ca549130e352eb297872a63200e99b148d88fbc9506ad882bec9d0203d65f280fb5b0ba92e336b7f932e8", "0xa4b330cf3f064f5b131578626ad7043ce2a433b6f175feb0b52d36134a454ca219373fd30d5e5796410e005b69082e47", "0x86fe5774112403ad83f9c55d58317eeb17ad8e1176d9f2f69c2afb7ed83bc718ed4e0245ceab4b377f5f062dcd4c00e7", "0x809d152a7e2654c7fd175b57f7928365a521be92e1ed06c05188a95864ddb25f7cab4c71db7d61bbf4cae46f3a1d96ce", "0xb82d663e55c2a5ada7e169e9b1a87bc1c0177baf1ec1c96559b4cb1c5214ce1ddf2ab8d345014cab6402f3774235cf5a", "0x86580af86df1bd2c385adb8f9a079e925981b7184db66fc5fe5b14cddb82e7d836b06eaeef14924ac529487b23dae111", "0xb5f5f4c5c94944ecc804df6ab8687d64e27d988cbfeae1ba7394e0f6adbf778c5881ead7cd8082dd7d68542b9bb4ecd5", "0xa6016916146c2685c46e8fdd24186394e2d5496e77e08c0c6a709d4cd7dfa97f1efcef94922b89196819076a91ad37b5", "0xb778e7367ded3b6eab53d5fc257f7a87e8faf74a593900f2f517220add2125be3f6142022660d8181df8d164ad9441ce", "0x8581b2d36abe6f553add4d24be761bec1b8efaa2929519114346615380b3c55b59e6ad86990e312f7e234d0203bdf59b", "0x9917e74fd45c3f71a829ff5498a7f6b5599b48c098dda2339bf04352bfc7f368ccf1a407f5835901240e76452ae807d7", "0xafd196ce6f9335069138fd2e3d133134da253978b4ce373152c0f26affe77a336505787594022e610f8feb722f7cc1fb", "0xa477491a1562e329764645e8f24d8e228e5ef28c9f74c6b5b3abc4b6a562c15ffb0f680d372aed04d9e1bf944dece7be", "0x9767440d58c57d3077319d3a330e5322b9ba16981ec74a5a14d53462eab59ae7fd2b14025bfc63b268862094acb444e6", "0x80986d921be3513ef69264423f351a61cb48390c1be8673aee0f089076086aaebea7ebe268fd0aa7182695606116f679", "0xa9554c5c921c07b450ee04e34ec58e054ac1541b26ce2ce5a393367a97348ba0089f53db6660ad76b60278b66fd12e3e", "0x95097e7d2999b3e84bf052c775581cf361325325f4a50192521d8f4693c830bed667d88f482dc1e3f833aa2bd22d2cbf", "0x9014c91d0f85aefd28436b5228c12f6353c055a9326c7efbf5e071e089e2ee7c070fcbc84c5fafc336cbb8fa6fec1ca1", "0x90f57ba36ee1066b55d37384942d8b57ae00f3cf9a3c1d6a3dfee1d1af42d4b5fa9baeb0cd7e46687d1d6d090ddb931d", "0x8e4b1db12fd760a17214c9e47f1fce6e43c0dbb4589a827a13ac61aaae93759345697bb438a00edab92e0b7b62414683", "0x8022a959a513cdc0e9c705e0fc04eafd05ff37c867ae0f31f6d01cddd5df86138a426cab2ff0ac8ff03a62e20f7e8f51", "0x914e9a38829834c7360443b8ed86137e6f936389488eccf05b4b4db7c9425611705076ecb3f27105d24b85c852be7511", "0x957fb10783e2bd0db1ba66b18e794df710bc3b2b05776be146fa5863c15b1ebdd39747b1a95d9564e1772cdfc4f37b8a", "0xb6307028444daed8ed785ac9d0de76bc3fe23ff2cc7e48102553613bbfb5afe0ebe45e4212a27021c8eb870721e62a1f", "0x8f76143597777d940b15a01b39c5e1b045464d146d9a30a6abe8b5d3907250e6c7f858ff2308f8591e8b0a7b3f3c568a", "0x96163138ac0ce5fd00ae9a289648fd9300a0ca0f63a88481d703ecd281c06a52a3b5178e849e331f9c85ca4ba398f4cc", "0xa63ef47c3e18245b0482596a09f488a716df3cbd0f9e5cfabed0d742843e65db8961c556f45f49762f3a6ac8b627b3ef", "0x8cb595466552e7c4d42909f232d4063e0a663a8ef6f6c9b7ce3a0542b2459cde04e0e54c7623d404acb5b82775ac04f6", "0xb47fe69960eb45f399368807cff16d941a5a4ebad1f5ec46e3dc8a2e4d598a7e6114d8f0ca791e9720fd786070524e2b", "0x89eb5ff83eea9df490e5beca1a1fbbbbcf7184a37e2c8c91ede7a1e654c81e8cd41eceece4042ea7918a4f4646b67fd6", "0xa84f5d155ed08b9054eecb15f689ba81e44589e6e7207a99790c598962837ca99ec12344105b16641ca91165672f7153", "0xa6cc8f25c2d5b2d2f220ec359e6a37a52b95fa6af6e173c65e7cd55299eff4aa9e6d9e6f2769e6459313f1f2aecb0fab", "0xafcde944411f017a9f7979755294981e941cc41f03df5e10522ef7c7505e5f1babdd67b3bf5258e8623150062eb41d9b", "0x8fab39f39c0f40182fcd996ade2012643fe7731808afbc53f9b26900b4d4d1f0f5312d9d40b3df8baa4739970a49c732", "0xae193af9726da0ebe7df1f9ee1c4846a5b2a7621403baf8e66c66b60f523e719c30c6b4f897bb14b27d3ff3da8392eeb", "0x8ac5adb82d852eba255764029f42e6da92dcdd0e224d387d1ef94174038db9709ac558d90d7e7c57ad4ce7f89bbfc38c", "0xa2066b3458fdf678ee487a55dd5bfb74fde03b54620cb0e25412a89ee28ad0d685e309a51e3e4694be2fa6f1593a344c", "0x88d031745dd0ae07d61a15b594be5d4b2e2a29e715d081649ad63605e3404b0c3a5353f0fd9fad9c05c18e93ce674fa1", "0x8283cfb0ef743a043f2b77ecaeba3005e2ca50435585b5dd24777ee6bce12332f85e21b446b536da38508807f0f07563", "0xb376de22d5f6b0af0b59f7d9764561f4244cf8ffe22890ecd3dcf2ff1832130c9b821e068c9d8773136f4796721e5963", "0xae3afc50c764f406353965363840bf28ee85e7064eb9d5f0bb3c31c64ab10f48c853e942ee2c9b51bae59651eaa08c2f", "0x948b204d103917461a01a6c57a88f2d66b476eae5b00be20ec8c747650e864bc8a83aee0aff59cb7584b7a3387e0ee48", "0x81ab098a082b07f896c5ffd1e4446cb7fb44804cbbf38d125208b233fc82f8ec9a6a8d8dd1c9a1162dc28ffeec0dde50", "0xa149c6f1312821ced2969268789a3151bdda213451760b397139a028da609c4134ac083169feb0ee423a0acafd10eceb", "0xb0ac9e27a5dadaf523010f730b28f0ebac01f460d3bbbe277dc9d44218abb5686f4fac89ae462682fef9edbba663520a", "0x8d0e0073cca273daaaa61b6fc54bfe5a009bc3e20ae820f6c93ba77b19eca517d457e948a2de5e77678e4241807157cb", "0xad61d3a2edf7c7533a04964b97499503fd8374ca64286dba80465e68fe932e96749b476f458c6fc57cb1a7ca85764d11", "0x90eb5e121ae46bc01a30881eaa556f46bd8457a4e80787cf634aab355082de34ac57d7f497446468225f7721e68e2a47", "0x8cdac557de7c42d1f3780e33dec1b81889f6352279be81c65566cdd4952d4c15d79e656cbd46035ab090b385e90245ef", "0x82b67e61b88b84f4f4d4f65df37b3e3dcf8ec91ea1b5c008fdccd52da643adbe6468a1cfdb999e87d195afe2883a3b46", "0x8503b467e8f5d6048a4a9b78496c58493a462852cab54a70594ae3fd064cfd0deb4b8f336a262155d9fedcaa67d2f6fd", "0x8db56c5ac763a57b6ce6832930c57117058e3e5a81532b7d19346346205e2ec614eb1a2ee836ef621de50a7bc9b7f040", "0xad344699198f3c6e8c0a3470f92aaffc805b76266734414c298e10b5b3797ca53578de7ccb2f458f5e0448203f55282b", "0x80602032c43c9e2a09154cc88b83238343b7a139f566d64cb482d87436b288a98f1ea244fd3bff8da3c398686a900c14", "0xa6385bd50ecd548cfb37174cdbb89e10025b5cadaf3cff164c95d7aef5a33e3d6a9bf0c681b9e11db9ef54ebeee2a0c1", "0xabf2d95f4aa34b0581eb9257a0cc8462b2213941a5deb8ba014283293e8b36613951b61261cc67bbd09526a54cbbff76", "0xa3d5de52f48df72c289ff713e445991f142390798cd42bd9d9dbefaee4af4f5faf09042d126b975cf6b98711c3072553", "0x8e627302ff3d686cff8872a1b7c2a57b35f45bf2fc9aa42b049d8b4d6996a662b8e7cbac6597f0cb79b0cc4e29fbf133", "0x8510702e101b39a1efbf4e504e6123540c34b5689645e70d0bac1ecc1baf47d86c05cef6c4317a4e99b4edaeb53f2d00", "0xaa173f0ecbcc6088f878f8726d317748c81ebf501bba461f163b55d66099b191ec7c55f7702f351a9c8eb42cfa3280e2", "0xb560a697eafab695bcef1416648a0a664a71e311ecbe5823ae903bd0ed2057b9d7574b9a86d3fe22aa3e6ddce38ea513", "0x8df6304a3d9cf40100f3f687575419c998cd77e5cc27d579cf4f8e98642de3609af384a0337d145dd7c5635172d26a71", "0x8105c7f3e4d30a29151849673853b457c1885c186c132d0a98e63096c3774bc9deb956cf957367e633d0913680bda307", "0x95373fc22c0917c3c2044ac688c4f29a63ed858a45c0d6d2d0fe97afd6f532dcb648670594290c1c89010ecc69259bef", "0x8c2fae9bcadab341f49b55230310df93cac46be42d4caa0d42e45104148a91e527af1b4209c0d972448162aed28fab64", "0xb05a77baab70683f76209626eaefdda2d36a0b66c780a20142d23c55bd479ddd4ad95b24579384b6cf62c8eb4c92d021", "0x8e6bc6a7ea2755b4aaa19c1c1dee93811fcde514f03485fdc3252f0ab7f032c315614f6336e57cea25dcfb8fb6084eeb", "0xb656a27d06aade55eadae2ad2a1059198918ea6cc3fd22c0ed881294d34d5ac7b5e4700cc24350e27d76646263b223aa", "0xa296469f24f6f56da92d713afcd4dd606e7da1f79dc4e434593c53695847eefc81c7c446486c4b3b8c8d00c90c166f14", "0x87a326f57713ac2c9dffeb3af44b9f3c613a8f952676fc46343299122b47ee0f8d792abaa4b5db6451ced5dd153aabd0", "0xb689e554ba9293b9c1f6344a3c8fcb6951d9f9eac4a2e2df13de021aade7c186be27500e81388e5b8bcab4c80f220a31", "0x87ae0aa0aa48eac53d1ca5a7b93917de12db9e40ceabf8fdb40884ae771cfdf095411deef7c9f821af0b7070454a2608", "0xa71ffa7eae8ace94e6c3581d4cb2ad25d48cbd27edc9ec45baa2c8eb932a4773c3272b2ffaf077b40f76942a1f3af7f2", "0x94c218c91a9b73da6b7a495b3728f3028df8ad9133312fc0c03e8c5253b7ccb83ed14688fd4602e2fd41f29a0bc698bd", "0xae1e77b90ca33728af07a4c03fb2ef71cd92e2618e7bf8ed4d785ce90097fc4866c29999eb84a6cf1819d75285a03af2", "0xb7a5945b277dab9993cf761e838b0ac6eaa903d7111fca79f9fde3d4285af7a89bf6634a71909d095d7619d913972c9c", "0x8c43b37be02f39b22029b20aca31bff661abce4471dca88aa3bddefd9c92304a088b2dfc8c4795acc301ca3160656af2", "0xb32e5d0fba024554bd5fe8a793ebe8003335ddd7f585876df2048dcf759a01285fecb53daae4950ba57f3a282a4d8495", "0x85ea7fd5e10c7b659df5289b2978b2c89e244f269e061b9a15fcab7983fc1962b63546e82d5731c97ec74b6804be63ef", "0x96b89f39181141a7e32986ac02d7586088c5a9662cec39843f397f3178714d02f929af70630c12cbaba0268f8ba2d4fa", "0x929ab1a2a009b1eb37a2817c89696a06426529ebe3f306c586ab717bd34c35a53eca2d7ddcdef36117872db660024af9", "0xa696dccf439e9ca41511e16bf3042d7ec0e2f86c099e4fc8879d778a5ea79e33aa7ce96b23dc4332b7ba26859d8e674d", "0xa8fe69a678f9a194b8670a41e941f0460f6e2dbc60470ab4d6ae2679cc9c6ce2c3a39df2303bee486dbfde6844e6b31a", "0x95f58f5c82de2f2a927ca99bf63c9fc02e9030c7e46d0bf6b67fe83a448d0ae1c99541b59caf0e1ccab8326231af09a5", "0xa57badb2c56ca2c45953bd569caf22968f76ed46b9bac389163d6fe22a715c83d5e94ae8759b0e6e8c2f27bff7748f3f", "0x868726fd49963b24acb5333364dffea147e98f33aa19c7919dc9aca0fd26661cfaded74ede7418a5fadbe7f5ae67b67b", "0xa8d8550dcc64d9f1dd7bcdab236c4122f2b65ea404bb483256d712c7518f08bb028ff8801f1da6aed6cbfc5c7062e33b", "0x97e25a87dae23155809476232178538d4bc05d4ff0882916eb29ae515f2a62bfce73083466cc0010ca956aca200aeacc", "0xb4ea26be3f4bd04aa82d7c4b0913b97bcdf5e88b76c57eb1a336cbd0a3eb29de751e1bc47c0e8258adec3f17426d0c71", "0x99ee555a4d9b3cf2eb420b2af8e3bc99046880536116d0ce7193464ac40685ef14e0e3c442f604e32f8338cb0ef92558", "0x8c64efa1da63cd08f319103c5c7a761221080e74227bbc58b8fb35d08aa42078810d7af3e60446cbaff160c319535648", "0x8d9fd88040076c28420e3395cbdfea402e4077a3808a97b7939d49ecbcf1418fe50a0460e1c1b22ac3f6e7771d65169a", "0xae3c19882d7a9875d439265a0c7003c8d410367627d21575a864b9cb4918de7dbdb58a364af40c5e045f3df40f95d337", "0xb4f7bfacab7b2cafe393f1322d6dcc6f21ffe69cd31edc8db18c06f1a2b512c27bd0618091fd207ba8df1808e9d45914", "0x94f134acd0007c623fb7934bcb65ef853313eb283a889a3ffa79a37a5c8f3665f3d5b4876bc66223610c21dc9b919d37", "0xaa15f74051171daacdc1f1093d3f8e2d13da2833624b80a934afec86fc02208b8f55d24b7d66076444e7633f46375c6a", "0xa32d6bb47ef9c836d9d2371807bafbbbbb1ae719530c19d6013f1d1f813c49a60e4fa51d83693586cba3a840b23c0404", "0xb61b3599145ea8680011aa2366dc511a358b7d67672d5b0c5be6db03b0efb8ca5a8294cf220ea7409621f1664e00e631", "0x859cafc3ee90b7ececa1ed8ef2b2fc17567126ff10ca712d5ffdd16aa411a5a7d8d32c9cab1fbf63e87dce1c6e2f5f53", "0xa2fef1b0b2874387010e9ae425f3a9676d01a095d017493648bcdf3b31304b087ccddb5cf76abc4e1548b88919663b6b", "0x939e18c73befc1ba2932a65ede34c70e4b91e74cc2129d57ace43ed2b3af2a9cc22a40fbf50d79a63681b6d98852866d", "0xb3b4259d37b1b14aee5b676c9a0dd2d7f679ab95c120cb5f09f9fbf10b0a920cb613655ddb7b9e2ba5af4a221f31303c", "0x997255fe51aaca6e5a9cb3359bcbf25b2bb9e30649bbd53a8a7c556df07e441c4e27328b38934f09c09d9500b5fabf66", "0xabb91be2a2d860fd662ed4f1c6edeefd4da8dc10e79251cf87f06029906e7f0be9b486462718f0525d5e049472692cb7", "0xb2398e593bf340a15f7801e1d1fbda69d93f2a32a889ec7c6ae5e8a37567ac3e5227213c1392ee86cfb3b56ec2787839", "0x8ddf10ccdd72922bed36829a36073a460c2118fc7a56ff9c1ac72581c799b15c762cb56cb78e3d118bb9f6a7e56cb25e", "0x93e6bc0a4708d16387cacd44cf59363b994dc67d7ada7b6d6dbd831c606d975247541b42b2a309f814c1bfe205681fc6", "0xb93fc35c05998cffda2978e12e75812122831523041f10d52f810d34ff71944979054b04de0117e81ddf5b0b4b3e13c0", "0x92221631c44d60d68c6bc7b287509f37ee44cbe5fdb6935cee36b58b17c7325098f98f7910d2c3ca5dc885ad1d6dabc7", "0xa230124424a57fad3b1671f404a94d7c05f4c67b7a8fbacfccea28887b78d7c1ed40b92a58348e4d61328891cd2f6cee", "0xa6a230edb8518a0f49d7231bc3e0bceb5c2ac427f045819f8584ba6f3ae3d63ed107a9a62aad543d7e1fcf1f20605706", "0x845be1fe94223c7f1f97d74c49d682472585d8f772762baad8a9d341d9c3015534cc83d102113c51a9dea2ab10d8d27b", "0xb44262515e34f2db597c8128c7614d33858740310a49cdbdf9c8677c5343884b42c1292759f55b8b4abc4c86e4728033", "0x805592e4a3cd07c1844bc23783408310accfdb769cca882ad4d07d608e590a288b7370c2cb327f5336e72b7083a0e30f", "0x95153e8b1140df34ee864f4ca601cb873cdd3efa634af0c4093fbaede36f51b55571ab271e6a133020cd34db8411241f", "0x82878c1285cfa5ea1d32175c9401f3cc99f6bb224d622d3fd98cc7b0a27372f13f7ab463ce3a33ec96f9be38dbe2dfe3", "0xb7588748f55783077c27fc47d33e20c5c0f5a53fc0ac10194c003aa09b9f055d08ec971effa4b7f760553997a56967b3", "0xb36b4de6d1883b6951f59cfae381581f9c6352fcfcf1524fccdab1571a20f80441d9152dc6b48bcbbf00371337ca0bd5", "0x89c5523f2574e1c340a955cbed9c2f7b5fbceb260cb1133160dabb7d41c2f613ec3f6e74bbfab3c4a0a6f0626dbe068f", "0xa52f58cc39f968a9813b1a8ddc4e83f4219e4dd82c7aa1dd083bea7edf967151d635aa9597457f879771759b876774e4", "0x8300a67c2e2e123f89704abfde095463045dbd97e20d4c1157bab35e9e1d3d18f1f4aaba9cbe6aa2d544e92578eaa1b6", "0xac6a7f2918768eb6a43df9d3a8a04f8f72ee52f2e91c064c1c7d75cad1a3e83e5aba9fe55bb94f818099ac91ccf2e961", "0x8d64a2b0991cf164e29835c8ddef6069993a71ec2a7de8157bbfa2e00f6367be646ed74cbaf524f0e9fe13fb09fa15fd", "0x8b2ffe5a545f9f680b49d0a9797a4a11700a2e2e348c34a7a985fc278f0f12def6e06710f40f9d48e4b7fbb71e072229", "0x8ab8f71cd337fa19178924e961958653abf7a598e3f022138b55c228440a2bac4176cea3aea393549c03cd38a13eb3fc", "0x8419d28318c19ea4a179b7abb43669fe96347426ef3ac06b158d79c0acf777a09e8e770c2fb10e14b3a0421705990b23", "0x8bacdac310e1e49660359d0a7a17fe3d334eb820e61ae25e84cb52f863a2f74cbe89c2e9fc3283745d93a99b79132354", "0xb57ace3fa2b9f6b2db60c0d861ace7d7e657c5d35d992588aeed588c6ce3a80b6f0d49f8a26607f0b17167ab21b675e4", "0x83e265cde477f2ecc164f49ddc7fb255bb05ff6adc347408353b7336dc3a14fdedc86d5a7fb23f36b8423248a7a67ed1", "0xa60ada971f9f2d79d436de5d3d045f5ab05308cae3098acaf5521115134b2a40d664828bb89895840db7f7fb499edbc5", "0xa63eea12efd89b62d3952bf0542a73890b104dd1d7ff360d4755ebfa148fd62de668edac9eeb20507967ea37fb220202", "0xa0275767a270289adc991cc4571eff205b58ad6d3e93778ddbf95b75146d82517e8921bd0d0564e5b75fa0ccdab8e624", "0xb9b03fd3bf07201ba3a039176a965d736b4ef7912dd9e9bf69fe1b57c330a6aa170e5521fe8be62505f3af81b41d7806", "0xa95f640e26fb1106ced1729d6053e41a16e4896acac54992279ff873e5a969aad1dcfa10311e28b8f409ac1dab7f03bb", "0xb144778921742418053cb3c70516c63162c187f00db2062193bb2c14031075dbe055d020cde761b26e8c58d0ea6df2c1", "0x8432fbb799e0435ef428d4fefc309a05dd589bce74d7a87faf659823e8c9ed51d3e42603d878e80f439a38be4321c2fa", "0xb08ddef14e42d4fd5d8bf39feb7485848f0060d43b51ed5bdda39c05fe154fb111d29719ee61a23c392141358c0cfcff", "0x8ae3c5329a5e025b86b5370e06f5e61177df4bda075856fade20a17bfef79c92f54ed495f310130021ba94fb7c33632b", "0x92b6d3c9444100b4d7391febfc1dddaa224651677c3695c47a289a40d7a96d200b83b64e6d9df51f534564f272a2c6c6", "0xb432bc2a3f93d28b5e506d68527f1efeb2e2570f6be0794576e2a6ef9138926fdad8dd2eabfa979b79ab7266370e86bc", "0x8bc315eacedbcfc462ece66a29662ca3dcd451f83de5c7626ef8712c196208fb3d8a0faf80b2e80384f0dd9772f61a23", "0xa72375b797283f0f4266dec188678e2b2c060dfed5880fc6bb0c996b06e91a5343ea2b695adaab0a6fd183b040b46b56", "0xa43445036fbaa414621918d6a897d3692fdae7b2961d87e2a03741360e45ebb19fcb1703d23f1e15bb1e2babcafc56ac", "0xb9636b2ffe305e63a1a84bd44fb402442b1799bd5272638287aa87ca548649b23ce8ce7f67be077caed6aa2dbc454b78", "0x99a30bf0921d854c282b83d438a79f615424f28c2f99d26a05201c93d10378ab2cd94a792b571ddae5d4e0c0013f4006", "0x8648e3c2f93d70b392443be116b48a863e4b75991bab5db656a4ef3c1e7f645e8d536771dfe4e8d1ceda3be8d32978b0", "0xab50dc9e6924c1d2e9d2e335b2d679fc7d1a7632e84964d3bac0c9fe57e85aa5906ec2e7b0399d98ddd022e9b19b5904", "0xab729328d98d295f8f3272afaf5d8345ff54d58ff9884da14f17ecbdb7371857fdf2f3ef58080054e9874cc919b46224", "0x83fa5da7592bd451cad3ad7702b4006332b3aae23beab4c4cb887fa6348317d234bf62a359e665b28818e5410c278a09", "0x8bdbff566ae9d368f114858ef1f009439b3e9f4649f73efa946e678d6c781d52c69af195df0a68170f5f191b2eac286b", "0x91245e59b4425fd4edb2a61d0d47c1ccc83d3ced8180de34887b9655b5dcda033d48cde0bdc3b7de846d246c053a02e8", "0xa2cb00721e68f1cad8933947456f07144dc69653f96ceed845bd577d599521ba99cdc02421118971d56d7603ed118cbf", "0xaf8cd66d303e808b22ec57860dd909ca64c27ec2c60e26ffecfdc1179d8762ffd2739d87b43959496e9fee4108df71df", "0x9954136812dffcd5d3f167a500e7ab339c15cfc9b3398d83f64b0daa3dd5b9a851204f424a3493b4e326d3de81e50a62", "0x93252254d12511955f1aa464883ad0da793f84d900fea83e1df8bca0f2f4cf5b5f9acbaec06a24160d33f908ab5fea38", "0x997cb55c26996586ba436a95566bd535e9c22452ca5d2a0ded2bd175376557fa895f9f4def4519241ff386a063f2e526", "0xa12c78ad451e0ac911260ade2927a768b50cb4125343025d43474e7f465cdc446e9f52a84609c5e7e87ae6c9b3f56cda", "0xa789d4ca55cbba327086563831b34487d63d0980ba8cf55197c016702ed6da9b102b1f0709ce3da3c53ff925793a3d73", "0xa5d76acbb76741ce85be0e655b99baa04f7f587347947c0a30d27f8a49ae78cce06e1cde770a8b618d3db402be1c0c4b", "0x873c0366668c8faddb0eb7c86f485718d65f8c4734020f1a18efd5fa123d3ea8a990977fe13592cd01d17e60809cb5ff", "0xb659b71fe70f37573ff7c5970cc095a1dc0da3973979778f80a71a347ef25ad5746b2b9608bad4ab9a4a53a4d7df42d7", "0xa34cbe05888e5e5f024a2db14cb6dcdc401a9cbd13d73d3c37b348f68688f87c24ca790030b8f84fef9e74b4eab5e412", "0x94ce8010f85875c045b0f014db93ef5ab9f1f6842e9a5743dce9e4cb872c94affd9e77c1f1d1ab8b8660b52345d9acb9", "0xadefa9b27a62edc0c5b019ddd3ebf45e4de846165256cf6329331def2e088c5232456d3de470fdce3fa758bfdd387512", "0xa6b83821ba7c1f83cc9e4529cf4903adb93b26108e3d1f20a753070db072ad5a3689643144bdd9c5ea06bb9a7a515cd0", "0xa3a9ddedc2a1b183eb1d52de26718151744db6050f86f3580790c51d09226bf05f15111691926151ecdbef683baa992c", "0xa64bac89e7686932cdc5670d07f0b50830e69bfb8c93791c87c7ffa4913f8da881a9d8a8ce8c1a9ce5b6079358c54136", "0xa77b5a63452cb1320b61ab6c7c2ef9cfbcade5fd4727583751fb2bf3ea330b5ca67757ec1f517bf4d503ec924fe32fbd", "0x8746fd8d8eb99639d8cd0ca34c0d9c3230ed5a312aab1d3d925953a17973ee5aeb66e68667e93caf9cb817c868ea8f3d", "0x88a2462a26558fc1fbd6e31aa8abdc706190a17c27fdc4217ffd2297d1b1f3321016e5c4b2384c5454d5717dc732ed03", "0xb78893a97e93d730c8201af2e0d3b31cb923d38dc594ffa98a714e627c473d42ea82e0c4d2eeb06862ee22a9b2c54588", "0x920cc8b5f1297cf215a43f6fc843e379146b4229411c44c0231f6749793d40f07b9af7699fd5d21fd69400b97febe027", "0xa0f0eafce1e098a6b58c7ad8945e297cd93aaf10bc55e32e2e32503f02e59fc1d5776936577d77c0b1162cb93b88518b", "0x98480ba0064e97a2e7a6c4769b4d8c2a322cfc9a3b2ca2e67e9317e2ce04c6e1108169a20bd97692e1cb1f1423b14908", "0x83dbbb2fda7e287288011764a00b8357753a6a44794cc8245a2275237f11affdc38977214e463ad67aec032f3dfa37e9", "0x86442fff37598ce2b12015ff19b01bb8a780b40ad353d143a0f30a06f6d23afd5c2b0a1253716c855dbf445cc5dd6865", "0xb8a4c60c5171189414887847b9ed9501bff4e4c107240f063e2d254820d2906b69ef70406c585918c4d24f1dd052142b", "0x919f33a98e84015b2034b57b5ffe9340220926b2c6e45f86fd79ec879dbe06a148ae68b77b73bf7d01bd638a81165617", "0x95c13e78d89474a47fbc0664f6f806744b75dede95a479bbf844db4a7f4c3ae410ec721cb6ffcd9fa9c323da5740d5ae", "0xab7151acc41fffd8ec6e90387700bcd7e1cde291ea669567295bea1b9dd3f1df2e0f31f3588cd1a1c08af8120aca4921", "0x80e74c5c47414bd6eeef24b6793fb1fa2d8fb397467045fcff887c52476741d5bc4ff8b6d3387cb53ad285485630537f", "0xa296ad23995268276aa351a7764d36df3a5a3cffd7dbeddbcea6b1f77adc112629fdeffa0918b3242b3ccd5e7587e946", "0x813d2506a28a2b01cb60f49d6bd5e63c9b056aa56946faf2f33bd4f28a8d947569cfead3ae53166fc65285740b210f86", "0x924b265385e1646287d8c09f6c855b094daaee74b9e64a0dddcf9ad88c6979f8280ba30c8597b911ef58ddb6c67e9fe3", "0x8d531513c70c2d3566039f7ca47cd2352fd2d55b25675a65250bdb8b06c3843db7b2d29c626eed6391c238fc651cf350", "0x82b338181b62fdc81ceb558a6843df767b6a6e3ceedc5485664b4ea2f555904b1a45fbb35f6cf5d96f27da10df82a325", "0x92e62faaedea83a37f314e1d3cb4faaa200178371d917938e59ac35090be1db4b4f4e0edb78b9c991de202efe4f313d8", "0x99d645e1b642c2dc065bac9aaa0621bc648c9a8351efb6891559c3a41ba737bd155fb32d7731950514e3ecf4d75980e4", "0xb34a13968b9e414172fb5d5ece9a39cf2eb656128c3f2f6cc7a9f0c69c6bae34f555ecc8f8837dc34b5e470e29055c78", "0xa2a0bb7f3a0b23a2cbc6585d59f87cd7e56b2bbcb0ae48f828685edd9f7af0f5edb4c8e9718a0aaf6ef04553ba71f3b7", "0x8e1a94bec053ed378e524b6685152d2b52d428266f2b6eadd4bcb7c4e162ed21ab3e1364879673442ee2162635b7a4d8", "0x9944adaff14a85eab81c73f38f386701713b52513c4d4b838d58d4ffa1d17260a6d056b02334850ea9a31677c4b078bd", "0xa450067c7eceb0854b3eca3db6cf38669d72cb7143c3a68787833cbca44f02c0be9bfbe082896f8a57debb13deb2afb1", "0x8be4ad3ac9ef02f7df09254d569939757101ee2eda8586fefcd8c847adc1efe5bdcb963a0cafa17651befaafb376a531", "0x90f6de91ea50255f148ac435e08cf2ac00c772a466e38155bd7e8acf9197af55662c7b5227f88589b71abe9dcf7ba343", "0x86e5a24f0748b106dee2d4d54e14a3b0af45a96cbee69cac811a4196403ebbee17fd24946d7e7e1b962ac7f66dbaf610", "0xafdd96fbcda7aa73bf9eeb2292e036c25753d249caee3b9c013009cc22e10d3ec29e2aa6ddbb21c4e949b0c0bccaa7f4", "0xb5a4e7436d5473647c002120a2cb436b9b28e27ad4ebdd7c5f122b91597c507d256d0cbd889d65b3a908531936e53053", "0xb632414c3da704d80ac2f3e5e0e9f18a3637cdc2ebeb613c29300745582427138819c4e7b0bec3099c1b8739dac1807b", "0xa28df1464d3372ce9f37ef1db33cc010f752156afae6f76949d98cd799c0cf225c20228ae86a4da592d65f0cffe3951b", "0x898b93d0a31f7d3f11f253cb7a102db54b669fd150da302d8354d8e02b1739a47cb9bd88015f3baf12b00b879442464e", "0x96fb88d89a12049091070cb0048a381902965e67a8493e3991eaabe5d3b7ff7eecd5c94493a93b174df3d9b2c9511755", "0xb899cb2176f59a5cfba3e3d346813da7a82b03417cad6342f19cc8f12f28985b03bf031e856a4743fd7ebe16324805b0", "0xa60e2d31bc48e0c0579db15516718a03b73f5138f15037491f4dae336c904e312eda82d50862f4debd1622bb0e56d866", "0x979fc8b987b5cef7d4f4b58b53a2c278bd25a5c0ea6f41c715142ea5ff224c707de38451b0ad3aa5e749aa219256650a", "0xb2a75bff18e1a6b9cf2a4079572e41205741979f57e7631654a3c0fcec57c876c6df44733c9da3d863db8dff392b44a3", "0xb7a0f0e811222c91e3df98ff7f286b750bc3b20d2083966d713a84a2281744199e664879401e77470d44e5a90f3e5181", "0x82b74ba21c9d147fbc338730e8f1f8a6e7fc847c3110944eb17a48bea5e06eecded84595d485506d15a3e675fd0e5e62", "0xa7f44eef817d5556f0d1abcf420301217d23c69dd2988f44d91ea1f1a16c322263cbacd0f190b9ba22b0f141b9267b4f", "0xaadb68164ede84fc1cb3334b3194d84ba868d5a88e4c9a27519eef4923bc4abf81aab8114449496c073c2a6a0eb24114", "0xb5378605fabe9a8c12a5dc55ef2b1de7f51aedb61960735c08767a565793cea1922a603a6983dc25f7cea738d0f7c40d", "0xa97a4a5cd8d51302e5e670aee78fe6b5723f6cc892902bbb4f131e82ca1dfd5de820731e7e3367fb0c4c1922a02196e3", "0x8bdfeb15c29244d4a28896f2b2cb211243cd6a1984a3f5e3b0ebe5341c419beeab3304b390a009ffb47588018034b0ea", "0xa9af3022727f2aa2fca3b096968e97edad3f08edcbd0dbca107b892ae8f746a9c0485e0d6eb5f267999b23a845923ed0", "0x8e7594034feef412f055590fbb15b6322dc4c6ab7a4baef4685bd13d71a83f7d682b5781bdfa0d1c659489ce9c2b8000", "0x84977ca6c865ebee021c58106c1a4ad0c745949ecc5332948002fd09bd9b890524878d0c29da96fd11207621136421fe", "0x8687551a79158e56b2375a271136756313122132a6670fa51f99a1b5c229ed8eea1655a734abae13228b3ebfd2a825dd", "0xa0227d6708979d99edfc10f7d9d3719fd3fc68b0d815a7185b60307e4c9146ad2f9be2b8b4f242e320d4288ceeb9504c", "0x89f75583a16735f9dd8b7782a130437805b34280ccea8dac6ecaee4b83fe96947e7b53598b06fecfffdf57ffc12cc445", "0xa0056c3353227f6dd9cfc8e3399aa5a8f1d71edf25d3d64c982910f50786b1e395c508d3e3727ac360e3e040c64b5298", "0xb070e61a6d813626144b312ded1788a6d0c7cec650a762b2f8df6e4743941dd82a2511cd956a3f141fc81e15f4e092da", "0xb4e6db232e028a1f989bb5fc13416711f42d389f63564d60851f009dcffac01acfd54efa307aa6d4c0f932892d4e62b0", "0x89b5991a67db90024ddd844e5e1a03ef9b943ad54194ae0a97df775dde1addf31561874f4e40fbc37a896630f3bbda58", "0xad0e8442cb8c77d891df49cdb9efcf2b0d15ac93ec9be1ad5c3b3cca1f4647b675e79c075335c1f681d56f14dc250d76", "0xb5d55a6ae65bb34dd8306806cb49b5ccb1c83a282ee47085cf26c4e648e19a52d9c422f65c1cd7e03ca63e926c5e92ea", "0xb749501347e5ec07e13a79f0cb112f1b6534393458b3678a77f02ca89dca973fa7b30e55f0b25d8b92b97f6cb0120056", "0x94144b4a3ffc5eec6ba35ce9c245c148b39372d19a928e236a60e27d7bc227d18a8cac9983851071935d8ffb64b3a34f", "0x92bb4f9f85bc8c028a3391306603151c6896673135f8a7aefedd27acb322c04ef5dac982fc47b455d6740023e0dd3ea3", "0xb9633a4a101461a782fc2aa092e9dbe4e2ad00987578f18cd7cf0021a909951d60fe79654eb7897806795f93c8ff4d1c", "0x809f0196753024821b48a016eca5dbb449a7c55750f25981bb7a4b4c0e0846c09b8f6128137905055fc43a3f0deb4a74", "0xa27dc9cdd1e78737a443570194a03d89285576d3d7f3a3cf15cc55b3013e42635d4723e2e8fe1d0b274428604b630db9", "0x861f60f0462e04cd84924c36a28163def63e777318d00884ab8cb64c8df1df0bce5900342163edb60449296484a6c5bf", "0xb7bc23fb4e14af4c4704a944253e760adefeca8caee0882b6bbd572c84434042236f39ae07a8f21a560f486b15d82819", "0xb9a6eb492d6dd448654214bd01d6dc5ff12067a11537ab82023fc16167507ee25eed2c91693912f4155d1c07ed9650b3", "0x97678af29c68f9a5e213bf0fb85c265303714482cfc4c2c00b4a1e8a76ed08834ee6af52357b143a1ca590fb0265ea5a", "0x8a15b499e9eca5b6cac3070b5409e8296778222018ad8b53a5d1f6b70ad9bb10c68a015d105c941ed657bf3499299e33", "0xb487fefede2e8091f2c7bfe85770db2edff1db83d4effe7f7d87bff5ab1ace35e9b823a71adfec6737fede8d67b3c467", "0x8b51b916402aa2c437fce3bcad6dad3be8301a1a7eab9d163085b322ffb6c62abf28637636fe6114573950117fc92898", "0xb06a2106d031a45a494adec0881cb2f82275dff9dcdd2bc16807e76f3bec28a6734edd3d54f0be8199799a78cd6228ad", "0xaf0a185391bbe2315eb97feac98ad6dd2e5d931d012c621abd6e404a31cc188b286fef14871762190acf086482b2b5e2", "0x8e78ee8206506dd06eb7729e32fceda3bebd8924a64e4d8621c72e36758fda3d0001af42443851d6c0aea58562870b43", "0xa1ba52a569f0461aaf90b49b92be976c0e73ec4a2c884752ee52ffb62dd137770c985123d405dfb5de70692db454b54a", "0x8d51b692fa1543c51f6b62b9acb8625ed94b746ef96c944ca02859a4133a5629da2e2ce84e111a7af8d9a5b836401c64", "0xa7a20d45044cf6492e0531d0b8b26ffbae6232fa05a96ed7f06bdb64c2b0f5ca7ec59d5477038096a02579e633c7a3ff", "0x84df867b98c53c1fcd4620fef133ee18849c78d3809d6aca0fb6f50ff993a053a455993f216c42ab6090fa5356b8d564", "0xa7227c439f14c48e2577d5713c97a5205feb69acb0b449152842e278fa71e8046adfab468089c8b2288af1fc51fa945b", "0x855189b3a105670779997690876dfaa512b4a25a24931a912c2f0f1936971d2882fb4d9f0b3d9daba77eaf660e9d05d5", "0xb5696bd6706de51c502f40385f87f43040a5abf99df705d6aac74d88c913b8ecf7a99a63d7a37d9bdf3a941b9e432ff5", "0xab997beb0d6df9c98d5b49864ef0b41a2a2f407e1687dfd6089959757ba30ed02228940b0e841afe6911990c74d536c4", "0xb36b65f85546ebfdbe98823d5555144f96b4ab39279facd19c0de3b8919f105ba0315a0784dce4344b1bc62d8bb4a5a3", "0xb8371f0e4450788720ac5e0f6cd3ecc5413d33895083b2c168d961ec2b5c3de411a4cc0712481cbe8df8c2fa1a7af006", "0x98325d8026b810a8b7a114171ae59a57e8bbc9848e7c3df992efc523621729fd8c9f52114ce01d7730541a1ada6f1df1", "0x8d0e76dbd37806259486cd9a31bc8b2306c2b95452dc395546a1042d1d17863ef7a74c636b782e214d3aa0e8d717f94a", "0xa4e15ead76da0214d702c859fb4a8accdcdad75ed08b865842bd203391ec4cba2dcc916455e685f662923b96ee0c023f", "0x8618190972086ebb0c4c1b4a6c94421a13f378bc961cc8267a301de7390c5e73c3333864b3b7696d81148f9d4843fd02", "0x85369d6cc7342e1aa15b59141517d8db8baaaeb7ab9670f3ba3905353948d575923d283b7e5a05b13a30e7baf1208a86", "0x87c51ef42233c24a6da901f28c9a075d9ba3c625687c387ad6757b72ca6b5a8885e6902a3082da7281611728b1e45f26", "0xaa6348a4f71927a3106ad0ea8b02fc8d8c65531e4ab0bd0a17243e66f35afe252e40ab8eef9f13ae55a72566ffdaff5c", "0x96a3bc976e9d03765cc3fee275fa05b4a84c94fed6b767e23ca689394501e96f56f7a97cffddc579a6abff632bf153be", "0x97dbf96c6176379fdb2b888be4e757b2bca54e74124bd068d3fa1dbd82a011bbeb75079da38e0cd22a761fe208ecad9b", "0xb70cf0a1d14089a4129ec4e295313863a59da8c7e26bf74cc0e704ed7f0ee4d7760090d0ddf7728180f1bf2c5ac64955", "0x882d664714cc0ffe53cbc9bef21f23f3649824f423c4dbad1f893d22c4687ab29583688699efc4d5101aa08b0c3e267a", "0x80ecb7cc963e677ccaddbe3320831dd6ee41209acf4ed41b16dc4817121a3d86a1aac9c4db3d8c08a55d28257088af32", "0xa25ba667d832b145f9ce18c3f9b1bd00737aa36db020e1b99752c8ef7d27c6c448982bd8d352e1b6df266b8d8358a8d5", "0x83734841c13dee12759d40bdd209b277e743b0d08cc0dd1e0b7afd2d65bfa640400eefcf6be4a52e463e5b3d885eeac6", "0x848d16505b04804afc773aebabb51b36fd8aacfbb0e09b36c0d5d57df3c0a3b92f33e7d5ad0a7006ec46ebb91df42b8c", "0x909a8d793f599e33bb9f1dc4792a507a97169c87cd5c087310bc05f30afcd247470b4b56dec59894c0fb1d48d39bb54e", "0x8e558a8559df84a1ba8b244ece667f858095c50bb33a5381e60fcc6ba586b69693566d8819b4246a27287f16846c1dfa", "0x84d6b69729f5aaa000cd710c2352087592cfbdf20d5e1166977e195818e593fa1a50d1e04566be23163a2523dc1612f1", "0x9536d262b7a42125d89f4f32b407d737ba8d9242acfc99d965913ab3e043dcac9f7072a43708553562cac4cba841df30", "0x9598548923ca119d6a15fd10861596601dd1dedbcccca97bb208cdc1153cf82991ea8cc17686fbaa867921065265970c", "0xb87f2d4af6d026e4d2836bc3d390a4a18e98a6e386282ce96744603bab74974272e97ac2da281afa21885e2cbb3a8001", "0x991ece62bf07d1a348dd22191868372904b9f8cf065ae7aa4e44fd24a53faf6d851842e35fb472895963aa1992894918", "0xa8c53dea4c665b30e51d22ca6bc1bc78aaf172b0a48e64a1d4b93439b053877ec26cb5221c55efd64fa841bbf7d5aff4", "0x93487ec939ed8e740f15335b58617c3f917f72d07b7a369befd479ae2554d04deb240d4a14394b26192efae4d2f4f35d", "0xa44793ab4035443f8f2968a40e043b4555960193ffa3358d22112093aadfe2c136587e4139ffd46d91ed4107f61ea5e0", "0xb13fe033da5f0d227c75927d3dacb06dbaf3e1322f9d5c7c009de75cdcba5e308232838785ab69a70f0bedea755e003f", "0x970a29b075faccd0700fe60d1f726bdebf82d2cc8252f4a84543ebd3b16f91be42a75c9719a39c4096139f0f31393d58", "0xa4c3eb1f7160f8216fc176fb244df53008ff32f2892363d85254002e66e2de21ccfe1f3b1047589abee50f29b9d507e3", "0x8c552885eab04ba40922a8f0c3c38c96089c95ff1405258d3f1efe8d179e39e1295cbf67677894c607ae986e4e6b1fb0", "0xb3671746fa7f848c4e2ae6946894defadd815230b906b419143523cc0597bc1d6c0a4c1e09d49b66b4a2c11cde3a4de3", "0x937a249a95813a5e2ef428e355efd202e15a37d73e56cfb7e57ea9f943f2ce5ca8026f2f1fd25bf164ba89d07077d858", "0x83646bdf6053a04aa9e2f112499769e5bd5d0d10f2e13db3ca89bd45c0b3b7a2d752b7d137fb3909f9c62b78166c9339", "0xb4eac4b91e763666696811b7ed45e97fd78310377ebea1674b58a2250973f80492ac35110ed1240cd9bb2d17493d708c", "0x82db43a99bc6573e9d92a3fd6635dbbb249ac66ba53099c3c0c8c8080b121dd8243cd5c6e36ba0a4d2525bae57f5c89c", "0xa64d6a264a681b49d134c655d5fc7756127f1ee7c93d328820f32bca68869f53115c0d27fef35fe71f7bc4fdaed97348", "0x8739b7a9e2b4bc1831e7f04517771bc7cde683a5e74e052542517f8375a2f64e53e0d5ac925ef722327e7bb195b4d1d9", "0x8f337cdd29918a2493515ebb5cf702bbe8ecb23b53c6d18920cc22f519e276ca9b991d3313e2d38ae17ae8bdfa4f8b7e", "0xb0edeab9850e193a61f138ef2739fc42ceec98f25e7e8403bfd5fa34a7bc956b9d0898250d18a69fa4625a9b3d6129da", "0xa9920f26fe0a6d51044e623665d998745c9eca5bce12051198b88a77d728c8238f97d4196f26e43b24f8841500b998d0", "0x86e655d61502b979eeeeb6f9a7e1d0074f936451d0a1b0d2fa4fb3225b439a3770767b649256fe481361f481a8dbc276", "0x84d3b32fa62096831cc3bf013488a9f3f481dfe293ae209ed19585a03f7db8d961a7a9dd0db82bd7f62d612707575d9c", "0x81c827826ec9346995ffccf62a241e3b2d32f7357acd1b1f8f7a7dbc97022d3eb51b8a1230e23ce0b401d2e535e8cd78", "0x94a1e40c151191c5b055b21e86f32e69cbc751dcbdf759a48580951834b96a1eed75914c0d19a38aefd21fb6c8d43d0c", "0xab890222b44bc21b71f7c75e15b6c6e16bb03371acce4f8d4353ff3b8fcd42a14026589c5ed19555a3e15e4d18bfc3a3", "0xaccb0be851e93c6c8cc64724cdb86887eea284194b10e7a43c90528ed97e9ec71ca69c6fac13899530593756dd49eab2", "0xb630220aa9e1829c233331413ee28c5efe94ea8ea08d0c6bfd781955078b43a4f92915257187d8526873e6c919c6a1de", "0xadd389a4d358c585f1274b73f6c3c45b58ef8df11f9d11221f620e241bf3579fba07427b288c0c682885a700cc1fa28d", "0xa9fe6ca8bf2961a3386e8b8dcecc29c0567b5c0b3bcf3b0f9169f88e372b80151af883871fc5229815f94f43a6f5b2b0", "0xad839ae003b92b37ea431fa35998b46a0afc3f9c0dd54c3b3bf7a262467b13ff3c323ada1c1ae02ac7716528bdf39e3e", "0x9356d3fd0edcbbb65713c0f2a214394f831b26f792124b08c5f26e7f734b8711a87b7c4623408da6a091c9aef1f6af3c", "0x896b25b083c35ac67f0af3784a6a82435b0e27433d4d74cd6d1eafe11e6827827799490fb1c77c11de25f0d75f14e047", "0x8bfa019391c9627e8e5f05c213db625f0f1e51ec68816455f876c7e55b8f17a4f13e5aae9e3fb9e1cf920b1402ee2b40", "0x8ba3a6faa6a860a8f3ce1e884aa8769ceded86380a86520ab177ab83043d380a4f535fe13884346c5e51bee68da6ab41", "0xa8292d0844084e4e3bb7af92b1989f841a46640288c5b220fecfad063ee94e86e13d3d08038ec2ac82f41c96a3bfe14d", "0x8229bb030b2fc566e11fd33c7eab7a1bb7b49fed872ea1f815004f7398cb03b85ea14e310ec19e1f23e0bdaf60f8f76c", "0x8cfbf869ade3ec551562ff7f63c2745cc3a1f4d4dc853a0cd42dd5f6fe54228f86195ea8fe217643b32e9f513f34a545", "0xac52a3c8d3270ddfe1b5630159da9290a5ccf9ccbdef43b58fc0a191a6c03b8a5974cf6e2bbc7bd98d4a40a3581482d7", "0xab13decb9e2669e33a7049b8eca3ca327c40dea15ad6e0e7fa63ed506db1d258bc36ac88b35f65cae0984e937eb6575d", "0xb5e748eb1a7a1e274ff0cc56311c198f2c076fe4b7e73e5f80396fe85358549df906584e6bb2c8195b3e2be7736850a5", "0xb5cb911325d8f963c41f691a60c37831c7d3bbd92736efa33d1f77a22b3fde7f283127256c2f47e197571e6fe0b46149", "0x8a01dc6ed1b55f26427a014faa347130738b191a06b800e32042a46c13f60b49534520214359d68eb2e170c31e2b8672", "0xa72fa874866e19b2efb8e069328362bf7921ec375e3bcd6b1619384c3f7ee980f6cf686f3544e9374ff54b4d17a1629c", "0x8db21092f7c5f110fba63650b119e82f4b42a997095d65f08f8237b02dd66fdf959f788df2c35124db1dbd330a235671", "0x8c65d50433d9954fe28a09fa7ba91a70a590fe7ba6b3060f5e4be0f6cef860b9897fa935fb4ebc42133524eb071dd169", "0xb4614058e8fa21138fc5e4592623e78b8982ed72aa35ee4391b164f00c68d277fa9f9eba2eeefc890b4e86eba5124591", "0xab2ad3a1bce2fbd55ca6b7c23786171fe1440a97d99d6df4d80d07dd56ac2d7203c294b32fc9e10a6c259381a73f24a1", "0x812ae3315fdc18774a8da3713a4679e8ed10b9405edc548c00cacbe25a587d32040566676f135e4723c5dc25df5a22e9", "0xa464b75f95d01e5655b54730334f443c8ff27c3cb79ec7af4b2f9da3c2039c609908cd128572e1fd0552eb597e8cef8d", "0xa0db3172e93ca5138fe419e1c49a1925140999f6eff7c593e5681951ee0ec1c7e454c851782cbd2b8c9bc90d466e90e0", "0x806db23ba7d00b87d544eed926b3443f5f9c60da6b41b1c489fba8f73593b6e3b46ebfcab671ee009396cd77d5e68aa1", "0x8bfdf2c0044cc80260994e1c0374588b6653947b178e8b312be5c2a05e05767e98ea15077278506aee7df4fee1aaf89e", "0x827f6558c16841b5592ff089c9c31e31eb03097623524394813a2e4093ad2d3f8f845504e2af92195aaa8a1679d8d692", "0x925c4f8eab2531135cd71a4ec88e7035b5eea34ba9d799c5898856080256b4a15ed1a746e002552e2a86c9c157e22e83", "0xa9f9a368f0e0b24d00a35b325964c85b69533013f9c2cfad9708be5fb87ff455210f8cb8d2ce3ba58ca3f27495552899", "0x8ac0d3bebc1cae534024187e7c71f8927ba8fcc6a1926cb61c2b6c8f26bb7831019e635a376146c29872a506784a4aaa", "0x97c577be2cbbfdb37ad754fae9df2ada5fc5889869efc7e18a13f8e502fbf3f4067a509efbd46fd990ab47ce9a70f5a8", "0x935e7d82bca19f16614aa43b4a3474e4d20d064e4bfdf1cea2909e5c9ab72cfe3e54dc50030e41ee84f3588cebc524e9", "0x941aafc08f7c0d94cebfbb1f0aad5202c02e6e37f2c12614f57e727efa275f3926348f567107ee6d8914dd71e6060271", "0xaf0fbc1ba05b4b5b63399686df3619968be5d40073de0313cbf5f913d3d4b518d4c249cdd2176468ccaa36040a484f58", "0xa0c414f23f46ca6d69ce74c6f8a00c036cb0edd098af0c1a7d39c802b52cfb2d5dbdf93fb0295453d4646e2af7954d45", "0x909cf39e11b3875bb63b39687ae1b5d1f5a15445e39bf164a0b14691b4ddb39a8e4363f584ef42213616abc4785b5d66", "0xa92bac085d1194fbd1c88299f07a061d0bdd3f980b663e81e6254dbb288bf11478c0ee880e28e01560f12c5ccb3c0103", "0x841705cd5cd76b943e2b7c5e845b9dd3c8defe8ef67e93078d6d5e67ade33ad4b0fd413bc196f93b0a4073c855cd97d4", "0x8e7eb8364f384a9161e81d3f1d52ceca9b65536ae49cc35b48c3e2236322ba4ae9973e0840802d9fa4f4d82ea833544f", "0xaed3ab927548bc8bec31467ba80689c71a168e34f50dcb6892f19a33a099f5aa6b3f9cb79f5c0699e837b9a8c7f27efe", "0xb8fbf7696210a36e20edabd77839f4dfdf50d6d015cdf81d587f90284a9bcef7d2a1ff520728d7cc69a4843d6c20dedd", "0xa9d533769ce6830211c884ae50a82a7bf259b44ac71f9fb11f0296fdb3981e6b4c1753fe744647b247ebc433a5a61436", "0x8b4bdf90d33360b7f428c71cde0a49fb733badba8c726876945f58c620ce7768ae0e98fc8c31fa59d8955a4823336bb1", "0x808d42238e440e6571c59e52a35ae32547d502dc24fd1759d8ea70a7231a95859baf30b490a4ba55fa2f3aaa11204597", "0x85594701f1d2fee6dc1956bc44c7b31db93bdeec2f3a7d622c1a08b26994760773e3d57521a44cfd7e407ac3fd430429", "0xa66de045ce7173043a6825e9dc440ac957e2efb6df0a337f4f8003eb0c719d873a52e6eba3cb0d69d977ca37d9187674", "0x87a1c6a1fdff993fa51efa5c3ba034c079c0928a7d599b906336af7c2dcab9721ceaf3108c646490af9dff9a754f54b3", "0x926424223e462ceb75aed7c22ade8a7911a903b7e5dd4bc49746ddce8657f4616325cd12667d4393ac52cdd866396d0e", "0xb5dc96106593b42b30f06f0b0a1e0c1aafc70432e31807252d3674f0b1ea5e58eac8424879d655c9488d85a879a3e572", "0x997ca0987735cc716507cb0124b1d266d218b40c9d8e0ecbf26a1d65719c82a637ce7e8be4b4815d307df717bde7c72a", "0x92994d3f57a569b7760324bb5ae4e8e14e1633d175dab06aa57b8e391540e05f662fdc08b8830f489a063f59b689a688", "0xa8087fcc6aa4642cb998bea11facfe87eb33b90a9aa428ab86a4124ad032fc7d2e57795311a54ec9f55cc120ebe42df1", "0xa9bd7d1de6c0706052ca0b362e2e70e8c8f70f1f026ea189b4f87a08ce810297ebfe781cc8004430776c54c1a05ae90c", "0x856d33282e8a8e33a3d237fb0a0cbabaf77ba9edf2fa35a831fdafcadf620561846aa6cbb6bdc5e681118e1245834165", "0x9524a7aa8e97a31a6958439c5f3339b19370f03e86b89b1d02d87e4887309dbbe9a3a8d2befd3b7ed5143c8da7e0a8ad", "0x824fdf433e090f8acbd258ac7429b21f36f9f3b337c6d0b71d1416a5c88a767883e255b2888b7c906dd2e9560c4af24c", "0x88c7fee662ca7844f42ed5527996b35723abffd0d22d4ca203b9452c639a5066031207a5ae763dbc0865b3299d19b1ec", "0x919dca5c5595082c221d5ab3a5bc230f45da7f6dec4eb389371e142c1b9c6a2c919074842479c2844b72c0d806170c0c", "0xb939be8175715e55a684578d8be3ceff3087f60fa875fff48e52a6e6e9979c955efef8ff67cfa2b79499ea23778e33b0", "0x873b6db725e7397d11bc9bed9ac4468e36619135be686790a79bc6ed4249058f1387c9a802ea86499f692cf635851066", "0xaeae06db3ec47e9e5647323fa02fac44e06e59b885ad8506bf71b184ab3895510c82f78b6b22a5d978e8218e7f761e9f", "0xb99c0a8359c72ab88448bae45d4bf98797a26bca48b0d4460cd6cf65a4e8c3dd823970ac3eb774ae5d0cea4e7fadf33e", "0x8f10c8ec41cdfb986a1647463076a533e6b0eec08520c1562401b36bb063ac972aa6b28a0b6ce717254e35940b900e3c", "0xa106d9be199636d7add43b942290269351578500d8245d4aae4c083954e4f27f64740a3138a66230391f2d0e6043a8de", "0xa469997908244578e8909ff57cffc070f1dbd86f0098df3cfeb46b7a085cfecc93dc69ee7cad90ff1dc5a34d50fe580c", "0xa4ef087bea9c20eb0afc0ee4caba7a9d29dfa872137828c721391273e402fb6714afc80c40e98bbd8276d3836bffa080", "0xb07a013f73cd5b98dae0d0f9c1c0f35bff8a9f019975c4e1499e9bee736ca6fcd504f9bc32df1655ff333062382cff04", "0xb0a77188673e87cc83348c4cc5db1eecf6b5184e236220c8eeed7585e4b928db849944a76ec60ef7708ef6dac02d5592", "0xb1284b37e59b529f0084c0dacf0af6c0b91fc0f387bf649a8c74819debf606f7b07fc3e572500016fb145ec2b24e9f17", "0x97b20b5b4d6b9129da185adfbf0d3d0b0faeba5b9715f10299e48ea0521709a8296a9264ce77c275a59c012b50b6519a", "0xb9d37e946fae5e4d65c1fbfacc8a62e445a1c9d0f882e60cca649125af303b3b23af53c81d7bac544fb7fcfc7a314665", "0x8e5acaac379f4bb0127efbef26180f91ff60e4c525bc9b798fc50dfaf4fe8a5aa84f18f3d3cfb8baead7d1e0499af753", "0xb0c0b8ab1235bf1cda43d4152e71efc1a06c548edb964eb4afceb201c8af24240bf8ab5cae30a08604e77432b0a5faf0", "0x8cc28d75d5c8d062d649cbc218e31c4d327e067e6dbd737ec0a35c91db44fbbd0d40ec424f5ed79814add16947417572", "0x95ae6219e9fd47efaa9cb088753df06bc101405ba50a179d7c9f7c85679e182d3033f35b00dbba71fdcd186cd775c52e", "0xb5d28fa09f186ebc5aa37453c9b4d9474a7997b8ae92748ecb940c14868792292ac7d10ade01e2f8069242b308cf97e5", "0x8c922a0faa14cc6b7221f302df3342f38fc8521ec6c653f2587890192732c6da289777a6cd310747ea7b7d104af95995", "0xb9ad5f660b65230de54de535d4c0fcae5bc6b59db21dea5500fdc12eea4470fb8ea003690fdd16d052523418d5e01e8c", "0xa39a9dd41a0ff78c82979483731f1cd68d3921c3e9965869662c22e02dde3877802e180ba93f06e7346f96d9fa9261d2", "0x8b32875977ec372c583b24234c27ed73aef00cdff61eb3c3776e073afbdeade548de9497c32ec6d703ff8ad0a5cb7fe4", "0x9644cbe755a5642fe9d26cfecf170d3164f1848c2c2e271d5b6574a01755f3980b3fc870b98cf8528fef6ecef4210c16", "0x81ea9d1fdd9dd66d60f40ce0712764b99da9448ae0b300f8324e1c52f154e472a086dda840cb2e0b9813dc8ce8afd4b5", "0x906aaa4a7a7cdf01909c5cfbc7ded2abc4b869213cbf7c922d4171a4f2e637e56f17020b852ad339d83b8ac92f111666", "0x939b5f11acbdeff998f2a080393033c9b9d8d5c70912ea651c53815c572d36ee822a98d6dfffb2e339f29201264f2cf4", "0xaba4898bf1ccea9b9e2df1ff19001e05891581659c1cbbde7ee76c349c7fc7857261d9785823c9463a8aea3f40e86b38", "0x83ca1a56b8a0be4820bdb5a9346357c68f9772e43f0b887729a50d2eb2a326bbcede676c8bf2e51d7c89bbd8fdb778a6", "0x94e86e9fe6addfe2c3ee3a547267ed921f4230d877a85bb4442c2d9350c2fa9a9c54e6fe662de82d1a2407e4ab1691c2", "0xa0cc3bdef671a59d77c6984338b023fa2b431b32e9ed2abe80484d73edc6540979d6f10812ecc06d4d0c5d4eaca7183c", "0xb5343413c1b5776b55ea3c7cdd1f3af1f6bd802ea95effe3f2b91a523817719d2ecc3f8d5f3cc2623ace7e35f99ca967", "0x92085d1ed0ed28d8cabe3e7ff1905ed52c7ceb1eac5503760c52fb5ee3a726aba7c90b483c032acc3f166b083d7ec370", "0x8ec679520455275cd957fca8122724d287db5df7d29f1702a322879b127bff215e5b71d9c191901465d19c86c8d8d404", "0xb65eb2c63d8a30332eb24ee8a0c70156fc89325ebbb38bacac7cf3f8636ad8a472d81ccca80423772abc00192d886d8a", "0xa9fe1c060b974bee4d590f2873b28635b61bfcf614e61ff88b1be3eee4320f4874e21e8d666d8ac8c9aba672efc6ecae", "0xb3fe2a9a389c006a831dea7e777062df84b5c2803f9574d7fbe10b7e1c125817986af8b6454d6be9d931a5ac94cfe963", "0x95418ad13b734b6f0d33822d9912c4c49b558f68d08c1b34a0127fcfa666bcae8e6fda8832d2c75bb9170794a20e4d7c", "0xa9a7df761e7f18b79494bf429572140c8c6e9d456c4d4e336184f3f51525a65eb9582bea1e601bdb6ef8150b7ca736a5", "0xa0de03b1e75edf7998c8c1ac69b4a1544a6fa675a1941950297917366682e5644a4bda9cdeedfaf9473d7fccd9080b0c", "0xa61838af8d95c95edf32663a68f007d95167bf6e41b0c784a30b22d8300cfdd5703bd6d16e86396638f6db6ae7e42a85", "0x8866d62084d905c145ff2d41025299d8b702ac1814a7dec4e277412c161bc9a62fed735536789cb43c88693c6b423882", "0x91da22c378c81497fe363e7f695c0268443abee50f8a6625b8a41e865638a643f07b157ee566de09ba09846934b4e2d7", "0x941d21dd57c9496aa68f0c0c05507405fdd413acb59bc668ce7e92e1936c68ec4b065c3c30123319884149e88228f0b2", "0xa77af9b094bc26966ddf2bf9e1520c898194a5ccb694915950dadc204facbe3066d3d89f50972642d76b14884cfbaa21", "0x8e76162932346869f4618bde744647f7ab52ab498ad654bdf2a4feeb986ac6e51370841e5acbb589e38b6e7142bb3049", "0xb60979ace17d6937ece72e4f015da4657a443dd01cebc7143ef11c09e42d4aa8855999a65a79e2ea0067f31c9fc2ab0f", "0xb3e2ffdd5ee6fd110b982fd4fad4b93d0fca65478f986d086eeccb0804960bfaa1919afa743c2239973ea65091fe57d2", "0x8ce0ce05e7d7160d44574011da687454dbd3c8b8290aa671731b066e2c82f8cf2d63cb8e932d78c6122ec610e44660e6", "0xab005dd8d297045c39e2f72fb1c48edb501ccf3575d3d04b9817b3afee3f0bb0f3f53f64bda37d1d9cde545aae999bae", "0x95bd7edb4c4cd60e3cb8a72558845a3cce6bb7032ccdf33d5a49ebb6ddf203bc3c79e7b7e550735d2d75b04c8b2441e8", "0x889953ee256206284094e4735dbbb17975bafc7c3cb94c9fbfee4c3e653857bfd49e818f64a47567f721b98411a3b454", "0xb188423e707640ab0e75a061e0b62830cde8afab8e1ad3dae30db69ffae4e2fc005bababbdcbd7213b918ed4f70e0c14", "0xa97e0fafe011abd70d4f99a0b36638b3d6e7354284588f17a88970ed48f348f88392779e9a038c6cbc9208d998485072", "0x87db11014a91cb9b63e8dfaa82cdebca98272d89eb445ee1e3ff9dbaf2b3fad1a03b888cffc128e4fe208ed0dddece0f", "0xaad2e40364edd905d66ea4ac9d51f9640d6fda9a54957d26ba233809851529b32c85660fa401dbee3679ec54fa6dd966", "0x863e99336ca6edf03a5a259e59a2d0f308206e8a2fb320cfc0be06057366df8e0f94b33a28f574092736b3c5ada84270", "0xb34bcc56a057589f34939a1adc51de4ff6a9f4fee9c7fa9aa131e28d0cf0759a0c871b640162acdfbf91f3f1b59a3703", "0x935dd28f2896092995c5eff1618e5b6efe7a40178888d7826da9b0503c2d6e68a28e7fac1a334e166d0205f0695ef614", "0xb842cd5f8f5de5ca6c68cb4a5c1d7b451984930eb4cc18fd0934d52fdc9c3d2d451b1c395594d73bc3451432bfba653f", "0x9014537885ce2debad736bc1926b25fdab9f69b216bf024f589c49dc7e6478c71d595c3647c9f65ff980b14f4bb2283b", "0x8e827ccca1dd4cd21707140d10703177d722be0bbe5cac578db26f1ef8ad2909103af3c601a53795435b27bf95d0c9ed", "0x8a0b8ad4d466c09d4f1e9167410dbe2edc6e0e6229d4b3036d30f85eb6a333a18b1c968f6ca6d6889bb08fecde017ef4", "0x9241ee66c0191b06266332dc9161dede384c4bb4e116dbd0890f3c3790ec5566da4568243665c4725b718ac0f6b5c179", "0xaeb4d5fad81d2b505d47958a08262b6f1b1de9373c2c9ba6362594194dea3e002ab03b8cbb43f867be83065d3d370f19", "0x8781bc83bb73f7760628629fe19e4714b494dbed444c4e4e4729b7f6a8d12ee347841a199888794c2234f51fa26fc2b9", "0xb58864f0acd1c2afa29367e637cbde1968d18589245d9936c9a489c6c495f54f0113ecdcbe4680ac085dd3c397c4d0c3", "0x94a24284afaeead61e70f3e30f87248d76e9726759445ca18cdb9360586c60cc9f0ec1c397f9675083e0b56459784e2e", "0xaed358853f2b54dcbddf865e1816c2e89be12e940e1abfa661e2ee63ffc24a8c8096be2072fa83556482c0d89e975124", "0xb95374e6b4fc0765708e370bc881e271abf2e35c08b056a03b847e089831ef4fe3124b9c5849d9c276eb2e35b3daf264", "0xb834cdbcfb24c8f84bfa4c552e7fadc0028a140952fd69ed13a516e1314a4cd35d4b954a77d51a1b93e1f5d657d0315d", "0x8fb6d09d23bfa90e7443753d45a918d91d75d8e12ec7d016c0dfe94e5c592ba6aaf483d2f16108d190822d955ad9cdc3", "0xaa315cd3c60247a6ad4b04f26c5404c2713b95972843e4b87b5a36a89f201667d70f0adf20757ebe1de1b29ae27dda50", "0xa116862dca409db8beff5b1ccd6301cdd0c92ca29a3d6d20eb8b87f25965f42699ca66974dd1a355200157476b998f3b", "0xb4c2f5fe173c4dc8311b60d04a65ce1be87f070ac42e13cd19c6559a2931c6ee104859cc2520edebbc66a13dc7d30693", "0x8d4a02bf99b2260c334e7d81775c5cf582b00b0c982ce7745e5a90624919028278f5e9b098573bad5515ce7fa92a80c8", "0x8543493bf564ce6d97bd23be9bff1aba08bd5821ca834f311a26c9139c92a48f0c2d9dfe645afa95fec07d675d1fd53b", "0x9344239d13fde08f98cb48f1f87d34cf6abe8faecd0b682955382a975e6eed64e863fa19043290c0736261622e00045c", "0xaa49d0518f343005ca72b9e6c7dcaa97225ce6bb8b908ebbe7b1a22884ff8bfb090890364e325a0d414ad180b8f161d1", "0x907d7fd3e009355ab326847c4a2431f688627faa698c13c03ffdd476ecf988678407f029b8543a475dcb3dafdf2e7a9c", "0x845f1f10c6c5dad2adc7935f5cd2e2b32f169a99091d4f1b05babe7317b9b1cdce29b5e62f947dc621b9acbfe517a258", "0x8f3be8e3b380ea6cdf9e9c237f5e88fd5a357e5ded80ea1fc2019810814de82501273b4da38916881125b6fa0cfd4459", "0xb9c7f487c089bf1d20c822e579628db91ed9c82d6ca652983aa16d98b4270c4da19757f216a71b9c13ddee3e6e43705f", "0x8ba2d8c88ad2b872db104ea8ddbb006ec2f3749fd0e19298a804bb3a5d94de19285cc7fb19fee58a66f7851d1a66c39f", "0x9375ecd3ed16786fe161af5d5c908f56eeb467a144d3bbddfc767e90065b7c94fc53431adebecba2b6c9b5821184d36e", "0xa49e069bfadb1e2e8bff6a4286872e2a9765d62f0eaa4fcb0e5af4bbbed8be3510fb19849125a40a8a81d1e33e81c3eb", "0x9522cc66757b386aa6b88619525c8ce47a5c346d590bb3647d12f991e6c65c3ab3c0cfc28f0726b6756c892eae1672be", "0xa9a0f1f51ff877406fa83a807aeb17b92a283879f447b8a2159653db577848cc451cbadd01f70441e351e9ed433c18bc", "0x8ff7533dcff6be8714df573e33f82cf8e9f2bcaaa43e939c4759d52b754e502717950de4b4252fb904560fc31dce94a4", "0x959724671e265a28d67c29d95210e97b894b360da55e4cf16e6682e7912491ed8ca14bfaa4dce9c25a25b16af580494f", "0x92566730c3002f4046c737032487d0833c971e775de59fe02d9835c9858e2e3bc37f157424a69764596c625c482a2219", "0xa84b47ceff13ed9c3e5e9cdf6739a66d3e7c2bd8a6ba318fefb1a9aecf653bb2981da6733ddb33c4b0a4523acc429d23", "0xb4ddf571317e44f859386d6140828a42cf94994e2f1dcbcc9777f4eebbfc64fc1e160b49379acc27c4672b8e41835c5d", "0x8ab95c94072b853d1603fdd0a43b30db617d13c1d1255b99075198e1947bfa5f59aed2b1147548a1b5e986cd9173d15c", "0x89511f2eab33894fd4b3753d24249f410ff7263052c1fef6166fc63a79816656b0d24c529e45ccce6be28de6e375d916", "0xa0866160ca63d4f2be1b4ea050dac6b59db554e2ebb4e5b592859d8df339b46fd7cb89aaed0951c3ee540aee982c238a", "0x8fcc5cbba1b94970f5ff2eb1922322f5b0aa7d918d4b380c9e7abfd57afd8b247c346bff7b87af82efbce3052511cd1b", "0x99aeb2a5e846b0a2874cca02c66ed40d5569eb65ab2495bc3f964a092e91e1517941f2688e79f8cca49cd3674c4e06dc", "0xb7a096dc3bad5ca49bee94efd884aa3ff5615cf3825cf95fbe0ce132e35f46581d6482fa82666c7ef5f1643eaee8f1ca", "0x94393b1da6eaac2ffd186b7725eca582f1ddc8cdd916004657f8a564a7c588175cb443fc6943b39029f5bbe0add3fad8", "0x884b85fe012ccbcd849cb68c3ad832d83b3ef1c40c3954ffdc97f103b1ed582c801e1a41d9950f6bddc1d11f19d5ec76", "0xb00061c00131eded8305a7ce76362163deb33596569afb46fe499a7c9d7a0734c084d336b38d168024c2bb42b58e7660", "0xa439153ac8e6ca037381e3240e7ba08d056c83d7090f16ed538df25901835e09e27de2073646e7d7f3c65056af6e4ce7", "0x830fc9ca099097d1f38b90e6843dc86f702be9d20bdacc3e52cae659dc41df5b8d2c970effa6f83a5229b0244a86fe22", "0xb81ea2ffaaff2bb00dd59a9ab825ba5eed4db0d8ac9c8ed1a632ce8f086328a1cddd045fbe1ace289083c1325881b7e7", "0xb51ea03c58daf2db32c99b9c4789b183365168cb5019c72c4cc91ac30b5fb7311d3db76e6fa41b7cd4a8c81e2f6cdc94", "0xa4170b2c6d09ca5beb08318730419b6f19215ce6c631c854116f904be3bc30dd85a80c946a8ab054d3e307afaa3f8fbc", "0x897cc42ff28971ff54d2a55dd6b35cfb8610ac902f3c06e3a5cea0e0a257e870c471236a8e84709211c742a09c5601a6", "0xa18f2e98d389dace36641621488664ecbb422088ab03b74e67009b8b8acacaaa24fdcf42093935f355207d934adc52a8", "0x92adcfb678cc2ba19c866f3f2b988fdcb4610567f3ab436cc0cb9acaf5a88414848d71133ebdbec1983e38e6190f1b5f", "0xa86d43c2ce01b366330d3b36b3ca85f000c3548b8297e48478da1ee7d70d8576d4650cba7852ed125c0d7cb6109aa7f3", "0x8ed31ceed9445437d7732dce78a762d72ff32a7636bfb3fd7974b7ae15db414d8184a1766915244355deb354fbc5803b", "0x9268f70032584f416e92225d65af9ea18c466ebc7ae30952d56a4e36fd9ea811dde0a126da9220ba3c596ec54d8a335e", "0x9433b99ee94f2d3fbdd63b163a2bdf440379334c52308bd24537f7defd807145a062ff255a50d119a7f29f4b85d250e3", "0x90ce664f5e4628a02278f5cf5060d1a34f123854634b1870906e5723ac9afd044d48289be283b267d45fcbf3f4656aaf", "0xaaf21c4d59378bb835d42ae5c5e5ab7a3c8c36a59e75997989313197752b79a472d866a23683b329ea69b048b87fa13e", "0xb83c0589b304cec9ede549fde54f8a7c2a468c6657da8c02169a6351605261202610b2055c639b9ed2d5b8c401fb8f56", "0x9370f326ea0f170c2c05fe2c5a49189f20aec93b6b18a5572a818cd4c2a6adb359e68975557b349fb54f065d572f4c92", "0xac3232fa5ce6f03fca238bef1ce902432a90b8afce1c85457a6bee5571c033d4bceefafc863af04d4e85ac72a4d94d51", "0x80d9ea168ff821b22c30e93e4c7960ce3ad3c1e6deeebedd342a36d01bd942419b187e2f382dbfd8caa34cca08d06a48", "0xa387a3c61676fb3381eefa2a45d82625635a666e999aba30e3b037ec9e040f414f9e1ad9652abd3bcad63f95d85038db", "0xa1b229fe32121e0b391b0f6e0180670b9dc89d79f7337de4c77ea7ad0073e9593846f06797c20e923092a08263204416", "0x92164a9d841a2b828cedf2511213268b698520f8d1285852186644e9a0c97512cafa4bfbe29af892c929ebccd102e998", "0x82ee2fa56308a67c7db4fd7ef539b5a9f26a1c2cc36da8c3206ba4b08258fbb3cec6fe5cdbd111433fb1ba2a1e275927", "0x8c77bfe9e191f190a49d46f05600603fa42345592539b82923388d72392404e0b29a493a15e75e8b068dddcd444c2928", "0x80b927f93ccf79dcf5c5b20bcf5a7d91d7a17bc0401bb7cc9b53a6797feac31026eb114257621f5a64a52876e4474cc1", "0xb6b68b6501c37804d4833d5a063dd108a46310b1400549074e3cac84acc6d88f73948b7ad48d686de89c1ec043ae8c1a", "0xab3da00f9bdc13e3f77624f58a3a18fc3728956f84b5b549d62f1033ae4b300538e53896e2d943f160618e05af265117", "0xb6830e87233b8eace65327fdc764159645b75d2fd4024bf8f313b2dd5f45617d7ecfb4a0b53ccafb5429815a9a1adde6", "0xb9251cfe32a6dc0440615aadcd98b6b1b46e3f4e44324e8f5142912b597ee3526bea2431e2b0282bb58f71be5b63f65e", "0xaf8d70711e81cdddfb39e67a1b76643292652584c1ce7ce4feb1641431ad596e75c9120e85f1a341e7a4da920a9cdd94", "0x98cd4e996594e89495c078bfd52a4586b932c50a449a7c8dfdd16043ca4cda94dafbaa8ad1b44249c99bbcc52152506e", "0xb9fc6d1c24f48404a4a64fbe3e43342738797905db46e4132aee5f086aaa4c704918ad508aaefa455cfe1b36572e6242", "0xa365e871d30ba9291cedaba1be7b04e968905d003e9e1af7e3b55c5eb048818ae5b913514fb08b24fb4fbdccbb35d0b8", "0x93bf99510971ea9af9f1e364f1234c898380677c8e8de9b0dd24432760164e46c787bc9ec42a7ad450500706cf247b2d", "0xb872f825a5b6e7b9c7a9ddfeded3516f0b1449acc9b4fd29fc6eba162051c17416a31e5be6d3563f424d28e65bab8b8f", "0xb06b780e5a5e8eb4f4c9dc040f749cf9709c8a4c9ef15e925f442b696e41e5095db0778a6c73bcd329b265f2c6955c8b", "0x848f1a981f5fc6cd9180cdddb8d032ad32cdfa614fc750d690dbae36cc0cd355cbf1574af9b3ffc8b878f1b2fafb9544", "0xa03f48cbff3e9e8a3a655578051a5ae37567433093ac500ed0021c6250a51b767afac9bdb194ee1e3eac38a08c0eaf45", "0xb5be78ce638ff8c4aa84352b536628231d3f7558c5be3bf010b28feac3022e64691fa672f358c8b663904aebe24a54ed", "0xa9d4da70ff676fa55d1728ba6ab03b471fa38b08854d99e985d88c2d050102d8ccffbe1c90249a5607fa7520b15fe791", "0x8fe9f7092ffb0b69862c8e972fb1ecf54308c96d41354ed0569638bb0364f1749838d6d32051fff1599112978c6e229c", "0xae6083e95f37770ecae0df1e010456f165d96cfe9a7278c85c15cffd61034081ce5723e25e2bede719dc9341ec8ed481", "0xa260891891103089a7afbd9081ea116cfd596fd1015f5b65e10b0961eb37fab7d09c69b7ce4be8bf35e4131848fb3fe4", "0x8d729fa32f6eb9fd2f6a140bef34e8299a2f3111bffd0fe463aa8622c9d98bfd31a1df3f3e87cd5abc52a595f96b970e", "0xa30ec6047ae4bc7da4daa7f4c28c93aedb1112cfe240e681d07e1a183782c9ff6783ac077c155af23c69643b712a533f", "0xac830726544bfe7b5467339e5114c1a75f2a2a8d89453ce86115e6a789387e23551cd64620ead6283dfa4538eb313d86", "0x8445c135b7a48068d8ed3e011c6d818cfe462b445095e2fbf940301e50ded23f272d799eea47683fc027430ce14613ef", "0x95785411715c9ae9d8293ce16a693a2aa83e3cb1b4aa9f76333d0da2bf00c55f65e21e42e50e6c5772ce213dd7b4f7a0", "0xb273b024fa18b7568c0d1c4d2f0c4e79ec509dafac8c5951f14192d63ddbcf2d8a7512c1c1b615cc38fa3e336618e0c5", "0xa78b9d3ea4b6a90572eb27956f411f1d105fdb577ee2ffeec9f221da9b45db84bfe866af1f29597220c75e0c37a628d8", "0xa4be2bf058c36699c41513c4d667681ce161a437c09d81383244fc55e1c44e8b1363439d0cce90a3e44581fb31d49493", "0xb6eef13040f17dd4eba22aaf284d2f988a4a0c4605db44b8d2f4bf9567ac794550b543cc513c5f3e2820242dd704152e", "0x87eb00489071fa95d008c5244b88e317a3454652dcb1c441213aa16b28cd3ecaa9b22fec0bdd483c1df71c37119100b1", "0x92d388acdcb49793afca329cd06e645544d2269234e8b0b27d2818c809c21726bc9cf725651b951e358a63c83dedee24", "0xae27e219277a73030da27ab5603c72c8bd81b6224b7e488d7193806a41343dff2456132274991a4722fdb0ef265d04cd", "0x97583e08ecb82bbc27c0c8476d710389fa9ffbead5c43001bd36c1b018f29faa98de778644883e51870b69c5ffb558b5", "0x90a799a8ce73387599babf6b7da12767c0591cadd36c20a7990e7c05ea1aa2b9645654ec65308ee008816623a2757a6a", "0xa1b47841a0a2b06efd9ab8c111309cc5fc9e1d5896b3e42ed531f6057e5ade8977c29831ce08dbda40348386b1dcc06d", "0xb92b8ef59bbddb50c9457691bc023d63dfcc54e0fd88bd5d27a09e0d98ac290fc90e6a8f6b88492043bf7c87fac8f3e4", "0xa9d6240b07d62e22ec8ab9b1f6007c975a77b7320f02504fc7c468b4ee9cfcfd945456ff0128bc0ef2174d9e09333f8d", "0x8e96534c94693226dc32bca79a595ca6de503af635f802e86442c67e77564829756961d9b701187fe91318da515bf0e6", "0xb6ba290623cd8dd5c2f50931c0045d1cfb0c30877bc8fe58cbc3ff61ee8da100045a39153916efa1936f4aee0892b473", "0xb43baa7717fac02d4294f5b3bb5e58a65b3557747e3188b482410388daac7a9c177f762d943fd5dcf871273921213da8", "0xb9cf00f8fb5e2ef2b836659fece15e735060b2ea39b8e901d3dcbdcf612be8bf82d013833718c04cd46ffaa70b85f42e", "0x8017d0c57419e414cbba504368723e751ef990cc6f05dad7b3c2de6360adc774ad95512875ab8337d110bf39a42026fa", "0xae7401048b838c0dcd4b26bb6c56d79d51964a0daba780970b6c97daee4ea45854ea0ac0e4139b3fe60dac189f84df65", "0x887b237b0cd0f816b749b21db0b40072f9145f7896c36916296973f9e6990ede110f14e5976c906d08987c9836cca57f", "0xa88c3d5770148aee59930561ca1223aceb2c832fb5417e188dca935905301fc4c6c2c9270bc1dff7add490a125eb81c6", "0xb6cf9b02c0cd91895ad209e38c54039523f137b5848b9d3ad33ae43af6c20c98434952db375fe378de7866f2d0e8b18a", "0x84ef3d322ff580c8ad584b1fe4fe346c60866eb6a56e982ba2cf3b021ecb1fdb75ecc6c29747adda86d9264430b3f816", "0xa0561c27224baf0927ad144cb71e31e54a064c598373fcf0d66aebf98ab7af1d8e2f343f77baefff69a6da750a219e11", "0xaa5cc43f5b8162b016f5e1b61214c0c9d15b1078911c650b75e6cdfb49b85ee04c6739f5b1687d15908444f691f732de", "0xad4ac099b935589c7b8fdfdf3db332b7b82bb948e13a5beb121ebd7db81a87d278024a1434bcf0115c54ca5109585c3d", "0x8a00466abf3f109a1dcd19e643b603d3af23d42794ef8ca2514dd507ecea44a031ac6dbc18bd02f99701168b25c1791e", "0xb00b5900dfad79645f8bee4e5adc7b84eb22e5b1e67df77ccb505b7fc044a6c08a8ea5faca662414eb945f874f884cea", "0x950e204e5f17112250b22ea6bb8423baf522fc0af494366f18fe0f949f51d6e6812074a80875cf1ed9c8e7420058d541", "0x91e5cbf8bb1a1d50c81608c9727b414d0dd2fb467ebc92f100882a3772e54f94979cfdf8e373fdef7c7fcdd60fec9e00", "0xa093f6a857b8caaff80599c2e89c962b415ecbaa70d8fd973155fa976a284c6b29a855f5f7a3521134d00d2972755188", "0xb4d55a3551b00da54cc010f80d99ddd2544bde9219a3173dfaadf3848edc7e4056ab532fb75ac26f5f7141e724267663", "0xa03ea050fc9b011d1b04041b5765d6f6453a93a1819cd9bd6328637d0b428f08526466912895dcc2e3008ee58822e9a7", "0x99b12b3665e473d01bc6985844f8994fb65cb15745024fb7af518398c4a37ff215da8f054e8fdf3286984ae36a73ca5e", "0x9972c7e7a7fb12e15f78d55abcaf322c11249cd44a08f62c95288f34f66b51f146302bce750ff4d591707075d9123bd2", "0xa64b4a6d72354e596d87cda213c4fc2814009461570ccb27d455bbe131f8d948421a71925425b546d8cf63d5458cd64b", "0x91c215c73b195795ede2228b7ed1f6e37892e0c6b0f4a0b5a16c57aa1100c84df9239054a173b6110d6c2b7f4bf1ce52", "0x88807198910ec1303480f76a3683870246a995e36adaeadc29c22f0bdba8152fe705bd070b75de657b04934f7d0ccf80", "0xb37c0026c7b32eb02cacac5b55cb5fe784b8e48b2945c64d3037af83ece556a117f0ff053a5968c2f5fa230e291c1238", "0x94c768384ce212bc2387e91ce8b45e4ff120987e42472888a317abc9dcdf3563b62e7a61c8e98d7cdcbe272167d91fc6", "0xa10c2564936e967a390cb14ef6e8f8b04ea9ece5214a38837eda09e79e0c7970b1f83adf017c10efd6faa8b7ffa2c567", "0xa5085eed3a95f9d4b1269182ea1e0d719b7809bf5009096557a0674bde4201b0ddc1f0f16a908fc468846b3721748ce3", "0x87468eb620b79a0a455a259a6b4dfbc297d0d53336537b771254dd956b145dc816b195b7002647ea218552e345818a3f", "0xace2b77ffb87366af0a9cb5d27d6fc4a14323dbbf1643f5f3c4559306330d86461bb008894054394cbfaefeaa0bc2745", "0xb27f56e840a54fbd793f0b7a7631aa4cee64b5947e4382b2dfb5eb1790270288884c2a19afebe5dc0c6ef335d4531c1c", "0x876e438633931f7f895062ee16c4b9d10428875f7bc79a8e156a64d379a77a2c45bf5430c5ab94330f03da352f1e9006", "0xa2512a252587d200d2092b44c914df54e04ff8bcef36bf631f84bde0cf5a732e3dc7f00f662842cfd74b0b0f7f24180e", "0x827f1bc8f54a35b7a4bd8154f79bcc055e45faed2e74adf7cf21cca95df44d96899e847bd70ead6bb27b9c0ed97bbd8b", "0xa0c92cf5a9ed843714f3aea9fe7b880f622d0b4a3bf66de291d1b745279accf6ba35097849691370f41732ba64b5966b", "0xa63f5c1e222775658421c487b1256b52626c6f79cb55a9b7deb2352622cedffb08502042d622eb3b02c97f9c09f9c957", "0x8cc093d52651e65fb390e186db6cc4de559176af4624d1c44cb9b0e836832419dacac7b8db0627b96288977b738d785d", "0xaa7b6a17dfcec146134562d32a12f7bd7fe9522e300859202a02939e69dbd345ed7ff164a184296268f9984f9312e8fc", "0x8ac76721f0d2b679f023d06cbd28c85ae5f4b43c614867ccee88651d4101d4fd352dbdb65bf36bfc3ebc0109e4b0c6f9", "0x8d350f7c05fc0dcd9a1170748846fb1f5d39453e4cb31e6d1457bed287d96fc393b2ecc53793ca729906a33e59c6834a", "0xb9913510dfc5056d7ec5309f0b631d1ec53e3a776412ada9aefdaf033c90da9a49fdde6719e7c76340e86599b1f0eec2", "0x94955626bf4ce87612c5cfffcf73bf1c46a4c11a736602b9ba066328dc52ad6d51e6d4f53453d4ed55a51e0aad810271", "0xb0fcab384fd4016b2f1e53f1aafd160ae3b1a8865cd6c155d7073ecc1664e05b1d8bca1def39c158c7086c4e1103345e", "0x827de3f03edfbde08570b72de6662c8bfa499b066a0a27ebad9b481c273097d17a5a0a67f01553da5392ec3f149b2a78", "0xab7940384c25e9027c55c40df20bd2a0d479a165ced9b1046958353cd69015eeb1e44ed2fd64e407805ba42df10fc7bf", "0x8ad456f6ff8cd58bd57567d931f923d0c99141978511b17e03cab7390a72b9f62498b2893e1b05c7c22dd274e9a31919", "0xac75399e999effe564672db426faa17a839e57c5ef735985c70cd559a377adec23928382767b55ed5a52f7b11b54b756", "0xb17f975a00b817299ac7af5f2024ea820351805df58b43724393bfb3920a8cd747a3bbd4b8286e795521489db3657168", "0xa2bed800a6d95501674d9ee866e7314063407231491d794f8cf57d5be020452729c1c7cefd8c50dc1540181f5caab248", "0x9743f5473171271ffdd3cc59a3ae50545901a7b45cd4bc3570db487865f3b73c0595bebabbfe79268809ee1862e86e4a", "0xb7eab77c2d4687b60d9d7b04e842b3880c7940140012583898d39fcc22d9b9b0a9be2c2e3788b3e6f30319b39c338f09", "0x8e2b8f797a436a1b661140e9569dcf3e1eea0a77c7ff2bc4ff0f3e49af04ed2de95e255df8765f1d0927fb456a9926b1", "0x8aefea201d4a1f4ff98ffce94e540bb313f2d4dfe7e9db484a41f13fc316ed02b282e1acc9bc6f56cad2dc2e393a44c9", "0xb950c17c0e5ca6607d182144aa7556bb0efe24c68f06d79d6413a973b493bfdf04fd147a4f1ab03033a32004cc3ea66f", "0xb7b8dcbb179a07165f2dc6aa829fad09f582a71b05c3e3ea0396bf9e6fe73076f47035c031c2101e8e38e0d597eadd30", "0xa9d77ed89c77ec1bf8335d08d41c3c94dcca9fd1c54f22837b4e54506b212aa38d7440126c80648ab7723ff18e65ed72", "0xa819d6dfd4aef70e52b8402fe5d135f8082d40eb7d3bb5c4d7997395b621e2bb10682a1bad2c9caa33dd818550fc3ec6", "0x8f6ee34128fac8bbf13ce2d68b2bb363eb4fd65b297075f88e1446ddeac242500eeb4ef0735e105882ff5ba8c44c139b", "0xb4440e48255c1644bcecf3a1e9958f1ec4901cb5b1122ee5b56ffd02cad1c29c4266999dbb85aa2605c1b125490074d4", "0xa43304a067bede5f347775d5811cf65a6380a8d552a652a0063580b5c5ef12a0867a39c7912fa219e184f4538eba1251", "0xa891ad67a790089ffc9f6d53e6a3d63d3556f5f693e0cd8a7d0131db06fd4520e719cfcc3934f0a8f62a95f90840f1d4", "0xaea6df8e9bb871081aa0fc5a9bafb00be7d54012c5baf653791907d5042a326aeee966fd9012a582cc16695f5baf7042", "0x8ffa2660dc52ed1cd4eff67d6a84a8404f358a5f713d04328922269bee1e75e9d49afeec0c8ad751620f22352a438e25", "0x87ec6108e2d63b06abed350f8b363b7489d642486f879a6c3aa90e5b0f335efc2ff2834eef9353951a42136f8e6a1b32", "0x865619436076c2760d9e87ddc905023c6de0a8d56eef12c98a98c87837f2ca3f27fd26a2ad752252dbcbe2b9f1d5a032", "0x980437dce55964293cb315c650c5586ffd97e7a944a83f6618af31c9d92c37b53ca7a21bb5bc557c151b9a9e217e7098", "0x95d128fc369df4ad8316b72aea0ca363cbc7b0620d6d7bb18f7076a8717a6a46956ff140948b0cc4f6d2ce33b5c10054", "0x8c7212d4a67b9ec70ebbca04358ad2d36494618d2859609163526d7b3acc2fc935ca98519380f55e6550f70a9bc76862", "0x893a2968819401bf355e85eee0f0ed0406a6d4a7d7f172d0017420f71e00bb0ba984f6020999a3cdf874d3cd8ebcd371", "0x9103c1af82dece25d87274e89ea0acd7e68c2921c4af3d8d7c82ab0ed9990a5811231b5b06113e7fa43a6bd492b4564f", "0x99cfd87a94eab7d35466caa4ed7d7bb45e5c932b2ec094258fb14bf205659f83c209b83b2f2c9ccb175974b2a33e7746", "0x874b6b93e4ee61be3f00c32dd84c897ccd6855c4b6251eb0953b4023634490ed17753cd3223472873cbc6095b2945075", "0x84a32c0dc4ea60d33aac3e03e70d6d639cc9c4cc435c539eff915017be3b7bdaba33349562a87746291ebe9bc5671f24", "0xa7057b24208928ad67914e653f5ac1792c417f413d9176ba635502c3f9c688f7e2ee81800d7e3dc0a340c464da2fd9c5", "0xa03fb9ed8286aacfa69fbd5d953bec591c2ae4153400983d5dbb6cd9ea37fff46ca9e5cceb9d117f73e9992a6c055ad2", "0x863b2de04e89936c9a4a2b40380f42f20aefbae18d03750fd816c658aee9c4a03df7b12121f795c85d01f415baaeaa59", "0x8526eb9bd31790fe8292360d7a4c3eed23be23dd6b8b8f01d2309dbfdc0cfd33ad1568ddd7f8a610f3f85a9dfafc6a92", "0xb46ab8c5091a493d6d4d60490c40aa27950574a338ea5bbc045be3a114af87bdcb160a8c80435a9b7ad815f3cb56a3f3", "0xaeadc47b41a8d8b4176629557646202f868b1d728b2dda58a347d937e7ffc8303f20d26d6c00b34c851b8aeec547885d", "0xaebb19fc424d72c1f1822aa7adc744cd0ef7e55727186f8df8771c784925058c248406ebeeaf3c1a9ee005a26e9a10c6", "0x8ff96e81c1a4a2ab1b4476c21018fae0a67e92129ee36120cae8699f2d7e57e891f5c624902cb1b845b944926a605cc3", "0x8251b8d2c43fadcaa049a9e7aff838dae4fb32884018d58d46403ac5f3beb5c518bfd45f03b8abb710369186075eb71c", "0xa8b2a64f865f51a5e5e86a66455c093407933d9d255d6b61e1fd81ffafc9538d73caaf342338a66ba8ee166372a3d105", "0xaad915f31c6ba7fdc04e2aaac62e84ef434b7ee76a325f07dc430d12c84081999720181067b87d792efd0117d7ee1eab", "0xa13db3bb60389883fd41d565c54fb5180d9c47ce2fe7a169ae96e01d17495f7f4fa928d7e556e7c74319c4c25d653eb2", "0xa4491b0198459b3f552855d680a59214eb74e6a4d6c5fa3b309887dc50ebea2ecf6d26c040550f7dc478b452481466fb", "0x8f017f13d4b1e3f0c087843582b52d5f8d13240912254d826dd11f8703a99a2f3166dfbdfdffd9a3492979d77524276b", "0x96c3d5dcd032660d50d7cd9db2914f117240a63439966162b10c8f1f3cf74bc83b0f15451a43b31dbd85e4a7ce0e4bb1", "0xb479ec4bb79573d32e0ec93b92bdd7ec8c26ddb5a2d3865e7d4209d119fd3499eaac527615ffac78c440e60ef3867ae0", "0xb2c49c4a33aa94b52b6410b599e81ff15490aafa7e43c8031c865a84e4676354a9c81eb4e7b8be6825fdcefd1e317d44", "0x906dc51d6a90c089b6704b47592805578a6eed106608eeb276832f127e1b8e858b72e448edcbefb497d152447e0e68ff", "0xb0e81c63b764d7dfbe3f3fddc9905aef50f3633e5d6a4af6b340495124abedcff5700dfd1577bbbed7b6bf97d02719cb", "0x9304c64701e3b4ed6d146e48a881f7d83a17f58357cca0c073b2bb593afd2d94f6e2a7a1ec511d0a67ad6ff4c3be5937", "0xb6fdbd12ba05aa598d80b83f70a15ef90e5cba7e6e75fa038540ee741b644cd1f408a6cecfd2a891ef8d902de586c6b5", "0xb80557871a6521b1b3c74a1ba083ae055b575df607f1f7b04c867ba8c8c181ea68f8d90be6031f4d25002cca27c44da2", "0xaa7285b8e9712e06b091f64163f1266926a36607f9d624af9996856ed2aaf03a580cb22ce407d1ade436c28b44ca173f", "0x8148d72b975238b51e6ea389e5486940d22641b48637d7dfadfa603a605bfc6d74a016480023945d0b85935e396aea5d", "0x8a014933a6aea2684b5762af43dcf4bdbb633cd0428d42d71167a2b6fc563ece5e618bff22f1db2ddb69b845b9a2db19", "0x990d91740041db770d0e0eb9d9d97d826f09fd354b91c41e0716c29f8420e0e8aac0d575231efba12fe831091ec38d5a", "0x9454d0d32e7e308ddec57cf2522fb1b67a2706e33fb3895e9e1f18284129ab4f4c0b7e51af25681d248d7832c05eb698", "0xa5bd434e75bac105cb3e329665a35bce6a12f71dd90c15165777d64d4c13a82bceedb9b48e762bd24034e0fc9fbe45f4", "0xb09e3b95e41800d4dc29c6ffdaab2cd611a0050347f6414f154a47ee20ee59bf8cf7181454169d479ebce1eb5c777c46", "0xb193e341d6a047d15eea33766d656d807b89393665a783a316e9ba10518e5515c8e0ade3d6e15641d917a8a172a5a635", "0xade435ec0671b3621dde69e07ead596014f6e1daa1152707a8c18877a8b067bde2895dd47444ffa69db2bbef1f1d8816", "0xa7fd3d6d87522dfc56fb47aef9ce781a1597c56a8bbfd796baba907afdc872f753d732bfda1d3402aee6c4e0c189f52d", "0xa298cb4f4218d0464b2fab393e512bbc477c3225aa449743299b2c3572f065bc3a42d07e29546167ed9e1b6b3b3a3af3", "0xa9ee57540e1fd9c27f4f0430d194b91401d0c642456c18527127d1f95e2dba41c2c86d1990432eb38a692fda058fafde", "0x81d6c1a5f93c04e6d8e5a7e0678c1fc89a1c47a5c920bcd36180125c49fcf7c114866b90e90a165823560b19898a7c16", "0xa4b7a1ec9e93c899b9fd9aaf264c50e42c36c0788d68296a471f7a3447af4dbc81e4fa96070139941564083ec5b5b5a1", "0xb3364e327d381f46940c0e11e29f9d994efc6978bf37a32586636c0070b03e4e23d00650c1440f448809e1018ef9f6d8", "0x8056e0913a60155348300e3a62e28b5e30629a90f7dd4fe11289097076708110a1d70f7855601782a3cdc5bdb1ca9626", "0xb4980fd3ea17bac0ba9ee1c470b17e575bb52e83ebdd7d40c93f4f87bebeaff1c8a679f9d3d09d635f068d37d5bd28bd", "0x905a9299e7e1853648e398901dfcd437aa575c826551f83520df62984f5679cb5f0ea86aa45ed3e18b67ddc0dfafe809", "0xab99553bf31a84f2e0264eb34a08e13d8d15e2484aa9352354becf9a15999c76cc568d68274b70a65e49703fc23540d0", "0xa43681597bc574d2dae8964c9a8dc1a07613d7a1272bdcb818d98c85d44e16d744250c33f3b5e4d552d97396b55e601f", "0xa54e5a31716fccb50245898c99865644405b8dc920ded7a11f3d19bdc255996054b268e16f2e40273f11480e7145f41e", "0x8134f3ad5ef2ad4ba12a8a4e4d8508d91394d2bcdc38b7c8c8c0b0a820357ac9f79d286c65220f471eb1adca1d98fc68", "0x94e2f755e60471578ab2c1adb9e9cea28d4eec9b0e92e0140770bca7002c365fcabfe1e5fb4fe6cfe79a0413712aa3ef", "0xad48f8d0ce7eb3cc6e2a3086ad96f562e5bed98a360721492ae2e74dc158586e77ec8c35d5fd5927376301b7741bad2b", "0x8614f0630bdd7fbad3a31f55afd9789f1c605dc85e7dc67e2edfd77f5105f878bb79beded6e9f0b109e38ea7da67e8d5", "0x9804c284c4c5e77dabb73f655b12181534ca877c3e1e134aa3f47c23b7ec92277db34d2b0a5d38d2b69e5d1c3008a3e3", "0xa51b99c3088e473afdaa9e0a9f7e75a373530d3b04e44e1148da0726b95e9f5f0c7e571b2da000310817c36f84b19f7f", "0xac4ff909933b3b76c726b0a382157cdc74ab851a1ac6cef76953c6444441804cc43abb883363f416592e8f6cfbc4550b", "0xae7d915eb9fc928b65a29d6edbc75682d08584d0014f7bcf17d59118421ae07d26a02137d1e4de6938bcd1ab8ef48fad", "0x852f7e453b1af89b754df6d11a40d5d41ea057376e8ecacd705aacd2f917457f4a093d6b9a8801837fa0f62986ad7149", "0x92c6bf5ada5d0c3d4dd8058483de36c215fa98edab9d75242f3eff9db07c734ad67337da6f0eefe23a487bf75a600dee", "0xa2b42c09d0db615853763552a48d2e704542bbd786aae016eb58acbf6c0226c844f5fb31e428cb6450b9db855f8f2a6f", "0x880cc07968266dbfdcfbc21815cd69e0eddfee239167ac693fb0413912d816f2578a74f7716eecd6deefa68c6eccd394", "0xb885b3ace736cd373e8098bf75ba66fa1c6943ca1bc4408cd98ac7074775c4478594f91154b8a743d9c697e1b29f5840", "0xa51ce78de512bd87bfa0835de819941dffbf18bec23221b61d8096fc9436af64e0693c335b54e7bfc763f287bdca2db6", "0xa3c76166a3bdb9b06ef696e57603b58871bc72883ee9d45171a30fe6e1d50e30bc9c51b4a0f5a7270e19a77b89733850", "0xacefc5c6f8a1e7c24d7b41e0fc7f6f3dc0ede6cf3115ffb9a6e54b1d954cbca9bda8ad7a084be9be245a1b8e9770d141", "0xb420ed079941842510e31cfad117fa11fb6b4f97dfbc6298cb840f27ebaceba23eeaf3f513bcffbf5e4aae946310182d", "0x95c3bb5ef26c5ed2f035aa5d389c6b3c15a6705b9818a3fefaed28922158b35642b2e8e5a1a620fdad07e75ad4b43af4", "0x825149f9081ecf07a2a4e3e8b5d21bade86c1a882475d51c55ee909330b70c5a2ac63771c8600c6f38df716af61a3ea1", "0x873b935aae16d9f08adbc25353cee18af2f1b8d5f26dec6538d6bbddc515f2217ed7d235dcfea59ae61b428798b28637", "0x9294150843a2bedcedb3bb74c43eb28e759cf9499582c5430bccefb574a8ddd4f11f9929257ff4c153990f9970a2558f", "0xb619563a811cc531da07f4f04e5c4c6423010ff9f8ed7e6ec9449162e3d501b269fb1c564c09c0429431879b0f45df02", "0x91b509b87eb09f007d839627514658c7341bc76d468920fe8a740a8cb96a7e7e631e0ea584a7e3dc1172266f641d0f5c", "0x8b8aceace9a7b9b4317f1f01308c3904d7663856946afbcea141a1c615e21ccad06b71217413e832166e9dd915fbe098", "0x87b3b36e725833ea0b0f54753c3728c0dbc87c52d44d705ffc709f2d2394414c652d3283bab28dcce09799504996cee0", "0xb2670aad5691cbf308e4a6a77a075c4422e6cbe86fdba24e9f84a313e90b0696afb6a067eebb42ba2d10340d6a2f6e51", "0x876784a9aff3d54faa89b2bacd3ff5862f70195d0b2edc58e8d1068b3c9074c0da1cfa23671fe12f35e33b8a329c0ccd", "0x8b48b9e758e8a8eae182f5cbec96f67d20cca6d3eee80a2d09208eb1d5d872e09ef23d0df8ebbb9b01c7449d0e3e3650", "0xb79303453100654c04a487bdcadc9e3578bc80930c489a7069a52e8ca1dba36c492c8c899ce025f8364599899baa287d", "0x961b35a6111da54ece6494f24dacd5ea46181f55775b5f03df0e370c34a5046ac2b4082925855325bb42bc2a2c98381d", "0xa31feb1be3f5a0247a1f7d487987eb622e34fca817832904c6ee3ee60277e5847945a6f6ea1ac24542c72e47bdf647df", "0xa12a2aa3e7327e457e1aae30e9612715dd2cfed32892c1cd6dcda4e9a18203af8a44afb46d03b2eed89f6b9c5a2c0c23", "0xa08265a838e69a2ca2f80fead6ccf16f6366415b920c0b22ee359bcd8d4464ecf156f400a16a7918d52e6d733dd64211", "0xb723d6344e938d801cca1a00032af200e541d4471fd6cbd38fb9130daa83f6a1dffbbe7e67fc20f9577f884acd7594b2", "0xa6733d83ec78ba98e72ddd1e7ff79b7adb0e559e256760d0c590a986e742445e8cdf560d44b29439c26d87edd0b07c8c", "0xa61c2c27d3f7b9ff4695a17afedf63818d4bfba390507e1f4d0d806ce8778d9418784430ce3d4199fd3bdbc2504d2af3", "0x8332f3b63a6dc985376e8b1b25eeae68be6160fbe40053ba7bcf6f073204f682da72321786e422d3482fd60c9e5aa034", "0xa280f44877583fbb6b860d500b1a3f572e3ee833ec8f06476b3d8002058e25964062feaa1e5bec1536d734a5cfa09145", "0xa4026a52d277fcea512440d2204f53047718ebfcae7b48ac57ea7f6bfbc5de9d7304db9a9a6cbb273612281049ddaec5", "0x95cdf69c831ab2fad6c2535ede9c07e663d2ddccc936b64e0843d2df2a7b1c31f1759c3c20f1e7a57b1c8f0dbb21b540", "0x95c96cec88806469c277ab567863c5209027cecc06c7012358e5f555689c0d9a5ffb219a464f086b45817e8536b86d2f", "0xafe38d4684132a0f03d806a4c8df556bf589b25271fbc6fe2e1ed16de7962b341c5003755da758d0959d2e6499b06c68", "0xa9b77784fda64987f97c3a23c5e8f61b918be0f7c59ba285084116d60465c4a2aaafc8857eb16823282cc83143eb9126", "0xa830f05881ad3ce532a55685877f529d32a5dbe56cea57ffad52c4128ee0fad0eeaf0da4362b55075e77eda7babe70e5", "0x992b3ad190d6578033c13ed5abfee4ef49cbc492babb90061e3c51ee4b5790cdd4c8fc1abff1fa2c00183b6b64f0bbbe", "0xb1015424d9364aeff75de191652dc66484fdbec3e98199a9eb9671ec57bec6a13ff4b38446e28e4d8aedb58dd619cd90", "0xa745304604075d60c9db36cada4063ac7558e7ec2835d7da8485e58d8422e817457b8da069f56511b02601289fbb8981", "0xa5ba4330bc5cb3dbe0486ddf995632a7260a46180a08f42ae51a2e47778142132463cc9f10021a9ad36986108fefa1a9", "0xb419e9fd4babcaf8180d5479db188bb3da232ae77a1c4ed65687c306e6262f8083070a9ac32220cddb3af2ec73114092", "0xa49e23dc5f3468f3bf3a0bb7e4a114a788b951ff6f23a3396ae9e12cbff0abd1240878a3d1892105413dbc38818e807c", "0xb7ecc7b4831f650202987e85b86bc0053f40d983f252e9832ef503aea81c51221ce93279da4aa7466c026b2d2070e55d", "0x96a8c35cb87f84fa84dcd6399cc2a0fd79cc9158ef4bdde4bae31a129616c8a9f2576cd19baa3f497ca34060979aed7d", "0x8681b2c00aa62c2b519f664a95dcb8faef601a3b961bb4ce5d85a75030f40965e2983871d41ea394aee934e859581548", "0x85c229a07efa54a713d0790963a392400f55fbb1a43995a535dc6c929f20d6a65cf4efb434e0ad1cb61f689b8011a3bc", "0x90856f7f3444e5ad44651c28e24cc085a5db4d2ffe79aa53228c26718cf53a6e44615f3c5cda5aa752d5f762c4623c66", "0x978999b7d8aa3f28a04076f74d11c41ef9c89fdfe514936c4238e0f13c38ec97e51a5c078ebc6409e517bfe7ccb42630", "0xa099914dd7ed934d8e0d363a648e9038eb7c1ec03fa04dbcaa40f7721c618c3ef947afef7a16b4d7ac8c12aa46637f03", "0xab2a104fed3c83d16f2cda06878fa5f30c8c9411de71bfb67fd2fc9aa454dcbcf3d299d72f8cc12e919466a50fcf7426", "0xa4471d111db4418f56915689482f6144efc4664cfb0311727f36c864648d35734351becc48875df96f4abd3cfcf820f9", "0x83be11727cd30ea94ccc8fa31b09b81c9d6a9a5d3a4686af9da99587332fe78c1f94282f9755854bafd6033549afec91", "0x88020ff971dc1a01a9e993cd50a5d2131ffdcbb990c1a6aaa54b20d8f23f9546a70918ea57a21530dcc440c1509c24ad", "0xae24547623465e87905eaffa1fa5d52bb7c453a8dbd89614fa8819a2abcedaf455c2345099b7324ae36eb0ad7c8ef977", "0xb59b0c60997de1ee00b7c388bc7101d136c9803bf5437b1d589ba57c213f4f835a3e4125b54738e78abbc21b000f2016", "0xa584c434dfe194546526691b68fa968c831c31da42303a1d735d960901c74011d522246f37f299555416b8cf25c5a548", "0x80408ce3724f4837d4d52376d255e10f69eb8558399ae5ca6c11b78b98fe67d4b93157d2b9b639f1b5b64198bfe87713", "0xabb941e8d406c2606e0ddc35c113604fdd9d249eacc51cb64e2991e551b8639ce44d288cc92afa7a1e7fc599cfc84b22", "0xb223173f560cacb1c21dba0f1713839e348ad02cbfdef0626748604c86f89e0f4c919ed40b583343795bdd519ba952c8", "0xaf1c70512ec3a19d98b8a1fc3ff7f7f5048a27d17d438d43f561974bbdd116fcd5d5c21040f3447af3f0266848d47a15", "0x8a44809568ebe50405bede19b4d2607199159b26a1b33e03d180e6840c5cf59d991a4fb150d111443235d75ecad085b7", "0xb06207cdca46b125a27b3221b5b50cf27af4c527dd7c80e2dbcebbb09778a96df3af67e50f07725239ce3583dad60660", "0x993352d9278814ec89b26a11c4a7c4941bf8f0e6781ae79559d14749ee5def672259792db4587f85f0100c7bb812f933", "0x9180b8a718b971fd27bc82c8582d19c4b4f012453e8c0ffeeeffe745581fc6c07875ab28be3af3fa3896d19f0c89ac5b", "0x8b8e1263eb48d0fe304032dd5ea1f30e73f0121265f7458ba9054d3626894e8a5fef665340abd2ede9653045c2665938", "0x99a2beee4a10b7941c24b2092192faf52b819afd033e4a2de050fd6c7f56d364d0cf5f99764c3357cf32399e60fc5d74", "0x946a4aad7f8647ea60bee2c5fcdeb6f9a58fb2cfca70c4d10e458027a04846e13798c66506151be3df9454b1e417893f", "0xa672a88847652d260b5472d6908d1d57e200f1e492d30dd1cecc441cdfc9b76e016d9bab560efd4d7f3c30801de884a9", "0x9414e1959c156cde1eb24e628395744db75fc24b9df4595350aaad0bc38e0246c9b4148f6443ef68b8e253a4a6bcf11c", "0x9316e9e4ec5fab4f80d6540df0e3a4774db52f1d759d2e5b5bcd3d7b53597bb007eb1887cb7dc61f62497d51ffc8d996", "0x902d6d77bb49492c7a00bc4b70277bc28c8bf9888f4307bb017ac75a962decdedf3a4e2cf6c1ea9f9ba551f4610cbbd7", "0xb07025a18b0e32dd5e12ec6a85781aa3554329ea12c4cd0d3b2c22e43d777ef6f89876dd90a9c8fb097ddf61cf18adc5", "0xb355a849ad3227caa4476759137e813505ec523cbc2d4105bc7148a4630f9e81918d110479a2d5f5e4cd9ccec9d9d3e3", "0xb49532cfdf02ee760109881ad030b89c48ee3bb7f219ccafc13c93aead754d29bdafe345be54c482e9d5672bd4505080", "0x9477802410e263e4f938d57fa8f2a6cac7754c5d38505b73ee35ea3f057aad958cb9722ba6b7b3cfc4524e9ca93f9cdc", "0x9148ea83b4436339580f3dbc9ba51509e9ab13c03063587a57e125432dd0915f5d2a8f456a68f8fff57d5f08c8f34d6e", "0xb00b6b5392b1930b54352c02b1b3b4f6186d20bf21698689bbfc7d13e86538a4397b90e9d5c93fd2054640c4dbe52a4f", "0x926a9702500441243cd446e7cbf15dde16400259726794694b1d9a40263a9fc9e12f7bcbf12a27cb9aaba9e2d5848ddc", "0xa0c6155f42686cbe7684a1dc327100962e13bafcf3db97971fc116d9f5c0c8355377e3d70979cdbd58fd3ea52440901c", "0xa277f899f99edb8791889d0817ea6a96c24a61acfda3ad8c3379e7c62b9d4facc4b965020b588651672fd261a77f1bfc", "0x8f528cebb866b501f91afa50e995234bef5bf20bff13005de99cb51eaac7b4f0bf38580cfd0470de40f577ead5d9ba0f", "0x963fc03a44e9d502cc1d23250efef44d299befd03b898d07ce63ca607bb474b5cf7c965a7b9b0f32198b04a8393821f7", "0xab087438d0a51078c378bf4a93bd48ef933ff0f1fa68d02d4460820df564e6642a663b5e50a5fe509527d55cb510ae04", "0xb0592e1f2c54746bb076be0fa480e1c4bebc4225e1236bcda3b299aa3853e3afb401233bdbcfc4a007b0523a720fbf62", "0x851613517966de76c1c55a94dc4595f299398a9808f2d2f0a84330ba657ab1f357701d0895f658c18a44cb00547f6f57", "0xa2fe9a1dd251e72b0fe4db27be508bb55208f8f1616b13d8be288363ec722826b1a1fd729fc561c3369bf13950bf1fd6", "0xb896cb2bc2d0c77739853bc59b0f89b2e008ba1f701c9cbe3bef035f499e1baee8f0ff1e794854a48c320586a2dfc81a", "0xa1b60f98e5e5106785a9b81a85423452ee9ef980fa7fa8464f4366e73f89c50435a0c37b2906052b8e58e212ebd366cf", "0xa853b0ebd9609656636df2e6acd5d8839c0fda56f7bf9288a943b06f0b67901a32b95e016ca8bc99bd7b5eab31347e72", "0xb290fa4c1346963bd5225235e6bdf7c542174dab4c908ab483d1745b9b3a6015525e398e1761c90e4b49968d05e30eea", "0xb0f65a33ad18f154f1351f07879a183ad62e5144ad9f3241c2d06533dad09cbb2253949daff1bb02d24d16a3569f7ef0", "0xa00db59b8d4218faf5aeafcd39231027324408f208ec1f54d55a1c41228b463b88304d909d16b718cfc784213917b71e", "0xb8d695dd33dc2c3bc73d98248c535b2770ad7fa31aa726f0aa4b3299efb0295ba9b4a51c71d314a4a1bd5872307534d1", "0xb848057cca2ca837ee49c42b88422303e58ea7d2fc76535260eb5bd609255e430514e927cc188324faa8e657396d63ec", "0x92677836061364685c2aaf0313fa32322746074ed5666fd5f142a7e8f87135f45cd10e78a17557a4067a51dfde890371", "0xa854b22c9056a3a24ab164a53e5c5cf388616c33e67d8ebb4590cb16b2e7d88b54b1393c93760d154208b5ca822dc68f", "0x86fff174920388bfab841118fb076b2b0cdec3fdb6c3d9a476262f82689fb0ed3f1897f7be9dbf0932bb14d346815c63", "0x99661cf4c94a74e182752bcc4b98a8c2218a8f2765642025048e12e88ba776f14f7be73a2d79bd21a61def757f47f904", "0x8a8893144d771dca28760cba0f950a5d634195fd401ec8cf1145146286caffb0b1a6ba0c4c1828d0a5480ce49073c64c", "0x938a59ae761359ee2688571e7b7d54692848eb5dde57ffc572b473001ea199786886f8c6346a226209484afb61d2e526", "0x923f68a6aa6616714cf077cf548aeb845bfdd78f2f6851d8148cba9e33a374017f2f3da186c39b82d14785a093313222", "0xac923a93d7da7013e73ce8b4a2b14b8fd0cc93dc29d5de941a70285bdd19be4740fedfe0c56b046689252a3696e9c5bc", "0xb49b32c76d4ec1a2c68d4989285a920a805993bc6fcce6dacd3d2ddae73373050a5c44ba8422a3781050682fa0ef6ba2", "0x8a367941c07c3bdca5712524a1411bad7945c7c48ffc7103b1d4dff2c25751b0624219d1ccde8c3f70c465f954be5445", "0xb838f029df455efb6c530d0e370bbbf7d87d61a9aea3d2fe5474c5fe0a39cf235ceecf9693c5c6c5820b1ba8f820bd31", "0xa8983b7c715eaac7f13a001d2abc462dfc1559dab4a6b554119c271aa8fe00ffcf6b6949a1121f324d6d26cb877bcbae", "0xa2afb24ad95a6f14a6796315fbe0d8d7700d08f0cfaf7a2abe841f5f18d4fecf094406cbd54da7232a159f9c5b6e805e", "0x87e8e95ad2d62f947b2766ff405a23f7a8afba14e7f718a691d95369c79955cdebe24c54662553c60a3f55e6322c0f6f", "0x87c2cbcecb754e0cc96128e707e5c5005c9de07ffd899efa3437cadc23362f5a1d3fcdd30a1f5bdc72af3fb594398c2a", "0x91afd6ee04f0496dc633db88b9370d41c428b04fd991002502da2e9a0ef051bcd7b760e860829a44fbe5539fa65f8525", "0x8c50e5d1a24515a9dd624fe08b12223a75ca55196f769f24748686315329b337efadca1c63f88bee0ac292dd0a587440", "0x8a07e8f912a38d94309f317c32068e87f68f51bdfa082d96026f5f5f8a2211621f8a3856dda8069386bf15fb2d28c18f", "0x94ad1dbe341c44eeaf4dc133eed47d8dbfe752575e836c075745770a6679ff1f0e7883b6aa917462993a7f469d74cab5", "0x8745f8bd86c2bb30efa7efb7725489f2654f3e1ac4ea95bd7ad0f3cfa223055d06c187a16192d9d7bdaea7b050c6a324", "0x900d149c8d79418cda5955974c450a70845e02e5a4ecbcc584a3ca64d237df73987c303e3eeb79da1af83bf62d9e579f", "0x8f652ab565f677fb1a7ba03b08004e3cda06b86c6f1b0b9ab932e0834acf1370abb2914c15b0d08327b5504e5990681c", "0x9103097d088be1f75ab9d3da879106c2f597e2cc91ec31e73430647bdd5c33bcfd771530d5521e7e14df6acda44f38a6", "0xb0fec7791cfb0f96e60601e1aeced9a92446b61fedab832539d1d1037558612d78419efa87ff5f6b7aab8fd697d4d9de", "0xb9d2945bdb188b98958854ba287eb0480ef614199c4235ce5f15fc670b8c5ffe8eeb120c09c53ea8a543a022e6a321ac", "0xa9461bb7d5490973ebaa51afc0bb4a5e42acdccb80e2f939e88b77ac28a98870e103e1042899750f8667a8cc9123bae9", "0xa37fdf11d4bcb2aed74b9f460a30aa34afea93386fa4cdb690f0a71bc58f0b8df60bec56e7a24f225978b862626fa00e", "0xa214420e183e03d531cf91661466ea2187d84b6e814b8b20b3730a9400a7d25cf23181bb85589ebc982cec414f5c2923", "0xad09a45a698a6beb3e0915f540ef16e9af7087f53328972532d6b5dfe98ce4020555ece65c6cbad8bd6be8a4dfefe6fd", "0xab6742800b02728c92d806976764cb027413d6f86edd08ad8bb5922a2969ee9836878cd39db70db0bd9a2646862acc4f", "0x974ca9305bd5ea1dc1755dff3b63e8bfe9f744321046c1395659bcea2a987b528e64d5aa96ac7b015650b2253b37888d", "0x84eee9d6bce039c52c2ebc4fccc0ad70e20c82f47c558098da4be2f386a493cbc76adc795b5488c8d11b6518c2c4fab8", "0x875d7bda46efcb63944e1ccf760a20144df3b00d53282b781e95f12bfc8f8316dfe6492c2efbf796f1150e36e436e9df", "0xb68a2208e0c587b5c31b5f6cb32d3e6058a9642e2d9855da4f85566e1412db528475892060bb932c55b3a80877ad7b4a", "0xba006368ecab5febb6ab348644d9b63de202293085ed468df8bc24d992ae8ce468470aa37f36a73630c789fb9c819b30", "0x90a196035150846cd2b482c7b17027471372a8ce7d914c4d82b6ea7fa705d8ed5817bd42d63886242585baf7d1397a1c", "0xa223b4c85e0daa8434b015fd9170b5561fe676664b67064974a1e9325066ecf88fc81f97ab5011c59fad28cedd04b240", "0x82e8ec43139cf15c6bbeed484b62e06cded8a39b5ce0389e4cbe9c9e9c02f2f0275d8d8d4e8dfec8f69a191bef220408", "0x81a3fc07a7b68d92c6ee4b6d28f5653ee9ec85f7e2ee1c51c075c1b130a8c5097dc661cf10c5aff1c7114b1a6a19f11a", "0x8ed2ef8331546d98819a5dd0e6c9f8cb2630d0847671314a28f277faf68da080b53891dd75c82cbcf7788b255490785d", "0xacecabf84a6f9bbed6b2fc2e7e4b48f02ef2f15e597538a73aea8f98addc6badda15e4695a67ecdb505c1554e8f345ec", "0xb8f51019b2aa575f8476e03dcadf86cc8391f007e5f922c2a36b2daa63f5a503646a468990cd5c65148d323942193051", "0xaaa595a84b403ec65729bc1c8055a94f874bf9adddc6c507b3e1f24f79d3ad359595a672b93aab3394db4e2d4a7d8970", "0x895144c55fcbd0f64d7dd69e6855cfb956e02b5658eadf0f026a70703f3643037268fdd673b0d21b288578a83c6338dd", "0xa2e92ae6d0d237d1274259a8f99d4ea4912a299816350b876fba5ebc60b714490e198a916e1c38c6e020a792496fa23c", "0xa45795fda3b5bb0ad1d3c628f6add5b2a4473a1414c1a232e80e70d1cfffd7f8a8d9861f8df2946999d7dbb56bf60113", "0xb6659bf7f6f2fef61c39923e8c23b8c70e9c903028d8f62516d16755cd3fba2fe41c285aa9432dc75ab08f8a1d8a81fc", "0xa735609a6bc5bfd85e58234fc439ff1f58f1ff1dd966c5921d8b649e21f006bf2b8642ad8a75063c159aaf6935789293", "0xa3c622eb387c9d15e7bda2e3e84d007cb13a6d50d655c3f2f289758e49d3b37b9a35e4535d3cc53d8efd51f407281f19", "0x8afe147b53ad99220f5ef9d763bfc91f9c20caecbcf823564236fb0e6ede49414c57d71eec4772c8715cc65a81af0047", "0xb5f0203233cf71913951e9c9c4e10d9243e3e4a1f2cb235bf3f42009120ba96e04aa414c9938ea8873b63148478927e8", "0x93c52493361b458d196172d7ba982a90a4f79f03aa8008edc322950de3ce6acf4c3977807a2ffa9e924047e02072b229", "0xb9e72b805c8ac56503f4a86c82720afbd5c73654408a22a2ac0b2e5caccdfb0e20b59807433a6233bc97ae58cf14c70a", "0xaf0475779b5cee278cca14c82da2a9f9c8ef222eb885e8c50cca2315fea420de6e04146590ed0dd5a29c0e0812964df5", "0xb430ccab85690db02c2d0eb610f3197884ca12bc5f23c51e282bf3a6aa7e4a79222c3d8761454caf55d6c01a327595f9", "0x830032937418b26ee6da9b5206f3e24dc76acd98589e37937e963a8333e5430abd6ce3dd93ef4b8997bd41440eed75d6", "0x8820a6d73180f3fe255199f3f175c5eb770461ad5cfdde2fb11508041ed19b8c4ce66ad6ecebf7d7e836cc2318df47ca", "0xaef1393e7d97278e77bbf52ef6e1c1d5db721ccf75fe753cf47a881fa034ca61eaa5098ee5a344c156d2b14ff9e284ad", "0x8a4a26c07218948c1196c45d927ef4d2c42ade5e29fe7a91eaebe34a29900072ce5194cf28d51f746f4c4c649daf4396", "0x84011dc150b7177abdcb715efbd8c201f9cb39c36e6069af5c50a096021768ba40cef45b659c70915af209f904ede3b6", "0xb1bd90675411389bb66910b21a4bbb50edce5330850c5ab0b682393950124252766fc81f5ecfc72fb7184387238c402e", "0x8dfdcd30583b696d2c7744655f79809f451a60c9ad5bf1226dc078b19f4585d7b3ef7fa9d54e1ac09520d95cbfd20928", "0xb351b4dc6d98f75b8e5a48eb7c6f6e4b78451991c9ba630e5a1b9874c15ac450cd409c1a024713bf2cf82dc400e025ef", "0xa462b8bc97ac668b97b28b3ae24b9f5de60e098d7b23ecb600d2194cd35827fb79f77c3e50d358f5bd72ee83fef18fa0", "0xa183753265c5f7890270821880cce5f9b2965b115ba783c6dba9769536f57a04465d7da5049c7cf8b3fcf48146173c18", "0xa8a771b81ed0d09e0da4d79f990e58eabcd2be3a2680419502dd592783fe52f657fe55125b385c41d0ba3b9b9cf54a83", "0xa71ec577db46011689d073245e3b1c3222a9b1fe6aa5b83629adec5733dd48617ebea91346f0dd0e6cdaa86e4931b168", "0xa334b8b244f0d598a02da6ae0f918a7857a54dce928376c4c85df15f3b0f2ba3ac321296b8b7c9dd47d770daf16c8f8c", "0xa29037f8ef925c417c90c4df4f9fb27fb977d04e2b3dd5e8547d33e92ab72e7a00f5461de21e28835319eae5db145eb7", "0xb91054108ae78b00e3298d667b913ebc44d8f26e531eae78a8fe26fdfb60271c97efb2dee5f47ef5a3c15c8228138927", "0x926c13efbe90604f6244be9315a34f72a1f8d1aab7572df431998949c378cddbf2fe393502c930fff614ff06ae98a0ce", "0x995c758fd5600e6537089b1baa4fbe0376ab274ff3e82a17768b40df6f91c2e443411de9cafa1e65ea88fb8b87d504f4", "0x9245ba307a7a90847da75fca8d77ec03fdfc812c871e7a2529c56a0a79a6de16084258e7a9ac4ae8a3756f394336e21c", "0x99e0cfa2bb57a7e624231317044c15e52196ecce020db567c8e8cb960354a0be9862ee0c128c60b44777e65ac315e59f", "0xad4f6b3d27bbbb744126601053c3dc98c07ff0eb0b38a898bd80dce778372846d67e5ab8fb34fb3ad0ef3f235d77ba7f", "0xa0f12cae3722bbbca2e539eb9cc7614632a2aefe51410430070a12b5bc5314ecec5857b7ff8f41e9980cac23064f7c56", "0xb487f1bc59485848c98222fd3bc36c8c9bb3d2912e2911f4ceca32c840a7921477f9b1fe00877e05c96c75d3eecae061", "0xa6033db53925654e18ecb3ce715715c36165d7035db9397087ac3a0585e587998a53973d011ac6d48af439493029cee6", "0xa6b4d09cd01c70a3311fd131d3710ccf97bde3e7b80efd5a8c0eaeffeb48cca0f951ced905290267b115b06d46f2693b", "0xa9dff1df0a8f4f218a98b6f818a693fb0d611fed0fc3143537cbd6578d479af13a653a8155e535548a2a0628ae24fa58", "0xa58e469f65d366b519f9a394cacb7edaddac214463b7b6d62c2dbc1316e11c6c5184ce45c16de2d77f990dcdd8b55430", "0x989e71734f8119103586dc9a3c5f5033ddc815a21018b34c1f876cdfc112efa868d5751bf6419323e4e59fa6a03ece1c", "0xa2da00e05036c884369e04cf55f3de7d659cd5fa3f849092b2519dd263694efe0f051953d9d94b7e121f0aee8b6174d7", "0x968f3c029f57ee31c4e1adea89a7f92e28483af9a74f30fbdb995dc2d40e8e657dff8f8d340d4a92bf65f54440f2859f", "0x932778df6f60ac1639c1453ef0cbd2bf67592759dcccb3e96dcc743ff01679e4c7dd0ef2b0833dda548d32cb4eba49e2", "0xa805a31139f8e0d6dae1ac87d454b23a3dc9fc653d4ca18d4f8ebab30fc189c16e73981c2cb7dd6f8c30454a5208109d", "0xa9ba0991296caa2aaa4a1ceacfb205544c2a2ec97088eace1d84ee5e2767656a172f75d2f0c4e16a3640a0e0dec316e0", "0xb1e49055c968dced47ec95ae934cf45023836d180702e20e2df57e0f62fb85d7ac60d657ba3ae13b8560b67210449459", "0xa94e1da570a38809c71e37571066acabff7bf5632737c9ab6e4a32856924bf6211139ab3cedbf083850ff2d0e0c0fcfc", "0x88ef1bb322000c5a5515b310c838c9af4c1cdbb32eab1c83ac3b2283191cd40e9573747d663763a28dad0d64adc13840", "0xa987ce205f923100df0fbd5a85f22c9b99b9b9cbe6ddfa8dfda1b8fe95b4f71ff01d6c5b64ca02eb24edb2b255a14ef0", "0x84fe8221a9e95d9178359918a108de4763ebfa7a6487facb9c963406882a08a9a93f492f8e77cf9e7ea41ae079c45993", "0xaa1cf3dc7c5dcfa15bbbc811a4bb6dbac4fba4f97fb1ed344ab60264d7051f6eef19ea9773441d89929ee942ed089319", "0x8f6a7d610d59d9f54689bbe6a41f92d9f6096cde919c1ab94c3c7fcecf0851423bc191e5612349e10f855121c0570f56", "0xb5af1fa7894428a53ea520f260f3dc3726da245026b6d5d240625380bfb9c7c186df0204bb604efac5e613a70af5106e", "0xa5bce6055ff812e72ce105f147147c7d48d7a2313884dd1f488b1240ee320f13e8a33f5441953a8e7a3209f65b673ce1", "0xb9b55b4a1422677d95821e1d042ab81bbf0bf087496504021ec2e17e238c2ca6b44fb3b635a5c9eac0871a724b8d47c3", "0x941c38e533ce4a673a3830845b56786585e5fe49c427f2e5c279fc6db08530c8f91db3e6c7822ec6bb4f956940052d18", "0xa38e191d66c625f975313c7007bbe7431b5a06ed2da1290a7d5d0f2ec73770d476efd07b8e632de64597d47df175cbb0", "0x94ba76b667abf055621db4c4145d18743a368d951565632ed4e743dd50dd3333507c0c34f286a5c5fdbf38191a2255cd", "0xa5ca38c60be5602f2bfa6e00c687ac96ac36d517145018ddbee6f12eb0faa63dd57909b9eeed26085fe5ac44e55d10ab", "0xb00fea3b825e60c1ed1c5deb4b551aa65a340e5af36b17d5262c9cd2c508711e4dc50dc2521a2c16c7c901902266e64a", "0x971b86fc4033485e235ccb0997a236206ba25c6859075edbcdf3c943116a5030b7f75ebca9753d863a522ba21a215a90", "0xb3b31f52370de246ee215400975b674f6da39b2f32514fe6bd54e747752eedca22bb840493b44a67df42a3639c5f901f", "0xaffbbfac9c1ba7cbfa1839d2ae271dd6149869b75790bf103230637da41857fc326ef3552ff31c15bda0694080198143", "0xa95d42aa7ef1962520845aa3688f2752d291926f7b0d73ea2ee24f0612c03b43f2b0fe3c9a9a99620ffc8d487b981bc2", "0x914a266065caf64985e8c5b1cb2e3f4e3fe94d7d085a1881b1fefa435afef4e1b39a98551d096a62e4f5cc1a7f0fdc2e", "0x81a0b4a96e2b75bc1bf2dbd165d58d55cfd259000a35504d1ffb18bc346a3e6f07602c683723864ffb980f840836fd8d", "0x91c1556631cddd4c00b65b67962b39e4a33429029d311c8acf73a18600e362304fb68bccb56fde40f49e95b7829e0b87", "0x8befbacc19e57f7c885d1b7a6028359eb3d80792fe13b92a8400df21ce48deb0bb60f2ddb50e3d74f39f85d7eab23adc", "0x92f9458d674df6e990789690ec9ca73dacb67fc9255b58c417c555a8cc1208ace56e8e538f86ba0f3615573a0fbac00d", "0xb4b1b3062512d6ae7417850c08c13f707d5838e43d48eb98dd4621baf62eee9e82348f80fe9b888a12874bfa538771f8", "0xa13c4a3ac642ede37d9c883f5319e748d2b938f708c9d779714108a449b343f7b71a6e3ef4080fee125b416762920273", "0xaf44983d5fc8cceee0551ef934e6e653f2d3efa385e5c8a27a272463a6f333e290378cc307c2b664eb923c78994e706e", "0xa389fd6c59fe2b4031cc244e22d3991e541bd203dd5b5e73a6159e72df1ab41d49994961500dcde7989e945213184778", "0x8d2141e4a17836c548de9598d7b298b03f0e6c73b7364979a411c464e0628e21cff6ac3d6decdba5d1c4909eff479761", "0x980b22ef53b7bdf188a3f14bc51b0dbfdf9c758826daa3cbc1e3986022406a8aa9a6a79e400567120b88c67faa35ce5f", "0xa28882f0a055f96df3711de5d0aa69473e71245f4f3e9aa944e9d1fb166e02caa50832e46da6d3a03b4801735fd01b29", "0x8db106a37d7b88f5d995c126abb563934dd8de516af48e85695d02b1aea07f79217e3cdd03c6f5ca57421830186c772b", "0xb5a7e50da0559a675c472f7dfaee456caab6695ab7870541b2be8c2b118c63752427184aad81f0e1afc61aef1f28c46f", "0x9962118780e20fe291d10b64f28d09442a8e1b5cffd0f3dd68d980d0614050a626c616b44e9807fbee7accecae00686a", "0xb38ddf33745e8d2ad6a991aefaf656a33c5f8cbe5d5b6b6fd03bd962153d8fd0e01b5f8f96d80ae53ab28d593ab1d4e7", "0x857dc12c0544ff2c0c703761d901aba636415dee45618aba2e3454ff9cbc634a85c8b05565e88520ff9be2d097c8b2b1", "0xa80d465c3f8cc63af6d74a6a5086b626c1cb4a8c0fee425964c3bd203d9d7094e299f81ce96d58afc20c8c9a029d9dae", "0x89e1c8fbde8563763be483123a3ed702efac189c6d8ab4d16c85e74bbaf856048cc42d5d6e138633a38572ba5ec3f594", "0x893a594cf495535f6d216508f8d03c317dcf03446668cba688da90f52d0111ac83d76ad09bf5ea47056846585ee5c791", "0xaadbd8be0ae452f7f9450c7d2957598a20cbf10139a4023a78b4438172d62b18b0de39754dd2f8862dbd50a3a0815e53", "0xae7d39670ecca3eb6db2095da2517a581b0e8853bdfef619b1fad9aacd443e7e6a40f18209fadd44038a55085c5fe8b2", "0x866ef241520eacb6331593cfcb206f7409d2f33d04542e6e52cba5447934e02d44c471f6c9a45963f9307e9809ab91d9", "0xb1a09911ad3864678f7be79a9c3c3eb5c84a0a45f8dcb52c67148f43439aeaaa9fd3ed3471276b7e588b49d6ebe3033a", "0xadd07b7f0dbb34049cd8feeb3c18da5944bf706871cfd9f14ff72f6c59ad217ebb1f0258b13b167851929387e4e34cfe", "0xae048892d5c328eefbdd4fba67d95901e3c14d974bfc0a1fc68155ca9f0d59e61d7ba17c6c9948b120cf35fd26e6fee9", "0x9185b4f3b7da0ddb4e0d0f09b8a9e0d6943a4611e43f13c3e2a767ed8592d31e0ba3ebe1914026a3627680274291f6e5", "0xa9c022d4e37b0802284ce3b7ee9258628ab4044f0db4de53d1c3efba9de19d15d65cc5e608dbe149c21c2af47d0b07b5", "0xb24dbd5852f8f24921a4e27013b6c3fa8885b973266cb839b9c388efad95821d5d746348179dcc07542bd0d0aefad1ce", "0xb5fb4f279300876a539a27a441348764908bc0051ebd66dc51739807305e73db3d2f6f0f294ffb91b508ab150eaf8527", "0xace50841e718265b290c3483ed4b0fdd1175338c5f1f7530ae9a0e75d5f80216f4de37536adcbc8d8c95982e88808cd0", "0xb19cadcde0f63bd1a9c24bd9c2806f53c14c0b9735bf351601498408ba503ddbd2037c891041cbba47f58b8c483f3b21", "0xb6061e63558d312eb891b97b39aa552fa218568d79ee26fe6dd5b864aea9e3216d8f2e2f3b093503be274766dac41426", "0x89730fdb2876ab6f0fe780d695f6e12090259027e789b819956d786e977518057e5d1d7f5ab24a3ae3d5d4c97773bd2b", "0xb6fa841e81f9f2cad0163a02a63ae96dc341f7ae803b616efc6e1da2fbea551c1b96b11ad02c4afbdf6d0cc9f23da172", "0x8fb66187182629c861ddb6896d7ed3caf2ad050c3dba8ab8eb0d7a2c924c3d44c48d1a148f9e33fb1f061b86972f8d21", "0x86022ac339c1f84a7fa9e05358c1a5b316b4fc0b83dbe9c8c7225dc514f709d66490b539359b084ce776e301024345fa", "0xb50b9c321468da950f01480bb62b6edafd42f83c0001d6e97f2bd523a1c49a0e8574fb66380ea28d23a7c4d54784f9f0", "0xa31c05f7032f30d1dac06678be64d0250a071fd655e557400e4a7f4c152be4d5c7aa32529baf3e5be7c4bd49820054f6", "0xb95ac0848cd322684772119f5b682d90a66bbf9dac411d9d86d2c34844bbd944dbaf8e47aa41380455abd51687931a78", "0xae4a6a5ce9553b65a05f7935e61e496a4a0f6fd8203367a2c627394c9ce1e280750297b74cdc48fd1d9a31e93f97bef4", "0xa22daf35f6e9b05e52e0b07f7bd1dbbebd2c263033fb0e1b2c804e2d964e2f11bc0ece6aca6af079dd3a9939c9c80674", "0x902150e0cb1f16b9b59690db35281e28998ce275acb313900da8b2d8dfd29fa1795f8ca3ff820c31d0697de29df347c1", "0xb17b5104a5dc665cdd7d47e476153d715eb78c6e5199303e4b5445c21a7fa7cf85fe7cfd08d7570f4e84e579b005428c", "0xa03f49b81c15433f121680aa02d734bb9e363af2156654a62bcb5b2ba2218398ccb0ff61104ea5d7df5b16ea18623b1e", "0x802101abd5d3c88876e75a27ffc2f9ddcce75e6b24f23dba03e5201281a7bd5cc7530b6a003be92d225093ca17d3c3bb", "0xa4d183f63c1b4521a6b52226fc19106158fc8ea402461a5cccdaa35fee93669df6a8661f45c1750cd01308149b7bf08e", "0x8d17c22e0c8403b69736364d460b3014775c591032604413d20a5096a94d4030d7c50b9fe3240e31d0311efcf9816a47", "0x947225acfcce5992eab96276f668c3cbe5f298b90a59f2bb213be9997d8850919e8f496f182689b5cbd54084a7332482", "0x8df6f4ed216fc8d1905e06163ba1c90d336ab991a18564b0169623eb39b84e627fa267397da15d3ed754d1f3423bff07", "0x83480007a88f1a36dea464c32b849a3a999316044f12281e2e1c25f07d495f9b1710b4ba0d88e9560e72433addd50bc2", "0xb3019d6e591cf5b33eb972e49e06c6d0a82a73a75d78d383dd6f6a4269838289e6e07c245f54fed67f5c9bb0fd5e1c5f", "0x92e8ce05e94927a9fb02debadb99cf30a26172b2705003a2c0c47b3d8002bf1060edb0f6a5750aad827c98a656b19199", "0xac2aff801448dbbfc13cca7d603fd9c69e82100d997faf11f465323b97255504f10c0c77401e4d1890339d8b224f5803", "0xb0453d9903d08f508ee27e577445dc098baed6cde0ac984b42e0f0efed62760bd58d5816cf1e109d204607b7b175e30c", "0xae68dc4ba5067e825d46d2c7c67f1009ceb49d68e8d3e4c57f4bcd299eb2de3575d42ea45e8722f8f28497a6e14a1cfe", "0xb22486c2f5b51d72335ce819bbafb7fa25eb1c28a378a658f13f9fc79cd20083a7e573248d911231b45a5cf23b561ca7", "0x89d1201d1dbd6921867341471488b4d2fd0fc773ae1d4d074c78ae2eb779a59b64c00452c2a0255826fca6b3d03be2b1", "0xa2998977c91c7a53dc6104f5bc0a5b675e5350f835e2f0af69825db8af4aeb68435bdbcc795f3dd1f55e1dd50bc0507f", "0xb0be4937a925b3c05056ed621910d535ccabf5ab99fd3b9335080b0e51d9607d0fd36cb5781ff340018f6acfca4a9736", "0xaea145a0f6e0ba9df8e52e84bb9c9de2c2dc822f70d2724029b153eb68ee9c17de7d35063dcd6a39c37c59fdd12138f7", "0x91cb4545d7165ee8ffbc74c874baceca11fdebbc7387908d1a25877ca3c57f2c5def424dab24148826832f1e880bede0", "0xb3b579cb77573f19c571ad5eeeb21f65548d7dff9d298b8d7418c11f3e8cd3727c5b467f013cb87d6861cfaceee0d2e3", "0xb98a1eeec2b19fecc8378c876d73645aa52fb99e4819903735b2c7a885b242787a30d1269a04bfb8573d72d9bbc5f0f0", "0x940c1f01ed362bd588b950c27f8cc1d52276c71bb153d47f07ec85b038c11d9a8424b7904f424423e714454d5e80d1cd", "0xaa343a8ecf09ce11599b8cf22f7279cf80f06dbf9f6d62cb05308dbbb39c46fd0a4a1240b032665fbb488a767379b91b", "0x87c3ac72084aca5974599d3232e11d416348719e08443acaba2b328923af945031f86432e170dcdd103774ec92e988c9", "0x91d6486eb5e61d2b9a9e742c20ec974a47627c6096b3da56209c2b4e4757f007e793ebb63b2b246857c9839b64dc0233", "0xaebcd3257d295747dd6fc4ff910d839dd80c51c173ae59b8b2ec937747c2072fa85e3017f9060aa509af88dfc7529481", "0xb3075ba6668ca04eff19efbfa3356b92f0ab12632dcda99cf8c655f35b7928c304218e0f9799d68ef9f809a1492ff7db", "0x93ba7468bb325639ec2abd4d55179c69fd04eaaf39fc5340709227bbaa4ad0a54ea8b480a1a3c8d44684e3be0f8d1980", "0xa6aef86c8c0d92839f38544d91b767c582568b391071228ff5a5a6b859c87bf4f81a7d926094a4ada1993ddbd677a920", "0x91dcd6d14207aa569194aa224d1e5037b999b69ade52843315ca61ba26abe9a76412c9e88259bc5cf5d7b95b97d9c3bc", "0xb3b483d31c88f78d49bd065893bc1e3d2aa637e27dedb46d9a7d60be7660ce7a10aaaa7deead362284a52e6d14021178", "0x8e5730070acf8371461ef301cc4523e8e672aa0e3d945d438a0e0aa6bdf8cb9c685dcf38df429037b0c8aff3955c6f5b", "0xb8c6d769890a8ee18dc4f9e917993315877c97549549b34785a92543cbeec96a08ae3a28d6e809c4aacd69de356c0012", "0x95ca86cd384eaceaa7c077c5615736ca31f36824bd6451a16142a1edc129fa42b50724aeed7c738f08d7b157f78b569e", "0x94df609c6d71e8eee7ab74226e371ccc77e01738fe0ef1a6424435b4570fe1e5d15797b66ed0f64eb88d4a3a37631f0e", "0x89057b9783212add6a0690d6bb99097b182738deff2bd9e147d7fd7d6c8eacb4c219923633e6309ad993c24572289901", "0x83a0f9f5f265c5a0e54defa87128240235e24498f20965009fef664f505a360b6fb4020f2742565dfc7746eb185bcec0", "0x91170da5306128931349bc3ed50d7df0e48a68b8cc8420975170723ac79d8773e4fa13c5f14dc6e3fafcad78379050b1", "0xb7178484d1b55f7e56a4cc250b6b2ec6040437d96bdfddfa7b35ed27435860f3855c2eb86c636f2911b012eb83b00db8", "0xac0b00c4322d1e4208e09cd977b4e54d221133ff09551f75b32b0b55d0e2be80941dda26257b0e288c162e63c7e9cf68", "0x9690ed9e7e53ed37ff362930e4096b878b12234c332fd19d5d064824084245952eda9f979e0098110d6963e468cf513e", "0xb6fa547bb0bb83e5c5be0ed462a8783fba119041c136a250045c09d0d2af330c604331e7de960df976ff76d67f8000cd", "0x814603907c21463bcf4e59cfb43066dfe1a50344ae04ef03c87c0f61b30836c3f4dea0851d6fa358c620045b7f9214c8", "0x9495639e3939fad2a3df00a88603a5a180f3c3a0fe4d424c35060e2043e0921788003689887b1ed5be424d9a89bb18bb", "0xaba4c02d8d57f2c92d5bc765885849e9ff8393d6554f5e5f3e907e5bfac041193a0d8716d7861104a4295d5a03c36b03", "0x8ead0b56c1ca49723f94a998ba113b9058059321da72d9e395a667e6a63d5a9dac0f5717cec343f021695e8ced1f72af", "0xb43037f7e3852c34ed918c5854cd74e9d5799eeddfe457d4f93bb494801a064735e326a76e1f5e50a339844a2f4a8ec9", "0x99db8422bb7302199eb0ff3c3d08821f8c32f53a600c5b6fb43e41205d96adae72be5b460773d1280ad1acb806af9be8", "0x8a9be08eae0086c0f020838925984df345c5512ff32e37120b644512b1d9d4fecf0fd30639ca90fc6cf334a86770d536", "0x81b43614f1c28aa3713a309a88a782fb2bdfc4261dd52ddc204687791a40cf5fd6a263a8179388596582cccf0162efc2", "0xa9f3a8b76912deb61d966c75daf5ddb868702ebec91bd4033471c8e533183df548742a81a2671de5be63a502d827437d", "0x902e2415077f063e638207dc7e14109652e42ab47caccd6204e2870115791c9defac5425fd360b37ac0f7bd8fe7011f8", "0xaa18e4fdc1381b59c18503ae6f6f2d6943445bd00dd7d4a2ad7e5adad7027f2263832690be30d456e6d772ad76f22350", "0xa348b40ba3ba7d81c5d4631f038186ebd5e5f314f1ea737259151b07c3cc8cf0c6ed4201e71bcc1c22fefda81a20cde6", "0xaa1306f7ac1acbfc47dc6f7a0cb6d03786cec8c8dc8060388ccda777bca24bdc634d03e53512c23dba79709ff64f8620", "0x818ccfe46e700567b7f3eb400e5a35f6a5e39b3db3aa8bc07f58ace35d9ae5a242faf8dbccd08d9a9175bbce15612155", "0xb7e3da2282b65dc8333592bb345a473f03bd6df69170055fec60222de9897184536bf22b9388b08160321144d0940279", "0xa4d976be0f0568f4e57de1460a1729129252b44c552a69fceec44e5b97c96c711763360d11f9e5bf6d86b4976bf40d69", "0x85d185f0397c24c2b875b09b6328a23b87982b84ee880f2677a22ff4c9a1ba9f0fea000bb3f7f66375a00d98ebafce17", "0xb4ccbb8c3a2606bd9b87ce022704663af71d418351575f3b350d294f4efc68c26f9a2ce49ff81e6ff29c3b63d746294e", "0x93ffd3265fddb63724dfde261d1f9e22f15ecf39df28e4d89e9fea03221e8e88b5dd9b77628bacaa783c6f91802d47cc", "0xb1fd0f8d7a01378e693da98d03a2d2fda6b099d03454b6f2b1fa6472ff6bb092751ce6290059826b74ac0361eab00e1e", "0xa89f440c71c561641589796994dd2769616b9088766e983c873fae0716b95c386c8483ab8a4f367b6a68b72b7456dd32", "0xaf4fe92b01d42d03dd5d1e7fa55e96d4bbcb7bf7d4c8c197acd16b3e0f3455807199f683dcd263d74547ef9c244b35cc", "0xa8227f6e0a344dfe76bfbe7a1861be32c4f4bed587ccce09f9ce2cf481b2dda8ae4f566154bc663d15f962f2d41761bd", "0xa7b361663f7495939ed7f518ba45ea9ff576c4e628995b7aea026480c17a71d63fc2c922319f0502eb7ef8f14a406882", "0x8ddcf382a9f39f75777160967c07012cfa89e67b19714a7191f0c68eaf263935e5504e1104aaabd0899348c972a8d3c6", "0x98c95b9f6f5c91f805fb185eedd06c6fc4457d37dd248d0be45a6a168a70031715165ea20606245cbdf8815dc0ac697f", "0x805b44f96e001e5909834f70c09be3efcd3b43632bcac5b6b66b6d227a03a758e4b1768ce2a723045681a1d34562aaeb", "0xb0e81b07cdc45b3dca60882676d9badb99f25c461b7efe56e3043b80100bb62d29e1873ae25eb83087273160ece72a55", "0xb0c53f0abe78ee86c7b78c82ae1f7c070bb0b9c45c563a8b3baa2c515d482d7507bb80771e60b38ac13f78b8af92b4a9", "0xa7838ef6696a9e4d2e5dfd581f6c8d6a700467e8fd4e85adabb5f7a56f514785dd4ab64f6f1b48366f7d94728359441b", "0x88c76f7700a1d23c30366a1d8612a796da57b2500f97f88fdf2d76b045a9d24e7426a8ffa2f4e86d3046937a841dad58", "0xad8964baf98c1f02e088d1d9fcb3af6b1dfa44cdfe0ed2eae684e7187c33d3a3c28c38e8f4e015f9c04d451ed6f85ff6", "0x90e9d00a098317ececaa9574da91fc149eda5b772dedb3e5a39636da6603aa007804fa86358550cfeff9be5a2cb7845e", "0xa56ff4ddd73d9a6f5ab23bb77efa25977917df63571b269f6a999e1ad6681a88387fcc4ca3b26d57badf91b236503a29", "0x97ad839a6302c410a47e245df84c01fb9c4dfef86751af3f9340e86ff8fc3cd52fa5ff0b9a0bd1d9f453e02ca80658a6", "0xa4c8c44cbffa804129e123474854645107d1f0f463c45c30fd168848ebea94880f7c0c5a45183e9eb837f346270bdb35", "0xa72e53d0a1586d736e86427a93569f52edd2f42b01e78aee7e1961c2b63522423877ae3ac1227a2cf1e69f8e1ff15bc3", "0x8559f88a7ef13b4f09ac82ae458bbae6ab25671cfbf52dae7eac7280d6565dd3f0c3286aec1a56a8a16dc3b61d78ce47", "0x8221503f4cdbed550876c5dc118a3f2f17800c04e8be000266633c83777b039a432d576f3a36c8a01e8fd18289ebc10b", "0x99bfbe5f3e46d4d898a578ba86ed26de7ed23914bd3bcdf3c791c0bcd49398a52419077354a5ab75cea63b6c871c6e96", "0xaa134416d8ff46f2acd866c1074af67566cfcf4e8be8d97329dfa0f603e1ff208488831ce5948ac8d75bfcba058ddcaa", "0xb02609d65ebfe1fe8e52f21224a022ea4b5ea8c1bd6e7b9792eed8975fc387cdf9e3b419b8dd5bcce80703ab3a12a45f", "0xa4f14798508698fa3852e5cac42a9db9797ecee7672a54988aa74037d334819aa7b2ac7b14efea6b81c509134a6b7ad2", "0x884f01afecbcb987cb3e7c489c43155c416ed41340f61ecb651d8cba884fb9274f6d9e7e4a46dd220253ae561614e44c", "0xa05523c9e71dce1fe5307cc71bd721feb3e1a0f57a7d17c7d1c9fb080d44527b7dbaa1f817b1af1c0b4322e37bc4bb1e", "0x8560aec176a4242b39f39433dd5a02d554248c9e49d3179530815f5031fee78ba9c71a35ceeb2b9d1f04c3617c13d8f0", "0x996aefd402748d8472477cae76d5a2b92e3f092fc834d5222ae50194dd884c9fb8b6ed8e5ccf8f6ed483ddbb4e80c747", "0x8fd09900320000cbabc40e16893e2fcf08815d288ec19345ad7b6bb22f7d78a52b6575a3ca1ca2f8bc252d2eafc928ec", "0x939e51f73022bc5dc6862a0adf8fb8a3246b7bfb9943cbb4b27c73743926cc20f615a036c7e5b90c80840e7f1bfee0e7", "0xa0a6258700cadbb9e241f50766573bf9bdb7ad380b1079dc3afb4054363d838e177b869cad000314186936e40359b1f2", "0x972699a4131c8ed27a2d0e2104d54a65a7ff1c450ad9da3a325c662ab26869c21b0a84d0700b98c8b5f6ce3b746873d7", "0xa454c7fe870cb8aa6491eafbfb5f7872d6e696033f92e4991d057b59d70671f2acdabef533e229878b60c7fff8f748b1", "0xa167969477214201f09c79027b10221e4707662e0c0fde81a0f628249f2f8a859ce3d30a7dcc03b8ecca8f7828ad85c7", "0x8ff6b7265175beb8a63e1dbf18c9153fb2578c207c781282374f51b40d57a84fd2ef2ea2b9c6df4a54646788a62fd17f", "0xa3d7ebeccde69d73d8b3e76af0da1a30884bb59729503ff0fb0c3bccf9221651b974a6e72ea33b7956fc3ae758226495", "0xb71ef144c9a98ce5935620cb86c1590bd4f48e5a2815d25c0cdb008fde628cf628c31450d3d4f67abbfeb16178a74cfd", "0xb5e0a16d115134f4e2503990e3f2035ed66b9ccf767063fe6747870d97d73b10bc76ed668550cb82eedc9a2ca6f75524", "0xb30ffaaf94ee8cbc42aa2c413175b68afdb207dbf351fb20be3852cb7961b635c22838da97eaf43b103aff37e9e725cc", "0x98aa7d52284f6c1f22e272fbddd8c8698cf8f5fbb702d5de96452141fafb559622815981e50b87a72c2b1190f59a7deb", "0x81fbacda3905cfaf7780bb4850730c44166ed26a7c8d07197a5d4dcd969c09e94a0461638431476c16397dd7bdc449f9", "0x95e47021c1726eac2e5853f570d6225332c6e48e04c9738690d53e07c6b979283ebae31e2af1fc9c9b3e59f87e5195b1", "0xac024a661ba568426bb8fce21780406537f518075c066276197300841e811860696f7588188bc01d90bace7bc73d56e3", "0xa4ebcaf668a888dd404988ab978594dee193dad2d0aec5cdc0ccaf4ec9a7a8228aa663db1da8ddc52ec8472178e40c32", "0xa20421b8eaf2199d93b083f2aff37fb662670bd18689d046ae976d1db1fedd2c2ff897985ecc6277b396db7da68bcb27", "0x8bc33d4b40197fd4d49d1de47489d10b90d9b346828f53a82256f3e9212b0cbc6930b895e879da9cec9fedf026aadb3e", "0xaaafdd1bec8b757f55a0433eddc0a39f818591954fd4e982003437fcceb317423ad7ee74dbf17a2960380e7067a6b4e2", "0xaad34277ebaed81a6ec154d16736866f95832803af28aa5625bf0461a71d02b1faba02d9d9e002be51c8356425a56867", "0x976e9c8b150d08706079945bd0e84ab09a648ecc6f64ded9eb5329e57213149ae409ae93e8fbd8eda5b5c69f5212b883", "0x8097fae1653247d2aed4111533bc378171d6b2c6d09cbc7baa9b52f188d150d645941f46d19f7f5e27b7f073c1ebd079", "0x83905f93b250d3184eaba8ea7d727c4464b6bdb027e5cbe4f597d8b9dc741dcbea709630bd4fd59ce24023bec32fc0f3", "0x8095030b7045cff28f34271386e4752f9a9a0312f8df75de4f424366d78534be2b8e1720a19cb1f9a2d21105d790a225", "0xa7b7b73a6ae2ed1009c49960374b0790f93c74ee03b917642f33420498c188a169724945a975e5adec0a1e83e07fb1b2", "0x856a41c54df393b6660b7f6354572a4e71c8bfca9cabaffb3d4ef2632c015e7ee2bc10056f3eccb3dbed1ad17d939178", "0xa8f7a55cf04b38cd4e330394ee6589da3a07dc9673f74804fdf67b364e0b233f14aec42e783200a2e4666f7c5ff62490", "0x82c529f4e543c6bca60016dc93232c115b359eaee2798a9cf669a654b800aafe6ab4ba58ea8b9cdda2b371c8d62fa845", "0x8caab020c1baddce77a6794113ef1dfeafc5f5000f48e97f4351b588bf02f1f208101745463c480d37f588d5887e6d8c", "0x8fa91b3cc400f48b77b6fd77f3b3fbfb3f10cdff408e1fd22d38f77e087b7683adad258804409ba099f1235b4b4d6fea", "0x8aa02787663d6be9a35677d9d8188b725d5fcd770e61b11b64e3def8808ea5c71c0a9afd7f6630c48634546088fcd8e2", "0xb5635b7b972e195cab878b97dea62237c7f77eb57298538582a330b1082f6207a359f2923864630136d8b1f27c41b9aa", "0x8257bb14583551a65975946980c714ecd6e5b629672bb950b9caacd886fbd22704bc9e3ba7d30778adab65dc74f0203a", "0xab5fe1cd12634bfa4e5c60d946e2005cbd38f1063ec9a5668994a2463c02449a0a185ef331bd86b68b6e23a8780cb3ba", "0xa7d3487da56cda93570cc70215d438204f6a2709bfb5fda6c5df1e77e2efc80f4235c787e57fbf2c74aaff8cbb510a14", "0xb61cff7b4c49d010e133319fb828eb900f8a7e55114fc86b39c261a339c74f630e1a7d7e1350244ada566a0ff3d46c4b", "0x8d4d1d55d321d278db7a85522ccceca09510374ca81d4d73e3bb5249ace7674b73900c35a531ec4fa6448fabf7ad00dc", "0x966492248aee24f0f56c8cfca3c8ec6ba3b19abb69ae642041d4c3be8523d22c65c4dafcab4c58989ccc4e0bd2f77919", "0xb20c320a90cb220b86e1af651cdc1e21315cd215da69f6787e28157172f93fc8285dcd59b039c626ed8ca4633cba1a47", "0xaae9e6b22f018ceb5c0950210bb8182cb8cb61014b7e14581a09d36ebd1bbfebdb2b82afb7fdb0cf75e58a293d9c456d", "0x875547fb67951ad37b02466b79f0c9b985ccbc500cfb431b17823457dc79fb9597ec42cd9f198e15523fcd88652e63a4", "0x92afce49773cb2e20fb21e4f86f18e0959ebb9c33361547ddb30454ee8e36b1e234019cbdca0e964cb292f7f77df6b90", "0x8af85343dfe1821464c76ba11c216cbef697b5afc69c4d821342e55afdac047081ec2e3f7b09fc14b518d9a23b78c003", "0xb7de4a1648fd63f3a918096ea669502af5357438e69dac77cb8102b6e6c15c76e033cfaa80dafc806e535ede5c1a20aa", "0xac80e9b545e8bd762951d96c9ce87f629d01ffcde07efc2ef7879ca011f1d0d8a745abf26c9d452541008871304fac00", "0xa4cf0f7ed724e481368016c38ea5816698a5f68eb21af4d3c422d2ba55f96a33e427c2aa40de1b56a7cfac7f7cf43ab0", "0x899b0a678bb2db2cae1b44e75a661284844ebcdd87abf308fedeb2e4dbe5c5920c07db4db7284a7af806a2382e8b111a", "0xaf0588a2a4afce2b1b13c1230816f59e8264177e774e4a341b289a101dcf6af813638fed14fb4d09cb45f35d5d032609", "0xa4b8df79e2be76e9f5fc5845f06fe745a724cf37c82fcdb72719b77bdebea3c0e763f37909373e3a94480cc5e875cba0", "0x83e42c46d88930c8f386b19fd999288f142d325e2ebc86a74907d6d77112cb0d449bc511c95422cc810574031a8cbba9", "0xb5e39534070de1e5f6e27efbdd3dc917d966c2a9b8cf2d893f964256e95e954330f2442027dc148c776d63a95bcde955", "0x958607569dc28c075e658cd4ae3927055c6bc456eef6212a6fea8205e48ed8777a8064f584cda38fe5639c371e2e7fba", "0x812adf409fa63575113662966f5078a903212ffb65c9b0bbe62da0f13a133443a7062cb8fd70f5e5dd5559a32c26d2c8", "0xa679f673e5ce6a3cce7fa31f22ee3785e96bcb55e5a776e2dd3467bef7440e3555d1a9b87cb215e86ee9ed13a090344b", "0xafedbb34508b159eb25eb2248d7fe328f86ef8c7d84c62d5b5607d74aae27cc2cc45ee148eb22153b09898a835c58df4", "0xb75505d4f6b67d31e665cfaf5e4acdb5838ae069166b7fbcd48937c0608a59e40a25302fcc1873d2e81c1782808c70f0", "0xb62515d539ec21a155d94fc00ea3c6b7e5f6636937bce18ed5b618c12257fb82571886287fd5d1da495296c663ebc512", "0xab8e1a9446bbdd588d1690243b1549d230e6149c28f59662b66a8391a138d37ab594df38e7720fae53217e5c3573b5be", "0xb31e8abf4212e03c3287bb2c0a153065a7290a16764a0bac8f112a72e632185a654bb4e88fdd6053e6c7515d9719fadb", "0xb55165477fe15b6abd2d0f4fddaa9c411710dcc4dd712daba3d30e303c9a3ee5415c256f9dc917ecf18c725b4dbab059", "0xa0939d4f57cacaae549b78e87cc234de4ff6a35dc0d9cd5d7410abc30ebcd34c135e008651c756e5a9d2ca79c40ef42b", "0x8cf10e50769f3443340844aad4d56ec790850fed5a41fcbd739abac4c3015f0a085a038fbe7fae9f5ad899cce5069f6b", "0x924055e804d82a99ea4bb160041ea4dc14b568abf379010bc1922fde5d664718c31d103b8b807e3a1ae809390e708c73", "0x8ec0f9d26f71b0f2e60a179e4fd1778452e2ffb129d50815e5d7c7cb9415fa69ae5890578086e8ef6bfde35ad2a74661", "0x98c7f12b15ec4426b59f737f73bf5faea4572340f4550b7590dfb7f7ffedb2372e3e555977c63946d579544c53210ad0", "0x8a935f7a955c78f69d66f18eee0092e5e833fa621781c9581058e219af4d7ceee48b84e472e159dda6199715fb2f9acf", "0xb78d4219f95a2dbfaa7d0c8a610c57c358754f4f43c2af312ab0fe8f10a5f0177e475332fb8fd23604e474fc2abeb051", "0x8d086a14803392b7318c28f1039a17e3cfdcece8abcaca3657ec3d0ac330842098a85c0212f889fabb296dfb133ce9aa", "0xa53249f417aac82f2c2a50c244ce21d3e08a5e5a8bd33bec2a5ab0d6cd17793e34a17edfa3690899244ce201e2fb9986", "0x8619b0264f9182867a1425be514dc4f1ababc1093138a728a28bd7e4ecc99b9faaff68c23792264bc6e4dce5f52a5c52", "0x8c171edbbbde551ec19e31b2091eb6956107dd9b1f853e1df23bff3c10a3469ac77a58335eee2b79112502e8e163f3de", "0xa9d19ec40f0ca07c238e9337c6d6a319190bdba2db76fb63902f3fb459aeeb50a1ac30db5b25ee1b4201f3ca7164a7f4", "0xb9c6ec14b1581a03520b8d2c1fbbc31fb8ceaef2c0f1a0d0080b6b96e18442f1734bea7ef7b635d787c691de4765d469", "0x8cb437beb4cfa013096f40ccc169a713dc17afee6daa229a398e45fd5c0645a9ad2795c3f0cd439531a7151945d7064d", "0xa6e8740cc509126e146775157c2eb278003e5bb6c48465c160ed27888ca803fa12eee1f6a8dd7f444f571664ed87fdc1", "0xb75c1fecc85b2732e96b3f23aefb491dbd0206a21d682aee0225838dc057d7ed3b576176353e8e90ae55663f79e986e4", "0xad8d249b0aea9597b08358bce6c77c1fd552ef3fbc197d6a1cfe44e5e6f89b628b12a6fb04d5dcfcbacc51f46e4ae7bb", "0xb998b2269932cbd58d04b8e898d373ac4bb1a62e8567484f4f83e224061bc0f212459f1daae95abdbc63816ae6486a55", "0x827988ef6c1101cddc96b98f4a30365ff08eea2471dd949d2c0a9b35c3bbfa8c07054ad1f4c88c8fbf829b20bb5a9a4f", "0x8692e638dd60babf7d9f2f2d2ce58e0ac689e1326d88311416357298c6a2bffbfebf55d5253563e7b3fbbf5072264146", "0xa685d75b91aea04dbc14ab3c1b1588e6de96dae414c8e37b8388766029631b28dd860688079b12d09cd27f2c5af11adf", "0xb57eced93eec3371c56679c259b34ac0992286be4f4ff9489d81cf9712403509932e47404ddd86f89d7c1c3b6391b28c", "0xa1c8b4e42ebcbd8927669a97f1b72e236fb19249325659e72be7ddaaa1d9e81ca2abb643295d41a8c04a2c01f9c0efd7", "0x877c33de20d4ed31674a671ba3e8f01a316581e32503136a70c9c15bf0b7cb7b1cba6cd4eb641fad165fb3c3c6c235fd", "0xa2a469d84ec478da40838f775d11ad38f6596eb41caa139cc190d6a10b5108c09febae34ffdafac92271d2e73c143693", "0x972f817caedb254055d52e963ed28c206848b6c4cfdb69dbc961c891f8458eaf582a6d4403ce1177d87bc2ea410ef60a", "0xaccbd739e138007422f28536381decc54bb6bd71d93edf3890e54f9ef339f83d2821697d1a4ac1f5a98175f9a9ecb9b5", "0x8940f8772e05389f823b62b3adc3ed541f91647f0318d7a0d3f293aeeb421013de0d0a3664ea53dd24e5fbe02d7efef6", "0x8ecce20f3ef6212edef07ec4d6183fda8e0e8cad2c6ccd0b325e75c425ee1faba00b5c26b4d95204238931598d78f49d", "0x97cc72c36335bd008afbed34a3b0c7225933faba87f7916d0a6d2161e6f82e0cdcda7959573a366f638ca75d30e9dab1", "0x9105f5de8699b5bdb6bd3bb6cc1992d1eac23929c29837985f83b22efdda92af64d9c574aa9640475087201bbbe5fd73", "0x8ffb33c4f6d05c413b9647eb6933526a350ed2e4278ca2ecc06b0e8026d8dbe829c476a40e45a6df63a633090a3f82ef", "0x8bfc6421fdc9c2d2aaa68d2a69b1a2728c25b84944cc3e6a57ff0c94bfd210d1cbf4ff3f06702d2a8257024d8be7de63", "0xa80e1dc1dddfb41a70220939b96dc6935e00b32fb8be5dff4eed1f1c650002ff95e4af481c43292e3827363b7ec4768a", "0x96f714ebd54617198bd636ba7f7a7f8995a61db20962f2165078d9ed8ee764d5946ef3cbdc7ebf8435bb8d5dd4c1deac", "0x8cdb0890e33144d66391d2ae73f5c71f5a861f72bc93bff6cc399fc25dd1f9e17d8772592b44593429718784802ac377", "0x8ccf9a7f80800ee770b92add734ed45a73ecc31e2af0e04364eefc6056a8223834c7c0dc9dfc52495bdec6e74ce69994", "0xaa0875f423bd68b5f10ba978ddb79d3b96ec093bfbac9ff366323193e339ed7c4578760fb60f60e93598bdf1e5cc4995", "0xa9214f523957b59c7a4cb61a40251ad72aba0b57573163b0dc0f33e41d2df483fb9a1b85a5e7c080e9376c866790f8cb", "0xb6224b605028c6673a536cc8ff9aeb94e7a22e686fda82cf16068d326469172f511219b68b2b3affb7933af0c1f80d07", "0xb6d58968d8a017c6a34e24c2c09852f736515a2c50f37232ac6b43a38f8faa7572cc31dade543b594b61b5761c4781d0", "0x8a97cefe5120020c38deeb861d394404e6c993c6cbd5989b6c9ebffe24f46ad11b4ba6348e2991cbf3949c28cfc3c99d", "0x95bf046f8c3a9c0ce2634be4de3713024daec3fc4083e808903b25ce3ac971145af90686b451efcc72f6b22df0216667", "0xa6a4e2f71b8fa28801f553231eff2794c0f10d12e7e414276995e21195abc9c2983a8997e41af41e78d19ff6fbb2680b", "0x8e5e62a7ca9c2f58ebaab63db2ff1fb1ff0877ae94b7f5e2897f273f684ae639dff44cc65718f78a9c894787602ab26a", "0x8542784383eec4f565fcb8b9fc2ad8d7a644267d8d7612a0f476fc8df3aff458897a38003d506d24142ad18f93554f2b", "0xb7db68ba4616ea072b37925ec4fb39096358c2832cc6d35169e032326b2d6614479f765ae98913c267105b84afcb9bf2", "0x8b31dbb9457d23d416c47542c786e07a489af35c4a87dadb8ee91bea5ac4a5315e65625d78dad2cf8f9561af31b45390", "0xa8545a1d91ac17257732033d89e6b7111db8242e9c6ebb0213a88906d5ef407a2c6fdb444e29504b06368b6efb4f4839", "0xb1bd85d29ebb28ccfb05779aad8674906b267c2bf8cdb1f9a0591dd621b53a4ee9f2942687ee3476740c0b4a7621a3ae", "0xa2b54534e152e46c50d91fff03ae9cd019ff7cd9f4168b2fe7ac08ef8c3bbc134cadd3f9d6bd33d20ae476c2a8596c8a", "0xb19b571ff4ae3e9f5d95acda133c455e72c9ea9973cae360732859836c0341c4c29ab039224dc5bc3deb824e031675d8", "0x940b5f80478648bac025a30f3efeb47023ce20ee98be833948a248bca6979f206bb28fc0f17b90acf3bb4abd3d14d731", "0x8f106b40588586ac11629b96d57808ad2808915d89539409c97414aded90b4ff23286a692608230a52bff696055ba5d6", "0xae6bda03aa10da3d2abbc66d764ca6c8d0993e7304a1bdd413eb9622f3ca1913baa6da1e9f4f9e6cf847f14f44d6924d", "0xa18e7796054a340ef826c4d6b5a117b80927afaf2ebd547794c400204ae2caf277692e2eabb55bc2f620763c9e9da66d", "0x8d2d25180dc2c65a4844d3e66819ccfcf48858f0cc89e1c77553b463ec0f7feb9a4002ce26bc618d1142549b9850f232", "0x863f413a394de42cc8166c1c75d513b91d545fff1de6b359037a742c70b008d34bf8e587afa2d62c844d0c6f0ea753e7", "0x83cd0cf62d63475e7fcad18a2e74108499cdbf28af2113cfe005e3b5887794422da450b1944d0a986eb7e1f4c3b18f25", "0xb4f8b350a6d88fea5ab2e44715a292efb12eb52df738c9b2393da3f1ddee68d0a75b476733ccf93642154bceb208f2b8", "0xb3f52aaa4cd4221cb9fc45936cc67fd3864bf6d26bf3dd86aa85aa55ecfc05f5e392ecce5e7cf9406b4b1c4fce0398c8", "0xb33137084422fb643123f40a6df2b498065e65230fc65dc31791c330e898c51c3a65ff738930f32c63d78f3c9315f85b", "0x91452bfa75019363976bb7337fe3a73f1c10f01637428c135536b0cdc7da5ce558dae3dfc792aa55022292600814a8ef", "0xad6ba94c787cd4361ca642c20793ea44f1f127d4de0bb4a77c7fbfebae0fcadbf28e2cb6f0c12c12a07324ec8c19761d", "0x890aa6248b17f1501b0f869c556be7bf2b1d31a176f9978bb97ab7a6bd4138eed32467951c5ef1871944b7f620542f43", "0x82111db2052194ee7dd22ff1eafffac0443cf969d3762cceae046c9a11561c0fdce9c0711f88ac01d1bed165f8a7cee3", "0xb1527b71df2b42b55832f72e772a466e0fa05743aacc7814f4414e4bcc8d42a4010c9e0fd940e6f254cafedff3cd6543", "0x922370fa49903679fc565f09c16a5917f8125e72acfeb060fcdbadbd1644eb9f4016229756019c93c6d609cda5d5d174", "0xaa4c7d98a96cab138d2a53d4aee8ebff6ef903e3b629a92519608d88b3bbd94de5522291a1097e6acf830270e64c8ee1", "0xb3dc21608a389a72d3a752883a382baaafc61ecc44083b832610a237f6a2363f24195acce529eb4aed4ef0e27a12b66e", "0x94619f5de05e07b32291e1d7ab1d8b7337a2235e49d4fb5f3055f090a65e932e829efa95db886b32b153bdd05a53ec8c", "0xade1e92722c2ffa85865d2426fb3d1654a16477d3abf580cfc45ea4b92d5668afc9d09275d3b79283e13e6b39e47424d", "0xb7201589de7bed094911dd62fcd25c459a8e327ac447b69f541cdba30233063e5ddffad0b67e9c3e34adcffedfd0e13d", "0x809d325310f862d6549e7cb40f7e5fc9b7544bd751dd28c4f363c724a0378c0e2adcb5e42ec8f912f5f49f18f3365c07", "0xa79c20aa533de7a5d671c99eb9eb454803ba54dd4f2efa3c8fec1a38f8308e9905c71e9282955225f686146388506ff6", "0xa85eeacb5e8fc9f3ed06a3fe2dc3108ab9f8c5877b148c73cf26e4e979bf5795edbe2e63a8d452565fd1176ed40402b2", "0x97ef55662f8a1ec0842b22ee21391227540adf7708f491436044f3a2eb18c471525e78e1e14fa292507c99d74d7437c6", "0x93110d64ed5886f3d16ce83b11425576a3a7a9bb831cd0de3f9a0b0f2270a730d68136b4ef7ff035ede004358f419b5c", "0xac9ed0a071517f0ae4f61ce95916a90ba9a77a3f84b0ec50ef7298acdcd44d1b94525d191c39d6bd1bb68f4471428760", "0x98abd6a02c7690f5a339adf292b8c9368dfc12e0f8069cf26a5e0ce54b4441638f5c66ea735142f3c28e00a0024267e6", "0xb51efb73ba6d44146f047d69b19c0722227a7748b0e8f644d0fc9551324cf034c041a2378c56ce8b58d06038fb8a78de", "0x8f115af274ef75c1662b588b0896b97d71f8d67986ae846792702c4742ab855952865ce236b27e2321967ce36ff93357", "0xb3c4548f14d58b3ab03c222da09e4381a0afe47a72d18d50a94e0008797f78e39e99990e5b4757be62310d400746e35a", "0xa9b1883bd5f31f909b8b1b6dcb48c1c60ed20aa7374b3ffa7f5b2ed036599b5bef33289d23c80a5e6420d191723b92f7", "0x85d38dffd99487ae5bb41ab4a44d80a46157bbbe8ef9497e68f061721f74e4da513ccc3422936b059575975f6787c936", "0xadf870fcb96e972c033ab7a35d28ae79ee795f82bc49c3bd69138f0e338103118d5529c53f2d72a9c0d947bf7d312af2", "0xab4c7a44e2d9446c6ff303eb49aef0e367a58b22cc3bb27b4e69b55d1d9ee639c9234148d2ee95f9ca8079b1457d5a75", "0xa386420b738aba2d7145eb4cba6d643d96bda3f2ca55bb11980b318d43b289d55a108f4bc23a9606fb0bccdeb3b3bb30", "0x847020e0a440d9c4109773ecca5d8268b44d523389993b1f5e60e541187f7c597d79ebd6e318871815e26c96b4a4dbb1", "0xa530aa7e5ca86fcd1bec4b072b55cc793781f38a666c2033b510a69e110eeabb54c7d8cbcb9c61fee531a6f635ffa972", "0x87364a5ea1d270632a44269d686b2402da737948dac27f51b7a97af80b66728b0256547a5103d2227005541ca4b7ed04", "0x8816fc6e16ea277de93a6d793d0eb5c15e9e93eb958c5ef30adaf8241805adeb4da8ce19c3c2167f971f61e0b361077d", "0x8836a72d301c42510367181bb091e4be377777aed57b73c29ef2ce1d475feedd7e0f31676284d9a94f6db01cc4de81a2", "0xb0d9d8b7116156d9dde138d28aa05a33e61f8a85839c1e9071ccd517b46a5b4b53acb32c2edd7150c15bc1b4bd8db9e3", "0xae931b6eaeda790ba7f1cd674e53dc87f6306ff44951fa0df88d506316a5da240df9794ccbd7215a6470e6b31c5ea193", "0x8c6d5bdf87bd7f645419d7c6444e244fe054d437ed1ba0c122fde7800603a5fadc061e5b836cb22a6cfb2b466f20f013", "0x90d530c6d0cb654999fa771b8d11d723f54b8a8233d1052dc1e839ea6e314fbed3697084601f3e9bbb71d2b4eaa596df", "0xb0d341a1422588c983f767b1ed36c18b141774f67ef6a43cff8e18b73a009da10fc12120938b8bba27f225bdfd3138f9", "0xa131b56f9537f460d304e9a1dd75702ace8abd68cb45419695cb8dee76998139058336c87b7afd6239dc20d7f8f940cc", "0xaa6c51fa28975f709329adee1bbd35d49c6b878041841a94465e8218338e4371f5cb6c17f44a63ac93644bf28f15d20f", "0x88440fb584a99ebd7f9ea04aaf622f6e44e2b43bbb49fb5de548d24a238dc8f26c8da2ccf03dd43102bda9f16623f609", "0x9777b8695b790e702159a4a750d5e7ff865425b95fa0a3c15495af385b91c90c00a6bd01d1b77bffe8c47d01baae846f", "0x8b9d764ece7799079e63c7f01690c8eff00896a26a0d095773dea7a35967a8c40db7a6a74692f0118bf0460c26739af4", "0x85808c65c485520609c9e61fa1bb67b28f4611d3608a9f7a5030ee61c3aa3c7e7dc17fff48af76b4aecee2cb0dbd22ac", "0xad2783a76f5b3db008ef5f7e67391fda4e7e36abde6b3b089fc4835b5c339370287935af6bd53998bed4e399eda1136d", "0x96f18ec03ae47c205cc4242ca58e2eff185c9dca86d5158817e2e5dc2207ab84aadda78725f8dc080a231efdc093b940", "0x97de1ab6c6cc646ae60cf7b86df73b9cf56cc0cd1f31b966951ebf79fc153531af55ca643b20b773daa7cab784b832f7", "0x870ba266a9bfa86ef644b1ef025a0f1b7609a60de170fe9508de8fd53170c0b48adb37f19397ee8019b041ce29a16576", "0xad990e888d279ac4e8db90619d663d5ae027f994a3992c2fbc7d262b5990ae8a243e19157f3565671d1cb0de17fe6e55", "0x8d9d5adcdd94c5ba3be4d9a7428133b42e485f040a28d16ee2384758e87d35528f7f9868de9bd23d1a42a594ce50a567", "0x85a33ed75d514ece6ad78440e42f7fcdb59b6f4cff821188236d20edae9050b3a042ce9bc7d2054296e133d033e45022", "0x92afd2f49a124aaba90de59be85ff269457f982b54c91b06650c1b8055f9b4b0640fd378df02a00e4fc91f7d226ab980", "0x8c0ee09ec64bd831e544785e3d65418fe83ed9c920d9bb4d0bf6dd162c1264eb9d6652d2def0722e223915615931581c", "0x8369bedfa17b24e9ad48ebd9c5afea4b66b3296d5770e09b00446c5b0a8a373d39d300780c01dcc1c6752792bccf5fd0", "0x8b9e960782576a59b2eb2250d346030daa50bbbec114e95cdb9e4b1ba18c3d34525ae388f859708131984976ca439d94", "0xb682bface862008fea2b5a07812ca6a28a58fd151a1d54c708fc2f8572916e0d678a9cb8dc1c10c0470025c8a605249e", "0xa38d5e189bea540a824b36815fc41e3750760a52be0862c4cac68214febdc1a754fb194a7415a8fb7f96f6836196d82a", "0xb9e7fbda650f18c7eb8b40e42cc42273a7298e65e8be524292369581861075c55299ce69309710e5b843cb884de171bd", "0xb6657e5e31b3193874a1bace08f42faccbd3c502fb73ad87d15d18a1b6c2a146f1baa929e6f517db390a5a47b66c0acf", "0xae15487312f84ed6265e4c28327d24a8a0f4d2d17d4a5b7c29b974139cf93223435aaebe3af918f5b4bb20911799715f", "0x8bb4608beb06bc394e1a70739b872ce5a2a3ffc98c7547bf2698c893ca399d6c13686f6663f483894bccaabc3b9c56ad", "0xb58ac36bc6847077584308d952c5f3663e3001af5ecf2e19cb162e1c58bd6c49510205d453cffc876ca1dc6b8e04a578", "0x924f65ced61266a79a671ffb49b300f0ea44c50a0b4e3b02064faa99fcc3e4f6061ea8f38168ab118c5d47bd7804590e", "0x8d67d43b8a06b0ff4fafd7f0483fa9ed1a9e3e658a03fb49d9d9b74e2e24858dc1bed065c12392037b467f255d4e5643", "0xb4d4f87813125a6b355e4519a81657fa97c43a6115817b819a6caf4823f1d6a1169683fd68f8d025cdfa40ebf3069acb", "0xa7fd4d2c8e7b59b8eed3d4332ae94b77a89a2616347402f880bc81bde072220131e6dbec8a605be3a1c760b775375879", "0x8d4a7d8fa6f55a30df37bcf74952e2fa4fd6676a2e4606185cf154bdd84643fd01619f8fb8813a564f72e3f574f8ce30", "0x8086fb88e6260e9a9c42e9560fde76315ff5e5680ec7140f2a18438f15bc2cc7d7d43bfb5880b180b738c20a834e6134", "0x916c4c54721de03934fee6f43de50bb04c81f6f8dd4f6781e159e71c40c60408aa54251d457369d133d4ba3ed7c12cb4", "0x902e5bf468f11ed9954e2a4a595c27e34abe512f1d6dc08bbca1c2441063f9af3dc5a8075ab910a10ff6c05c1c644a35", "0xa1302953015e164bf4c15f7d4d35e3633425a78294406b861675667eec77765ff88472306531e5d3a4ec0a2ff0dd6a9e", "0x87874461df3c9aa6c0fa91325576c0590f367075f2f0ecfeb34afe162c04c14f8ce9d608c37ac1adc8b9985bc036e366", "0x84b50a8a61d3cc609bfb0417348133e698fe09a6d37357ce3358de189efcf35773d78c57635c2d26c3542b13cc371752", "0xacaed2cff8633d12c1d12bb7270c54d65b0b0733ab084fd47f81d0a6e1e9b6f300e615e79538239e6160c566d8bb8d29", "0x889e6a0e136372ca4bac90d1ab220d4e1cad425a710e8cdd48b400b73bb8137291ceb36a39440fa84305783b1d42c72f", "0x90952e5becec45b2b73719c228429a2c364991cf1d5a9d6845ae5b38018c2626f4308daa322cab1c72e0f6c621bb2b35", "0x8f5a97a801b6e9dcd66ccb80d337562c96f7914e7169e8ff0fda71534054c64bf2a9493bb830623d612cfe998789be65", "0x84f3df8b9847dcf1d63ca470dc623154898f83c25a6983e9b78c6d2d90a97bf5e622445be835f32c1e55e6a0a562ea78", "0x91d12095cd7a88e7f57f254f02fdb1a1ab18984871dead2f107404bcf8069fe68258c4e6f6ebd2477bddf738135400bb", "0xb771a28bc04baef68604d4723791d3712f82b5e4fe316d7adc2fc01b935d8e644c06d59b83bcb542afc40ebafbee0683", "0x872f6341476e387604a7e93ae6d6117e72d164e38ebc2b825bc6df4fcce815004d7516423c190c1575946b5de438c08d", "0x90d6b4aa7d40a020cdcd04e8b016d041795961a8e532a0e1f4041252131089114a251791bf57794cadb7d636342f5d1c", "0x899023ba6096a181448d927fed7a0fe858be4eac4082a42e30b3050ee065278d72fa9b9d5ce3bc1372d4cbd30a2f2976", "0xa28f176571e1a9124f95973f414d5bdbf5794d41c3839d8b917100902ac4e2171eb940431236cec93928a60a77ede793", "0x838dbe5bcd29c4e465d02350270fa0036cd46f8730b13d91e77afb7f5ed16525d0021d3b2ae173a76c378516a903e0cb", "0x8e105d012dd3f5d20f0f1c4a7e7f09f0fdd74ce554c3032e48da8cce0a77260d7d47a454851387770f5c256fa29bcb88", "0x8f4df0f9feeb7a487e1d138d13ea961459a6402fd8f8cabb226a92249a0d04ded5971f3242b9f90d08da5ff66da28af6", "0xad1cfda4f2122a20935aa32fb17c536a3653a18617a65c6836700b5537122af5a8206befe9eaea781c1244c43778e7f1", "0x832c6f01d6571964ea383292efc8c8fa11e61c0634a25fa180737cc7ab57bc77f25e614aac9a2a03d98f27b3c1c29de2", "0x903f89cc13ec6685ac7728521898781fecb300e9094ef913d530bf875c18bcc3ceed7ed51e7b482d45619ab4b025c2e9", "0xa03c474bb915aad94f171e8d96f46abb2a19c9470601f4c915512ec8b9e743c3938450a2a5b077b4618b9df8809e1dc1", "0x83536c8456f306045a5f38ae4be2e350878fa7e164ea408d467f8c3bc4c2ee396bd5868008c089183868e4dfad7aa50b", "0x88f26b4ea1b236cb326cd7ad7e2517ec8c4919598691474fe15d09cabcfc37a8d8b1b818f4d112432ee3a716b0f37871", "0xa44324e3fe96e9c12b40ded4f0f3397c8c7ee8ff5e96441118d8a6bfad712d3ac990b2a6a23231a8f691491ac1fd480f", "0xb0de4693b4b9f932191a21ee88629964878680152a82996c0019ffc39f8d9369bbe2fe5844b68d6d9589ace54af947e4", "0x8e5d8ba948aea5fd26035351a960e87f0d23efddd8e13236cc8e4545a3dda2e9a85e6521efb8577e03772d3637d213d9", "0x93efc82d2017e9c57834a1246463e64774e56183bb247c8fc9dd98c56817e878d97b05f5c8d900acf1fbbbca6f146556", "0x8731176363ad7658a2862426ee47a5dce9434216cef60e6045fa57c40bb3ce1e78dac4510ae40f1f31db5967022ced32", "0xb10c9a96745722c85bdb1a693100104d560433d45b9ac4add54c7646a7310d8e9b3ca9abd1039d473ae768a18e489845", "0xa2ac374dfbb464bf850b4a2caf15b112634a6428e8395f9c9243baefd2452b4b4c61b0cb2836d8eae2d57d4900bf407e", "0xb69fe3ded0c4f5d44a09a0e0f398221b6d1bf5dbb8bc4e338b93c64f1a3cac1e4b5f73c2b8117158030ec03787f4b452", "0x8852cdbaf7d0447a8c6f211b4830711b3b5c105c0f316e3a6a18dcfbb9be08bd6f4e5c8ae0c3692da08a2dfa532f9d5c", "0x93bbf6d7432a7d98ade3f94b57bf9f4da9bc221a180a370b113066dd42601bb9e09edd79e2e6e04e00423399339eebda", "0xa80941c391f1eeafc1451c59e4775d6a383946ff22997aeaadf806542ba451d3b0f0c6864eeba954174a296efe2c1550", "0xa045fe2bb011c2a2f71a0181a8f457a3078470fb74c628eab8b59aef69ffd0d649723bf74d6885af3f028bc5a104fb39", "0xb9d8c35911009c4c8cad64692139bf3fc16b78f5a19980790cb6a7aea650a25df4231a4437ae0c351676a7e42c16134f", "0x94c79501ded0cfcbab99e1841abe4a00a0252b3870e20774c3da16c982d74c501916ec28304e71194845be6e3113c7ab", "0x900a66418b082a24c6348d8644ddb1817df5b25cb33044a519ef47cc8e1f7f1e38d2465b7b96d32ed472d2d17f8414c6", "0xb26f45d393b8b2fcb29bdbb16323dc7f4b81c09618519ab3a39f8ee5bd148d0d9f3c0b5dfab55b5ce14a1cb9206d777b", "0xaa1a87735fc493a80a96a9a57ca40a6d9c32702bfcaa9869ce1a116ae65d69cefe2f3e79a12454b4590353e96f8912b4", "0xa922b188d3d0b69b4e4ea2a2aa076566962844637da12c0832105d7b31dea4a309eee15d12b7a336be3ea36fcbd3e3b7", "0x8f3841fcf4105131d8c4d9885e6e11a46c448226401cf99356c291fadb864da9fa9d30f3a73c327f23f9fd99a11d633e", "0x9791d1183fae270e226379af6c497e7da803ea854bb20afa74b253239b744c15f670ee808f708ede873e78d79a626c9a", "0xa4cad52e3369491ada61bf28ada9e85de4516d21c882e5f1cd845bea9c06e0b2887b0c5527fcff6fc28acd3c04f0a796", "0xb9ac86a900899603452bd11a7892a9bfed8054970bfcbeaa8c9d1930db891169e38d6977f5258c25734f96c8462eee3b", "0xa3a154c28e5580656a859f4efc2f5ebfa7eaa84ca40e3f134fa7865e8581586db74992dbfa4036aa252fba103773ddde", "0x95cc2a0c1885a029e094f5d737e3ecf4d26b99036453a8773c77e360101f9f98676ee246f6f732a377a996702d55691f", "0x842651bbe99720438d8d4b0218feb60481280c05beb17750e9ca0d8c0599a60f873b7fbdcc7d8835ba9a6d57b16eec03", "0x81ee54699da98f5620307893dcea8f64670609fa20e5622265d66283adeac122d458b3308c5898e6c57c298db2c8b24f", "0xb97868b0b2bc98032d68352a535a1b341b9ff3c7af4e3a7f3ebc82d3419daa1b5859d6aedc39994939623c7cd878bd9b", "0xb60325cd5d36461d07ef253d826f37f9ee6474a760f2fff80f9873d01fd2b57711543cdc8d7afa1c350aa753c2e33dea", "0x8c205326c11d25a46717b780c639d89714c7736c974ae71287e3f4b02e6605ac2d9b4928967b1684f12be040b7bf2dd3", "0x95a392d82db51e26ade6c2ccd3396d7e40aff68fa570b5951466580d6e56dda51775dce5cf3a74a7f28c3cb2eb551c4d", "0x8f2cc8071eb56dffb70bda6dd433b556221dc8bba21c53353c865f00e7d4d86c9e39f119ea9a8a12ef583e9a55d9a6b6", "0x9449a71af9672aaf8856896d7e3d788b22991a7103f75b08c0abbcc2bfe60fda4ed8ce502cea4511ff0ea52a93e81222", "0x857090ab9fdb7d59632d068f3cc8cf27e61f0d8322d30e6b38e780a1f05227199b4cd746aac1311c36c659ef20931f28", "0x98a891f4973e7d9aaf9ac70854608d4f7493dffc7e0987d7be9dd6029f6ea5636d24ef3a83205615ca1ff403750058e1", "0xa486e1365bbc278dd66a2a25d258dc82f46b911103cb16aab3945b9c95ae87b386313a12b566df5b22322ede0afe25ad", "0xa9a1eb399ed95d396dccd8d1ac718043446f8b979ec62bdce51c617c97a312f01376ab7fb87d27034e5f5570797b3c33", "0xb7abc3858d7a74bb446218d2f5a037e0fae11871ed9caf44b29b69c500c1fa1dcfad64c9cdccc9d80d5e584f06213deb", "0x8cfb09fe2e202faa4cebad932b1d35f5ca204e1c2a0c740a57812ac9a6792130d1312aabd9e9d4c58ca168bfebd4c177", "0xa90a305c2cd0f184787c6be596fa67f436afd1f9b93f30e875f817ac2aae8bdd2e6e656f6be809467e6b3ad84adb86b1", "0x80a9ef993c2b009ae172cc8f7ec036f5734cf4f4dfa06a7db4d54725e7fbfae5e3bc6f22687bdbb6961939d6f0c87537", "0x848ade1901931e72b955d7db1893f07003e1708ff5d93174bac5930b9a732640f0578839203e9b77eb27965c700032d3", "0x93fdf4697609c5ae9c33b9ca2f5f1af44abeb2b98dc4fdf732cf7388de086f410730dc384d9b7a7f447bb009653c8381", "0x89ce3fb805aea618b5715c0d22a9f46da696b6fa86794f56fdf1d44155a33d42daf1920bcbe36cbacf3cf4c92df9cbc7", "0x829ce2c342cf82aa469c65f724f308f7a750bd1494adc264609cd790c8718b8b25b5cab5858cf4ee2f8f651d569eea67", "0xaf2f0cee7bf413204be8b9df59b9e4991bc9009e0d6dbe6815181df0ec2ca93ab8f4f3135b1c14d8f53d74bff0bd6f27", "0xb87998cecf7b88cde93d1779f10a521edd5574a2fbd240102978639ec57433ba08cdb53849038a329cebbe74657268d2", "0xa64542a1261a6ed3d720c2c3a802303aad8c4c110c95d0f12e05c1065e66f42da494792b6bfc5b9272363f3b1d457f58", "0x86a6fd042e4f282fadf07a4bfee03fc96a3aea49f7a00f52bf249a20f1ec892326855410e61f37fbb27d9305eb2fc713", "0x967ea5bc403b6db269682f7fd0df90659350d7e1aa66bc4fab4c9dfcd75ed0bba4b52f1cebc5f34dc8ba810793727629", "0xa52990f9f3b8616ce3cdc2c74cd195029e6a969753dcf2d1630438700e7d6ebde36538532b3525ac516f5f2ce9dd27a3", "0xa64f7ff870bab4a8bf0d4ef6f5c744e9bf1021ed08b4c80903c7ad318e80ba1817c3180cc45cb5a1cae1170f0241655f", "0xb00f706fa4de1f663f021e8ad3d155e84ce6084a409374b6e6cd0f924a0a0b51bebaaaf1d228c77233a73b0a5a0df0e9", "0x8b882cc3bff3e42babdb96df95fb780faded84887a0a9bab896bef371cdcf169d909f5658649e93006aa3c6e1146d62e", "0x9332663ef1d1dcf805c3d0e4ce7a07d9863fb1731172e766b3cde030bf81682cc011e26b773fb9c68e0477b4ae2cfb79", "0xa8aa8151348dbd4ef40aaeb699b71b4c4bfd3218560c120d85036d14f678f6736f0ec68e80ce1459d3d35feccc575164", "0xa16cd8b729768f51881c213434aa28301fa78fcb554ddd5f9012ee1e4eae7b5cb3dd88d269d53146dea92d10790faf0b", "0x86844f0ef9d37142faf3b1e196e44fbe280a3ba4189aa05c356778cb9e3b388a2bff95eed305ada8769935c9974e4c57", "0xae2eec6b328fccf3b47bcdac32901ac2744a51beb410b04c81dea34dee4912b619466a4f5e2780d87ecefaebbe77b46d", "0x915df4c38d301c8a4eb2dc5b1ba0ffaad67cbb177e0a80095614e9c711f4ef24a4cef133f9d982a63d2a943ba6c8669d", "0xae6a2a4dedfc2d1811711a8946991fede972fdf2a389b282471280737536ffc0ac3a6d885b1f8bda0366eb0b229b9979", "0xa9b628c63d08b8aba6b1317f6e91c34b2382a6c85376e8ef2410a463c6796740ae936fc4e9e0737cb9455d1daa287bd8", "0x848e30bf7edf2546670b390d5cf9ab71f98fcb6add3c0b582cb34996c26a446dee5d1bde4fdcde4fc80c10936e117b29", "0x907d6096c7c8c087d1808dd995d5d2b9169b3768c3f433475b50c2e2bd4b082f4d543afd8b0b0ddffa9c66222a72d51d", "0xa59970a2493b07339124d763ac9d793c60a03354539ecbcf6035bc43d1ea6e35718202ae6d7060b7d388f483d971573c", "0xb9cfef2af9681b2318f119d8611ff6d9485a68d8044581b1959ab1840cbca576dbb53eec17863d2149966e9feb21122f", "0xad47271806161f61d3afa45cdfe2babceef5e90031a21779f83dc8562e6076680525b4970b2f11fe9b2b23c382768323", "0x8e425a99b71677b04fe044625d338811fbb8ee32368a424f6ab2381c52e86ee7a6cecedf777dc97181519d41c351bc22", "0x86b55b54d7adefc12954a9252ee23ae83efe8b5b4b9a7dc307904413e5d69868c7087a818b2833f9b004213d629be8ad", "0xa14fda6b93923dd11e564ae4457a66f397741527166e0b16a8eb91c6701c244fd1c4b63f9dd3515193ec88fa6c266b35", "0xa9b17c36ae6cd85a0ed7f6cabc5b47dc8f80ced605db327c47826476dc1fb8f8669aa7a7dc679fbd4ee3d8e8b4bd6a6f", "0x82a0829469c1458d959c821148f15dacae9ea94bf56c59a6ab2d4dd8b3d16d73e313b5a3912a6c1f131d73a8f06730c4", "0xb22d56d549a53eaef549595924bdb621ff807aa4513feedf3fdcbf7ba8b6b9cfa4481c2f67fc642db397a6b794a8b63a", "0x974c59c24392e2cb9294006cbe3c52163e255f3bd0c2b457bdc68a6338e6d5b6f87f716854492f8d880a6b896ccf757c", "0xb70d247ba7cad97c50b57f526c2ba915786e926a94e8f8c3eebc2e1be6f4255411b9670e382060049c8f4184302c40b2", "0xad80201fe75ef21c3ddbd98cf23591e0d7a3ba1036dfe77785c32f44755a212c31f0ceb0a0b6f5ee9b6dc81f358d30c3", "0x8c656e841f9bb90b9a42d425251f3fdbc022a604d75f5845f479ed4be23e02aaf9e6e56cde351dd7449c50574818a199", "0x8b88dd3fa209d3063b7c5b058f7249ee9900fbc2287d16da61a0704a0a1d71e45d9c96e1cda7fdf9654534ec44558b22", "0x961da00cc8750bd84d253c08f011970ae1b1158ad6778e8ed943d547bceaf52d6d5a212a7de3bf2706688c4389b827d2", "0xa5dd379922549a956033e3d51a986a4b1508e575042b8eaa1df007aa77cf0b8c2ab23212f9c075702788fa9c53696133", "0xac8fcfde3a349d1e93fc8cf450814e842005c545c4844c0401bc80e6b96cdb77f29285a14455e167c191d4f312e866cd", "0xac63d79c799783a8466617030c59dd5a8f92ee6c5204676fd8d881ce5f7f8663bdbeb0379e480ea9b6340ab0dc88e574", "0x805874fde19ce359041ae2bd52a39e2841acabfd31f965792f2737d7137f36d4e4722ede8340d8c95afa6af278af8acb", "0x8d2f323a228aa8ba7b7dc1399138f9e6b41df1a16a7069003ab8104b8b68506a45141bc5fe66acf430e23e13a545190b", "0xa1610c721a2d9af882bb6b39bea97cff1527a3aea041d25934de080214ae77c959e79957164440686d15ab301e897d4d", "0xaba16d29a47fc36f12b654fde513896723e2c700c4190f11b26aa4011da57737ad717daa02794aa3246e4ae5f0b0cc3a", "0xa406db2f15fdd135f346cc4846623c47edd195e80ba8c7cb447332095314d565e4040694ca924696bb5ee7f8996ea0ba", "0x8b30e2cd9b47d75ba57b83630e40f832249af6c058d4f490416562af451993eec46f3e1f90bc4d389e4c06abd1b32a46", "0xaacf9eb7036e248e209adbfc3dd7ce386569ea9b312caa4b240726549db3c68c4f1c8cbf8ed5ea9ea60c7e57c9df3b8e", "0xb20fcac63bf6f5ee638a42d7f89be847f348c085ddcbec3fa318f4323592d136c230495f188ef2022aa355cc2b0da6f9", "0x811eff750456a79ec1b1249d76d7c1547065b839d8d4aaad860f6d4528eb5b669473dcceeeea676cddbc3980b68461b7", "0xb52d14ae33f4ab422f953392ae76a19c618cc31afc96290bd3fe2fb44c954b5c92c4789f3f16e8793f2c0c1691ade444", "0xa7826dafeeba0db5b66c4dfcf2b17fd7b40507a5a53ac2e42942633a2cb30b95ba1739a6e9f3b7a0e0f1ec729bf274e2", "0x8acfd83ddf7c60dd7c8b20c706a3b972c65d336b8f9b3d907bdd8926ced271430479448100050b1ef17578a49c8fa616", "0xaf0c69f65184bb06868029ad46f8465d75c36814c621ac20a5c0b06a900d59305584f5a6709683d9c0e4b6cd08d650a6", "0xb6cc8588191e00680ee6c3339bd0f0a17ad8fd7f4be57d5d7075bede0ea593a19e67f3d7c1a20114894ee5bfcab71063", "0xa82fd4f58635129dbb6cc3eb9391cf2d28400018b105fc41500fbbd12bd890b918f97d3d359c29dd3b4c4e34391dfab0", "0x92fc544ed65b4a3625cf03c41ddff7c039bc22d22c0d59dcc00efd5438401f2606adb125a1d5de294cca216ec8ac35a3", "0x906f67e4a32582b71f15940523c0c7ce370336935e2646bdaea16a06995256d25e99df57297e39d6c39535e180456407", "0x97510337ea5bbd5977287339197db55c60533b2ec35c94d0a460a416ae9f60e85cee39be82abeeacd5813cf54df05862", "0x87e6894643815c0ea48cb96c607266c5ee4f1f82ba5fe352fb77f9b6ed14bfc2b8e09e80a99ac9047dfcf62b2ae26795", "0xb6fd55dd156622ad7d5d51b7dde75e47bd052d4e542dd6449e72411f68275775c846dde301e84613312be8c7bce58b07", "0xb98461ac71f554b2f03a94e429b255af89eec917e208a8e60edf5fc43b65f1d17a20de3f31d2ce9f0cb573c25f2f4d98", "0x96f0dea40ca61cefbee41c4e1fe9a7d81fbe1f49bb153d083ab70f5d0488a1f717fd28cedcf6aa18d07cce2c62801898", "0x8d7c3ab310184f7dc34b6ce4684e4d29a31e77b09940448ea4daac730b7eb308063125d4dd229046cf11bfd521b771e0", "0x96f0564898fe96687918bbf0a6adead99cf72e3a35ea3347e124af9d006221f8e82e5a9d2fe80094d5e8d48e610f415e", "0xad50fcb92c2675a398cf07d4c40a579e44bf8d35f27cc330b57e54d5ea59f7d898af0f75dccfe3726e5471133d70f92b", "0x828beed62020361689ae7481dd8f116902b522fb0c6c122678e7f949fdef70ead011e0e6bffd25678e388744e17cdb69", "0x8349decac1ca16599eee2efc95bcaabf67631107da1d34a2f917884bd70dfec9b4b08ab7bc4379d6c73b19c0b6e54fb8", "0xb2a6a2e50230c05613ace9e58bb2e98d94127f196f02d9dddc53c43fc68c184549ca12d713cb1b025d8260a41e947155", "0x94ff52181aadae832aed52fc3b7794536e2a31a21fc8be3ea312ca5c695750d37f08002f286b33f4023dba1e3253ecfa", "0xa21d56153c7e5972ee9a319501be4faff199fdf09bb821ea9ce64aa815289676c00f105e6f00311b3a5b627091b0d0fc", "0xa27a60d219f1f0c971db73a7f563b371b5c9fc3ed1f72883b2eac8a0df6698400c9954f4ca17d7e94e44bd4f95532afb", "0xa2fc56fae99b1f18ba5e4fe838402164ce82f8a7f3193d0bbd360c2bac07c46f9330c4c7681ffb47074c6f81ee6e7ac6", "0xb748e530cd3afb96d879b83e89c9f1a444f54e55372ab1dcd46a0872f95ce8f49cf2363fc61be82259e04f555937ed16", "0x8bf8993e81080c7cbba1e14a798504af1e4950b2f186ab3335b771d6acaee4ffe92131ae9c53d74379d957cb6344d9cd", "0x96774d0ef730d22d7ab6d9fb7f90b9ead44285219d076584a901960542756700a2a1603cdf72be4708b267200f6c36a9", "0xb47703c2ab17be1e823cc7bf3460db1d6760c0e33862c90ca058845b2ff234b0f9834ddba2efb2ee1770eb261e7d8ffd", "0x84319e67c37a9581f8b09b5e4d4ae88d0a7fb4cbb6908971ab5be28070c3830f040b1de83ee663c573e0f2f6198640e4", "0x96811875fa83133e0b3c0e0290f9e0e28bca6178b77fdf5350eb19344d453dbd0d71e55a0ef749025a5a2ca0ad251e81", "0x81a423423e9438343879f2bfd7ee9f1c74ebebe7ce3cfffc8a11da6f040cc4145c3b527bd3cf63f9137e714dbcb474ef", "0xb8c3535701ddbeec2db08e17a4fa99ba6752d32ece5331a0b8743676f421fcb14798afc7c783815484f14693d2f70db8", "0x81aee980c876949bf40782835eec8817d535f6f3f7e00bf402ddd61101fdcd60173961ae90a1cf7c5d060339a18c959d", "0x87e67b928d97b62c49dac321ce6cb680233f3a394d4c9a899ac2e8db8ccd8e00418e66cdfd68691aa3cb8559723b580c", "0x8eac204208d99a2b738648df96353bbb1b1065e33ee4f6bba174b540bbbd37d205855e1f1e69a6b7ff043ca377651126", "0x848e6e7a54ad64d18009300b93ea6f459ce855971dddb419b101f5ac4c159215626fadc20cc3b9ab1701d8f6dfaddd8b", "0x88aa123d9e0cf309d46dddb6acf634b1ade3b090a2826d6e5e78669fa1220d6df9a6697d7778cd9b627db17eea846126", "0x9200c2a629b9144d88a61151b661b6c4256cc5dadfd1e59a8ce17a013c2d8f7e754aabe61663c3b30f1bc47784c1f8cf", "0xb6e1a2827c3bdda91715b0e1b1f10dd363cef337e7c80cac1f34165fc0dea7c8b69747e310563db5818390146ce3e231", "0x92c333e694f89f0d306d54105b2a5dcc912dbe7654d9e733edab12e8537350815be472b063e56cfde5286df8922fdecb", "0xa6fac04b6d86091158ebb286586ccfec2a95c9786e14d91a9c743f5f05546073e5e3cc717635a0c602cad8334e922346", "0xa581b4af77feebc1fb897d49b5b507c6ad513d8f09b273328efbb24ef0d91eb740d01b4d398f2738125dacfe550330cd", "0x81c4860cccf76a34f8a2bc3f464b7bfd3e909e975cce0d28979f457738a56e60a4af8e68a3992cf273b5946e8d7f76e2", "0x8d1eaa09a3180d8af1cbaee673db5223363cc7229a69565f592fa38ba0f9d582cedf91e15dabd06ebbf2862fc0feba54", "0x9832f49b0147f4552402e54593cfa51f99540bffada12759b71fcb86734be8e500eea2d8b3d036710bdf04c901432de9", "0x8bdb0e8ec93b11e5718e8c13cb4f5de545d24829fd76161216340108098dfe5148ed25e3b57a89a516f09fa79043734d", "0xab96f06c4b9b0b2c0571740b24fca758e6976315053a7ecb20119150a9fa416db2d3a2e0f8168b390bb063f0c1caf785", "0xab777f5c52acd62ecf4d1f168b9cc8e1a9b45d4ec6a8ff52c583e867c2239aba98d7d3af977289b367edce03d9c2dfb1", "0xa09d3ce5e748da84802436951acc3d3ea5d8ec1d6933505ed724d6b4b0d69973ab0930daec9c6606960f6e541e4a3ce2", "0x8ef94f7be4d85d5ad3d779a5cf4d7b2fc3e65c52fb8e1c3c112509a4af77a0b5be994f251e5e40fabeeb1f7d5615c22b", "0xa7406a5bf5708d9e10922d3c5c45c03ef891b8d0d74ec9f28328a72be4cdc05b4f2703fa99366426659dfca25d007535", "0xb7f52709669bf92a2e070bfe740f422f0b7127392c5589c7f0af71bb5a8428697c762d3c0d74532899da24ea7d8695c2", "0xb9dfb0c8df84104dbf9239ccefa4672ef95ddabb8801b74997935d1b81a78a6a5669a3c553767ec19a1281f6e570f4ff", "0xae4d5c872156061ce9195ac640190d8d71dd406055ee43ffa6f9893eb24b870075b74c94d65bc1d5a07a6573282b5520", "0xafe6bd3eb72266d333f1807164900dcfa02a7eb5b1744bb3c86b34b3ee91e3f05e38fa52a50dc64eeb4bdb1dd62874b8", "0x948043cf1bc2ef3c01105f6a78dc06487f57548a3e6ef30e6ebc51c94b71e4bf3ff6d0058c72b6f3ecc37efd7c7fa8c0", "0xa22fd17c2f7ffe552bb0f23fa135584e8d2d8d75e3f742d94d04aded2a79e22a00dfe7acbb57d44e1cdb962fb22ae170", "0x8cd0f4e9e4fb4a37c02c1bde0f69359c43ab012eb662d346487be0c3758293f1ca560122b059b091fddce626383c3a8f", "0x90499e45f5b9c81426f3d735a52a564cafbed72711d9279fdd88de8038e953bc48c57b58cba85c3b2e4ce56f1ddb0e11", "0x8c30e4c034c02958384564cac4f85022ef36ab5697a3d2feaf6bf105049675bbf23d01b4b6814711d3d9271abff04cac", "0x81f7999e7eeea30f3e1075e6780bbf054f2fb6f27628a2afa4d41872a385b4216dd5f549da7ce6cf39049b2251f27fb7", "0xb36a7191f82fc39c283ffe53fc1f5a9a00b4c64eee7792a8443475da9a4d226cf257f226ea9d66e329af15d8f04984ec", "0xaad4da528fdbb4db504f3041c747455baff5fcd459a2efd78f15bdf3aea0bdb808343e49df88fe7a7c8620009b7964a3", "0x99ebd8c6dd5dd299517fb6381cfc2a7f443e6e04a351440260dd7c2aee3f1d8ef06eb6c18820b394366ecdfd2a3ce264", "0x8873725b81871db72e4ec3643084b1cdce3cbf80b40b834b092767728605825c19b6847ad3dcf328438607e8f88b4410", "0xb008ee2f895daa6abd35bd39b6f7901ae4611a11a3271194e19da1cdcc7f1e1ea008fe5c5440e50d2c273784541ad9c5", "0x9036feafb4218d1f576ef89d0e99124e45dacaa6d816988e34d80f454d10e96809791d5b78f7fd65f569e90d4d7238c5", "0x92073c1d11b168e4fa50988b0288638b4868e48bbc668c5a6dddf5499875d53be23a285acb5e4bad60114f6cf6c556e9", "0x88c87dfcb8ba6cbfe7e1be081ccfadbd589301db2cb7c99f9ee5d7db90aa297ed1538d5a867678a763f2deede5fd219a", "0xb42a562805c661a50f5dea63108002c0f27c0da113da6a9864c9feb5552225417c0356c4209e8e012d9bcc9d182c7611", "0x8e6317d00a504e3b79cd47feb4c60f9df186467fe9ca0f35b55c0364db30528f5ff071109dabb2fc80bb9cd4949f0c24", "0xb7b1ea6a88694f8d2f539e52a47466695e39e43a5eb9c6f23bca15305fe52939d8755cc3ac9d6725e60f82f994a3772f", "0xa3cd55161befe795af93a38d33290fb642b8d80da8b786c6e6fb02d393ea308fbe87f486994039cbd7c7b390414594b6", "0xb416d2d45b44ead3b1424e92c73c2cf510801897b05d1724ff31cbd741920cd858282fb5d6040fe1f0aa97a65bc49424", "0x950ee01291754feace97c2e933e4681e7ddfbc4fcd079eb6ff830b0e481d929c93d0c7fb479c9939c28ca1945c40da09", "0x869bd916aee8d86efe362a49010382674825d49195b413b4b4018e88ce43fe091b475d0b863ff0ba2259400f280c2b23", "0x9782f38cd9c9d3385ec286ebbc7cba5b718d2e65a5890b0a5906b10a89dc8ed80d417d71d7c213bf52f2af1a1f513ea7", "0x91cd33bc2628d096269b23faf47ee15e14cb7fdc6a8e3a98b55e1031ea0b68d10ba30d97e660f7e967d24436d40fad73", "0x8becc978129cc96737034c577ae7225372dd855da8811ae4e46328e020c803833b5bdbc4a20a93270e2b8bd1a2feae52", "0xa36b1d8076783a9522476ce17f799d78008967728ce920531fdaf88303321bcaf97ecaa08e0c01f77bc32e53c5f09525", "0xb4720e744943f70467983aa34499e76de6d59aa6fadf86f6b787fdce32a2f5b535b55db38fe2da95825c51002cfe142d", "0x91ad21fc502eda3945f6de874d1b6bf9a9a7711f4d61354f9e5634fc73f9c06ada848de15ab0a75811d3250be862827d", "0x84f78e2ebf5fc077d78635f981712daf17e2475e14c2a96d187913006ad69e234746184a51a06ef510c9455b38acb0d7", "0x960aa7906e9a2f11db64a26b5892ac45f20d2ccb5480f4888d89973beb6fa0dfdc06d68d241ff5ffc7f1b82b1aac242d", "0xa99365dcd1a00c66c9db6924b97c920f5c723380e823b250db85c07631b320ec4e92e586f7319e67a522a0578f7b6d6c", "0xa25d92d7f70cf6a88ff317cfec071e13774516da664f5fac0d4ecaa65b8bf4eb87a64a4d5ef2bd97dfae98d388dbf5cc", "0xa7af47cd0041295798f9779020a44653007444e8b4ef0712982b06d0dcdd434ec4e1f7c5f7a049326602cb605c9105b7", "0xaefe172eac5568369a05980931cc476bebd9dea573ba276d59b9d8c4420784299df5a910033b7e324a6c2dfc62e3ef05", "0xb69bc9d22ffa645baa55e3e02522e9892bb2daa7fff7c15846f13517d0799766883ee09ae0869df4139150c5b843ca8a", "0x95a10856140e493354fdd12722c7fdded21b6a2ffbc78aa2697104af8ad0c8e2206f44b0bfee077ef3949d46bbf7c16b", "0x891f2fcd2c47cbea36b7fa715968540c233313f05333f09d29aba23c193f462ed490dd4d00969656e89c53155fdfe710", "0xa6c33e18115e64e385c843dde34e8a228222795c7ca90bc2cc085705d609025f3351d9be61822c69035a49fb3e48f2d5", "0xb87fb12f12c0533b005adad0487f03393ff682e13575e3cb57280c3873b2c38ba96a63c49eef7a442753d26b7005230b", "0xb905c02ba451bfd411c135036d92c27af3b0b1c9c2f1309d6948544a264b125f39dd41afeff4666b12146c545adc168a", "0x8b29c513f43a78951cf742231cf5457a6d9d55edf45df5481a0f299a418d94effef561b15d2c1a01d1b8067e7153fda9", "0xb9941cccd51dc645920d2781c81a317e5a33cb7cf76427b60396735912cb6d2ca9292bb4d36b6392467d390d2c58d9f3", "0xa8546b627c76b6ef5c93c6a98538d8593dbe21cb7673fd383d5401b0c935eea0bdeeefeb1af6ad41bad8464fb87bbc48", "0xaa286b27de2812de63108a1aec29d171775b69538dc6198640ac1e96767c2b83a50391f49259195957d457b493b667c9", "0xa932fb229f641e9abbd8eb2bd874015d97b6658ab6d29769fc23b7db9e41dd4f850382d4c1f08af8f156c5937d524473", "0xa1412840fcc86e2aeec175526f2fb36e8b3b8d21a78412b7266daf81e51b3f68584ed8bd42a66a43afdd8c297b320520", "0x89c78be9efb624c97ebca4fe04c7704fa52311d183ffd87737f76b7dadc187c12c982bd8e9ed7cd8beb48cdaafd2fd01", "0xa3f5ddec412a5bec0ce15e3bcb41c6214c2b05d4e9135a0d33c8e50a78eaba71e0a5a6ea8b45854dec5c2ed300971fc2", "0x9721f9cec7a68b7758e3887548790de49fa6a442d0396739efa20c2f50352a7f91d300867556d11a703866def2d5f7b5", "0xa23764e140a87e5991573521af039630dd28128bf56eed2edbed130fd4278e090b60cf5a1dca9de2910603d44b9f6d45", "0xa1a6494a994215e48ab55c70efa8ffdddce6e92403c38ae7e8dd2f8288cad460c6c7db526bbdf578e96ca04d9fe12797", "0xb1705ea4cb7e074efe0405fc7b8ee2ec789af0426142f3ec81241cacd4f7edcd88e39435e4e4d8e7b1df64f3880d6613", "0x85595d061d677116089a6064418b93eb44ff79e68d12bd9625078d3bbc440a60d0b02944eff6054433ee34710ae6fbb4", "0x9978d5e30bedb7526734f9a1febd973a70bfa20890490e7cc6f2f9328feab1e24f991285dbc3711d892514e2d7d005ad", "0xaf30243c66ea43b9f87a061f947f7bce745f09194f6e95f379c7582b9fead920e5d6957eaf05c12ae1282ada4670652f", "0xa1930efb473f88001e47aa0b2b2a7566848cccf295792e4544096ecd14ee5d7927c173a8576b405bfa2eec551cd67eb5", "0xb0446d1c590ee5a45f7e22d269c044f3848c97aec1d226b44bfd0e94d9729c28a38bccddc3a1006cc5fe4e3c24f001f2", "0xb8a8380172df3d84b06176df916cf557966d4f2f716d3e9437e415d75b646810f79f2b2b71d857181b7fc944018883a3", "0xa563afec25b7817bfa26e19dc9908bc00aa8fc3d19be7d6de23648701659009d10e3e4486c28e9c6b13d48231ae29ac5", "0xa5a8e80579de886fb7d6408f542791876885947b27ad6fa99a8a26e381f052598d7b4e647b0115d4b5c64297e00ce28e", "0x8f87afcc7ad33c51ac719bade3cd92da671a37a82c14446b0a2073f4a0a23085e2c8d31913ed2d0be928f053297de8f6", "0xa43c455ce377e0bc434386c53c752880687e017b2f5ae7f8a15c044895b242dffde4c92fb8f8bb50b18470b17351b156", "0x8368f8b12a5bceb1dba25adb3a2e9c7dc9b1a77a1f328e5a693f5aec195cd1e06b0fe9476b554c1c25dac6c4a5b640a3", "0x919878b27f3671fc78396f11531c032f3e2bd132d04cc234fa4858676b15fb1db3051c0b1db9b4fc49038216f11321ce", "0xb48cd67fb7f1242696c1f877da4bdf188eac676cd0e561fbac1a537f7b8229aff5a043922441d603a26aae56a15faee4", "0xa3e0fdfd4d29ea996517a16f0370b54787fefe543c2fe73bfc6f9e560c1fd30dad8409859e2d7fa2d44316f24746c712", "0x8bb156ade8faf149df7bea02c140c7e392a4742ae6d0394d880a849127943e6f26312033336d3b9fdc0092d71b5efe87", "0x8845e5d5cc555ca3e0523244300f2c8d7e4d02aaebcb5bd749d791208856c209a6f84dd99fd55968c9f0ab5f82916707", "0xa3e90bb5c97b07789c2f32dff1aec61d0a2220928202f5ad5355ae71f8249237799d6c8a22602e32e572cb12eabe0c17", "0xb150bcc391884c996149dc3779ce71f15dda63a759ee9cc05871f5a8379dcb62b047098922c0f26c7bd04deb394c33f9", "0x95cd4ad88d51f0f2efcfd0c2df802fe252bb9704d1afbf9c26a248df22d55da87bdfaf41d7bc6e5df38bd848f0b13f42", "0xa05a49a31e91dff6a52ac8b9c2cfdd646a43f0d488253f9e3cfbce52f26667166bbb9b608fc358763a65cbf066cd6d05", "0xa59c3c1227fdd7c2e81f5e11ef5c406da44662987bac33caed72314081e2eed66055d38137e01b2268e58ec85dd986c0", "0xb7020ec3bd73a99861f0f1d88cf5a19abab1cbe14b7de77c9868398c84bb8e18dbbe9831838a96b6d6ca06e82451c67b", "0x98d1ff2525e9718ee59a21d8900621636fcd873d9a564b8dceb4be80a194a0148daf1232742730b3341514b2e5a5436c", "0x886d97b635975fc638c1b6afc493e5998ca139edba131b75b65cfe5a8e814f11bb678e0eeee5e6e5cd913ad3f2fefdfc", "0x8fb9fd928d38d5d813b671c924edd56601dd7163b686c13f158645c2f869d9250f3859aa5463a39258c90fef0f41190a", "0xaac35e1cd655c94dec3580bb3800bd9c2946c4a9856f7d725af15fbea6a2d8ca51c8ad2772abed60ee0e3fb9cb24046b", "0xb8d71fa0fa05ac9e443c9b4929df9e7f09a919be679692682e614d24227e04894bfc14a5c73a62fb927fedff4a0e4aa7", "0xa45a19f11fbbb531a704badbb813ed8088ab827c884ee4e4ebf363fa1132ff7cfa9d28be9c85b143e4f7cdbc94e7cf1a", "0x82b54703a4f295f5471b255ab59dce00f0fe90c9fb6e06b9ee48b15c91d43f4e2ef4a96c3118aeb03b08767be58181bb", "0x8283264c8e6d2a36558f0d145c18576b6600ff45ff99cc93eca54b6c6422993cf392668633e5df396b9331e873d457e5", "0x8c549c03131ead601bc30eb6b9537b5d3beb7472f5bb1bcbbfd1e9f3704477f7840ab3ab7f7dc13bbbbcdff886a462d4", "0xafbb0c520ac1b5486513587700ad53e314cb74bfbc12e0b5fbdcfdaac36d342e8b59856196a0d84a25cff6e6e1d17e76", "0x89e4c22ffb51f2829061b3c7c1983c5c750cad158e3a825d46f7cf875677da5d63f653d8a297022b5db5845c9271b32b", "0xafb27a86c4c2373088c96b9adf4433f2ebfc78ac5c526e9f0510670b6e4e5e0057c0a4f75b185e1a30331b9e805c1c15", "0xa18e16b57445f88730fc5d3567bf5a176861dc14c7a08ed2996fe80eed27a0e7628501bcb78a1727c5e9ac55f29c12c4", "0x93d61bf88b192d6825cf4e1120af1c17aa0f994d158b405e25437eaeefae049f7b721a206e7cc8a04fdc29d3c42580a1", "0xa99f2995a2e3ed2fd1228d64166112038de2f516410aa439f4c507044e2017ea388604e2d0f7121256fadf7fbe7023d1", "0x914fd91cffc23c32f1c6d0e98bf660925090d873367d543034654389916f65f552e445b0300b71b61b721a72e9a5983c", "0xb42a578a7787b71f924e7def425d849c1c777156b1d4170a8ee7709a4a914e816935131afd9a0412c4cb952957b20828", "0x82fb30590e84b9e45db1ec475a39971cf554dc01bcc7050bc89265740725c02e2be5a972168c5170c86ae83e5b0ad2c0", "0xb14f8d8e1e93a84976289e0cf0dfa6f3a1809e98da16ee5c4932d0e1ed6bf8a07697fdd4dd86a3df84fb0003353cdcc0", "0x85d7a2f4bda31aa2cb208b771fe03291a4ebdaf6f1dc944c27775af5caec412584c1f45bc741fca2a6a85acb3f26ad7d", "0xaf02e56ce886ff2253bc0a68faad76f25ead84b2144e5364f3fb9b648f03a50ee9dc0b2c33ebacf7c61e9e43201ef9ef", "0x87e025558c8a0b0abd06dfc350016847ea5ced7af2d135a5c9eec9324a4858c4b21510fb0992ec52a73447f24945058e", "0x80fff0bafcd058118f5e7a4d4f1ae0912efeb281d2cbe4d34ba8945cc3dbe5d8baf47fb077343b90b8d895c90b297aca", "0xb6edcf3a40e7b1c3c0148f47a263cd819e585a51ef31c2e35a29ce6f04c53e413f743034c0d998d9c00a08ba00166f31", "0xabb87ed86098c0c70a76e557262a494ff51a30fb193f1c1a32f8e35eafa34a43fcc07aa93a3b7a077d9e35afa07b1a3d", "0xa280214cd3bb0fb7ecd2d8bcf518cbd9078417f2b91d2533ec2717563f090fb84f2a5fcfdbbeb2a2a1f8a71cc5aa5941", "0xa63083ca7238ea2b57d15a475963cf1d4f550d8cd76db290014a0461b90351f1f26a67d674c837b0b773b330c7c3d534", "0xa8fa39064cb585ece5263e2f42f430206476bf261bd50f18d2b694889bd79d04d56410664cecad62690e5c5a20b3f6ff", "0x85ba52ce9d700a5dcf6c5b00559acbe599d671ce5512467ff4b6179d7fad550567ce2a9c126a50964e3096458ea87920", "0xb913501e1008f076e5eac6d883105174f88b248e1c9801e568fefaffa1558e4909364fc6d9512aa4d125cbd7cc895f05", "0x8eb33b5266c8f2ed4725a6ad147a322e44c9264cf261c933cbbe230a43d47fca0f29ec39756b20561dabafadd5796494", "0x850ebc8b661a04318c9db5a0515066e6454fa73865aa4908767a837857ecd717387f614acb614a88e075d4edc53a2f5a", "0xa08d6b92d866270f29f4ce23a3f5d99b36b1e241a01271ede02817c8ec3f552a5c562db400766c07b104a331835c0c64", "0x8131804c89bb3e74e9718bfc4afa547c1005ff676bd4db9604335032b203390cfa54478d45c6c78d1fe31a436ed4be9f", "0x9106d94f23cc1eacec8316f16d6f0a1cc160967c886f51981fdb9f3f12ee1182407d2bb24e5b873de58cb1a3ee915a6b", "0xa13806bfc3eae7a7000c9d9f1bd25e10218d4e67f59ae798b145b098bca3edad2b1040e3fc1e6310e612fb8818f459ac", "0x8c69fbca502046cb5f6db99900a47b34117aef3f4b241690cdb3b84ca2a2fc7833e149361995dc41fa78892525bce746", "0x852c473150c91912d58ecb05769222fa18312800c3f56605ad29eec9e2d8667b0b81c379048d3d29100ed2773bb1f3c5", "0xb1767f6074426a00e01095dbb1795beb4e4050c6411792cbad6537bc444c3165d1058bafd1487451f9c5ddd209e0ae7e", "0x80c600a5fe99354ce59ff0f84c760923dc8ff66a30bf47dc0a086181785ceb01f9b951c4e66df800ea6d705e8bc47055", "0xb5cf19002fbc88a0764865b82afcb4d64a50196ea361e5c71dff7de084f4dcbbc34ec94a45cc9e0247bd51da565981aa", "0x93e67a254ea8ce25e112d93cc927fadaa814152a2c4ec7d9a56eaa1ed47aec99b7e9916b02e64452cc724a6641729bbb", "0xace70b32491bda18eee4a4d041c3bc9effae9340fe7e6c2f5ad975ee0874c17f1a7da7c96bd85fccff9312c518fac6e9", "0xab4cfa02065017dd7f1aadc66f2c92f78f0f11b8597c03a5d69d82cb2eaf95a4476a836ac102908f137662472c8d914b", "0xa40b8cd8deb8ae503d20364d64cab7c2801b7728a9646ed19c65edea6a842756a2f636283494299584ad57f4bb12cd0b", "0x8594e11d5fc2396bcd9dbf5509ce4816dbb2b7305168021c426171fb444d111da5a152d6835ad8034542277011c26c0e", "0x8024de98c26b4c994a66628dc304bb737f4b6859c86ded552c5abb81fd4c6c2e19d5a30beed398a694b9b2fdea1dd06a", "0x8843f5872f33f54df8d0e06166c1857d733995f67bc54abb8dfa94ad92407cf0179bc91b0a50bbb56cdc2b350d950329", "0xb8bab44c7dd53ef9edf497dcb228e2a41282c90f00ba052fc52d57e87b5c8ab132d227af1fcdff9a12713d1f980bcaae", "0x982b4d7b29aff22d527fd82d2a52601d95549bfb000429bb20789ed45e5abf1f4b7416c7b7c4b79431eb3574b29be658", "0x8eb1f571b6a1878e11e8c1c757e0bc084bab5e82e897ca9be9b7f4b47b91679a8190bf0fc8f799d9b487da5442415857", "0xa6e74b588e5af935c8b243e888582ef7718f8714569dd4992920740227518305eb35fab674d21a5551cca44b3e511ef2", "0xa30fc2f3a4cb4f50566e82307de73cd7bd8fe2c1184e9293c136a9b9e926a018d57c6e4f308c95b9eb8299e94d90a2a1", "0xa50c5869ca5d2b40722c056a32f918d47e0b65ca9d7863ca7d2fb4a7b64fe523fe9365cf0573733ceaadebf20b48fff8", "0x83bbdd32c04d17581418cf360749c7a169b55d54f2427390defd9f751f100897b2d800ce6636c5bbc046c47508d60c8c", "0xa82904bdf614de5d8deaff688c8a5e7ac5b3431687acbcda8fa53960b7c417a39c8b2e462d7af91ce6d79260f412db8e", "0xa4362e31ff4b05d278b033cf5eebea20de01714ae16d4115d04c1da4754269873afc8171a6f56c5104bfd7b0db93c3e7", "0xb5b8daa63a3735581e74a021b684a1038cea77168fdb7fdf83c670c2cfabcfc3ab2fc7359069b5f9048188351aef26b5", "0xb48d723894b7782d96ac8433c48faca1bdfa5238019c451a7f47d958097cce3ae599b876cf274269236b9d6ff8b6d7ca", "0x98ffff6a61a3a6205c7820a91ca2e7176fab5dba02bc194c4d14942ac421cb254183c705506ab279e4f8db066f941c6c", "0xae7db24731da2eaa6efc4f7fcba2ecc26940ddd68038dce43acf2cee15b72dc4ef42a7bfdd32946d1ed78786dd7696b3", "0xa656db14f1de9a7eb84f6301b4acb2fbf78bfe867f48a270e416c974ab92821eb4df1cb881b2d600cfed0034ac784641", "0xaa315f8ecba85a5535e9a49e558b15f39520fce5d4bf43131bfbf2e2c9dfccc829074f9083e8d49f405fb221d0bc4c3c", "0x90bffba5d9ff40a62f6c8e9fc402d5b95f6077ed58d030c93e321b8081b77d6b8dac3f63a92a7ddc01585cf2c127d66c", "0xabdd733a36e0e0f05a570d0504e73801bf9b5a25ff2c78786f8b805704997acb2e6069af342538c581144d53149fa6d3", "0xb4a723bb19e8c18a01bd449b1bb3440ddb2017f10bb153da27deb7a6a60e9bb37619d6d5435fbb1ba617687838e01dd0", "0x870016b4678bab3375516db0187a2108b2e840bae4d264b9f4f27dbbc7cc9cac1d7dc582d7a04d6fd1ed588238e5e513", "0x80d33d2e20e8fc170aa3cb4f69fffb72aeafb3b5bb4ea0bc79ab55da14142ca19b2d8b617a6b24d537366e3b49cb67c3", "0xa7ee76aec273aaae03b3b87015789289551969fb175c11557da3ab77e39ab49d24634726f92affae9f4d24003050d974", "0x8415ea4ab69d779ebd42d0fe0c6aef531d6a465a5739e429b1fcf433ec45aa8296c527e965a20f0ec9f340c9273ea3cf", "0x8c7662520794e8b4405d0b33b5cac839784bc86a5868766c06cbc1fa306dbe334978177417b31baf90ce7b0052a29c56", "0x902b2abecc053a3dbdea9897ee21e74821f3a1b98b2d560a514a35799f4680322550fd3a728d4f6d64e1de98033c32b8", "0xa05e84ed9ecab8d508d670c39f2db61ad6e08d2795ec32a3c9d0d3737ef3801618f4fc2a95f90ec2f068606131e076c5", "0x8b9208ff4d5af0c2e3f53c9375da666773ac57197dfabb0d25b1c8d0588ba7f3c15ee9661bb001297f322ea2fbf6928b", "0xa3c827741b34a03254d4451b5ab74a96f2b9f7fb069e2f5adaf54fd97cc7a4d516d378db5ca07da87d8566d6eef13726", "0x8509d8a3f4a0ed378e0a1e28ea02f6bf1d7f6c819c6c2f5297c7df54c895b848f841653e32ba2a2c22c2ff739571acb8", "0xa0ce988b7d3c40b4e496aa83a09e4b5472a2d98679622f32bea23e6d607bc7de1a5374fb162bce0549a67dad948519be", "0xaa8a3dd12bd60e3d2e05f9c683cdcb8eab17fc59134815f8d197681b1bcf65108cba63ac5c58ee632b1e5ed6bba5d474", "0x8b955f1d894b3aefd883fb4b65f14cd37fc2b9db77db79273f1700bef9973bf3fd123897ea2b7989f50003733f8f7f21", "0xac79c00ddac47f5daf8d9418d798d8af89fc6f1682e7e451f71ea3a405b0d36af35388dd2a332af790bc83ca7b819328", "0xa0d44dd2a4438b809522b130d0938c3fe7c5c46379365dbd1810a170a9aa5818e1c783470dd5d0b6d4ac7edbb7330910", "0xa30b69e39ad43dd540a43c521f05b51b5f1b9c4eed54b8162374ae11eac25da4f5756e7b70ce9f3c92c2eeceee7431ed", "0xac43220b762c299c7951222ea19761ab938bf38e4972deef58ed84f4f9c68c230647cf7506d7cbfc08562fcca55f0485", "0xb28233b46a8fb424cfa386a845a3b5399d8489ceb83c8f3e05c22c934798d639c93718b7b68ab3ce24c5358339e41cbb", "0xac30d50ee8ce59a10d4b37a3a35e62cdb2273e5e52232e202ca7d7b8d09d28958ee667fae41a7bb6cdc6fe8f6e6c9c85", "0xb199842d9141ad169f35cc7ff782b274cbaa645fdb727761e0a89edbf0d781a15f8218b4bf4eead326f2903dd88a9cc1", "0x85e018c7ddcad34bb8285a737c578bf741ccd547e68c734bdb3808380e12c5d4ef60fc896b497a87d443ff9abd063b38", "0x8c856e6ba4a815bdb891e1276f93545b7072f6cb1a9aa6aa5cf240976f29f4dee01878638500a6bf1daf677b96b54343", "0xb8a47555fa8710534150e1a3f13eab33666017be6b41005397afa647ea49708565f2b86b77ad4964d140d9ced6b4d585", "0x8cd1f1db1b2f4c85a3f46211599caf512d5439e2d8e184663d7d50166fd3008f0e9253272f898d81007988435f715881", "0xb1f34b14612c973a3eceb716dc102b82ab18afef9de7630172c2780776679a7706a4874e1df3eaadf541fb009731807f", "0xb25464af9cff883b55be2ff8daf610052c02df9a5e147a2cf4df6ce63edcdee6dc535c533590084cc177da85c5dc0baa", "0x91c3c4b658b42d8d3448ae1415d4541d02379a40dc51e36a59bd6e7b9ba3ea51533f480c7c6e8405250ee9b96a466c29", "0x86dc027b95deb74c36a58a1333a03e63cb5ae22d3b29d114cfd2271badb05268c9d0c819a977f5e0c6014b00c1512e3a", "0xae0e6ff58eb5fa35da5107ebeacf222ab8f52a22bb1e13504247c1dfa65320f40d97b0e6b201cb6613476687cb2f0681", "0x8f13415d960b9d7a1d93ef28afc2223e926639b63bdefce0f85e945dfc81670a55df288893a0d8b3abe13c5708f82f91", "0x956f67ca49ad27c1e3a68c1faad5e7baf0160c459094bf6b7baf36b112de935fdfd79fa4a9ea87ea8de0ac07272969f4", "0x835e45e4a67df9fb51b645d37840b3a15c171d571a10b03a406dd69d3c2f22df3aa9c5cbe1e73f8d767ce01c4914ea9a", "0x919b938e56d4b32e2667469d0bdccb95d9dda3341aa907683ee70a14bbbe623035014511c261f4f59b318b610ac90aa3", "0x96b48182121ccd9d689bf1dfdc228175564cd68dc904a99c808a7f0053a6f636c9d953e12198bdf2ea49ea92772f2e18", "0xac5e5a941d567fa38fdbcfa8cf7f85bb304e3401c52d88752bcd516d1fa9bac4572534ea2205e38423c1df065990790f", "0xac0bd594fb85a8d4fc26d6df0fa81f11919401f1ecf9168b891ec7f061a2d9368af99f7fd8d9b43b2ce361e7b8482159", "0x83d92c69ca540d298fe80d8162a1c7af3fa9b49dfb69e85c1d136a3ec39fe419c9fa78e0bb6d96878771fbd37fe92e40", "0xb35443ae8aa66c763c2db9273f908552fe458e96696b90e41dd509c17a5c04ee178e3490d9c6ba2dc0b8f793c433c134", "0x923b2d25aa45b2e580ffd94cbb37dc8110f340f0f011217ee1bd81afb0714c0b1d5fb4db86006cdd2457563276f59c59", "0x96c9125d38fca1a61ac21257b696f8ac3dae78def50285e44d90ea293d591d1c58f703540a7e4e99e070afe4646bbe15", "0xb57946b2332077fbcdcb406b811779aefd54473b5559a163cd65cb8310679b7e2028aa55c12a1401fdcfcac0e6fae29a", "0x845daedc5cf972883835d7e13c937b63753c2200324a3b8082a6c4abb4be06c5f7c629d4abe4bfaf1d80a1f073eb6ce6", "0x91a55dfd0efefcd03dc6dacc64ec93b8d296cb83c0ee72400a36f27246e7f2a60e73b7b70ba65819e9cfb73edb7bd297", "0x8874606b93266455fe8fdd25df9f8d2994e927460af06f2e97dd4d2d90db1e6b06d441b72c2e76504d753badca87fb37", "0x8ee99e6d231274ff9252c0f4e84549da173041299ad1230929c3e3d32399731c4f20a502b4a307642cac9306ccd49d3c", "0x8836497714a525118e20849d6933bb8535fb6f72b96337d49e3133d936999c90a398a740f42e772353b5f1c63581df6d", "0xa6916945e10628f7497a6cdc5e2de113d25f7ade3e41e74d3de48ccd4fce9f2fa9ab69645275002e6f49399b798c40af", "0x9597706983107eb23883e0812e1a2c58af7f3499d50c6e29b455946cb9812fde1aa323d9ed30d1c0ffd455abe32303cd", "0xa24ee89f7f515cc33bdbdb822e7d5c1877d337f3b2162303cfc2dae028011c3a267c5cb4194afa63a4856a6e1c213448", "0x8cd25315e4318801c2776824ae6e7d543cb85ed3bc2498ba5752df2e8142b37653cf9e60104d674be3aeb0a66912e97a", "0xb5085ecbe793180b40dbeb879f4c976eaaccaca3a5246807dced5890e0ed24d35f3f86955e2460e14fb44ff5081c07ba", "0x960188cc0b4f908633a6840963a6fa2205fc42c511c6c309685234911c5304ef4c304e3ae9c9c69daa2fb6a73560c256", "0xa32d0a70bf15d569b4cda5aebe3e41e03c28bf99cdd34ffa6c5d58a097f322772acca904b3a47addb6c7492a7126ebac", "0x977f72d06ad72d4aa4765e0f1f9f4a3231d9f030501f320fe7714cc5d329d08112789fa918c60dd7fdb5837d56bb7fc6", "0x99fa038bb0470d45852bb871620d8d88520adb701712fcb1f278fed2882722b9e729e6cdce44c82caafad95e37d0e6f7", "0xb855e8f4fc7634ada07e83b6c719a1e37acb06394bc8c7dcab7747a8c54e5df3943915f021364bd019fdea103864e55f", "0x88bc2cd7458532e98c596ef59ea2cf640d7cc31b4c33cef9ed065c078d1d4eb49677a67de8e6229cc17ea48bace8ee5a", "0xaaa78a3feaa836d944d987d813f9b9741afb076e6aca1ffa42682ab06d46d66e0c07b8f40b9dbd63e75e81efa1ef7b08", "0xb7b080420cc4d808723b98b2a5b7b59c81e624ab568ecdfdeb8bf3aa151a581b6f56e983ef1b6f909661e25db40b0c69", "0xabee85c462ac9a2c58e54f06c91b3e5cd8c5f9ab5b5deb602b53763c54826ed6deb0d6db315a8d7ad88733407e8d35e2", "0x994d075c1527407547590df53e9d72dd31f037c763848d1662eebd4cefec93a24328c986802efa80e038cb760a5300f5", "0xab8777640116dfb6678e8c7d5b36d01265dfb16321abbfc277da71556a34bb3be04bc4ae90124ed9c55386d2bfb3bda0", "0x967e3a828bc59409144463bcf883a3a276b5f24bf3cbfdd7a42343348cba91e00b46ac285835a9b91eef171202974204", "0x875a9f0c4ffe5bb1d8da5e3c8e41d0397aa6248422a628bd60bfae536a651417d4e8a7d2fb98e13f2dad3680f7bd86d3", "0xacaa330c3e8f95d46b1880126572b238dbb6d04484d2cd4f257ab9642d8c9fc7b212188b9c7ac9e0fd135c520d46b1bf", "0xaceb762edbb0f0c43dfcdb01ea7a1ac5918ca3882b1e7ebc4373521742f1ed5250d8966b498c00b2b0f4d13212e6dd0b", "0x81d072b4ad258b3646f52f399bced97c613b22e7ad76373453d80b1650c0ca87edb291a041f8253b649b6e5429bb4cff", "0x980a47d27416ac39c7c3a0ebe50c492f8c776ea1de44d5159ac7d889b6d554357f0a77f0e5d9d0ff41aae4369eba1fc2", "0x8b4dfd5ef5573db1476d5e43aacfb5941e45d6297794508f29c454fe50ea622e6f068b28b3debe8635cf6036007de2e3", "0xa60831559d6305839515b68f8c3bc7abbd8212cc4083502e19dd682d56ca37c9780fc3ce4ec2eae81ab23b221452dc57", "0x951f6b2c1848ced9e8a2339c65918e00d3d22d3e59a0a660b1eca667d18f8430d737884e9805865ef3ed0fe1638a22d9", "0xb02e38fe790b492aa5e89257c4986c9033a8b67010fa2add9787de857d53759170fdd67715ca658220b4e14b0ca48124", "0xa51007e4346060746e6b0e4797fc08ef17f04a34fe24f307f6b6817edbb8ce2b176f40771d4ae8a60d6152cbebe62653", "0xa510005b05c0b305075b27b243c9d64bcdce85146b6ed0e75a3178b5ff9608213f08c8c9246f2ca6035a0c3e31619860", "0xaaff4ef27a7a23be3419d22197e13676d6e3810ceb06a9e920d38125745dc68a930f1741c9c2d9d5c875968e30f34ab5", "0x864522a9af9857de9814e61383bebad1ba9a881696925a0ea6bfc6eff520d42c506bbe5685a9946ed710e889765be4a0", "0xb63258c080d13f3b7d5b9f3ca9929f8982a6960bdb1b0f8676f4dca823971601672f15e653917bf5d3746bb220504913", "0xb51ce0cb10869121ae310c7159ee1f3e3a9f8ad498827f72c3d56864808c1f21fa2881788f19ece884d3f705cd7bd0c5", "0x95d9cecfc018c6ed510e441cf84c712d9909c778c16734706c93222257f64dcd2a9f1bd0b400ca271e22c9c487014274", "0x8beff4d7d0140b86380ff4842a9bda94c2d2be638e20ac68a4912cb47dbe01a261857536375208040c0554929ced1ddc", "0x891ff49258749e2b57c1e9b8e04b12c77d79c3308b1fb615a081f2aacdfb4b39e32d53e069ed136fdbd43c53b87418fa", "0x9625cad224e163d387738825982d1e40eeff35fe816d10d7541d15fdc4d3eee48009090f3faef4024b249205b0b28f72", "0x8f3947433d9bd01aa335895484b540a9025a19481a1c40b4f72dd676bfcf332713714fd4010bde936eaf9470fd239ed0", "0xa00ec2d67789a7054b53f0e858a8a232706ccc29a9f3e389df7455f1a51a2e75801fd78469a13dbc25d28399ae4c6182", "0xa3f65884506d4a62b8775a0ea0e3d78f5f46bc07910a93cd604022154eabdf1d73591e304d61edc869e91462951975e1", "0xa14eef4fd5dfac311713f0faa9a60415e3d30b95a4590cbf95f2033dffb4d16c02e7ceff3dcd42148a4e3bc49cce2dd4", "0x8afa11c0eef3c540e1e3460bc759bb2b6ea90743623f88e62950c94e370fe4fd01c22b6729beba4dcd4d581198d9358f", "0xafb05548a69f0845ffcc5f5dc63e3cdb93cd270f5655173b9a950394b0583663f2b7164ba6df8d60c2e775c1d9f120af", "0x97f179e01a947a906e1cbeafa083960bc9f1bade45742a3afee488dfb6011c1c6e2db09a355d77f5228a42ccaa7bdf8e", "0x8447fca4d35f74b3efcbd96774f41874ca376bf85b79b6e66c92fa3f14bdd6e743a051f12a7fbfd87f319d1c6a5ce217", "0xa57ca39c23617cd2cf32ff93b02161bd7baf52c4effb4679d9d5166406e103bc8f3c6b5209e17c37dbb02deb8bc72ddd", "0x9667c7300ff80f0140be002b0e36caab07aaee7cce72679197c64d355e20d96196acaf54e06e1382167d081fe6f739c1", "0x828126bb0559ce748809b622677267ca896fa2ee76360fd2c02990e6477e06a667241379ca7e65d61a5b64b96d7867de", "0x8b8835dea6ba8cf61c91f01a4b3d2f8150b687a4ee09b45f2e5fc8f80f208ae5d142d8e3a18153f0722b90214e60c5a7", "0xa98e8ff02049b4da386e3ee93db23bbb13dfeb72f1cfde72587c7e6d962780b7671c63e8ac3fbaeb1a6605e8d79e2f29", "0x87a4892a0026d7e39ef3af632172b88337cb03669dea564bcdb70653b52d744730ebb5d642e20cb627acc9dbb547a26b", "0x877352a22fc8052878a57effc159dac4d75fe08c84d3d5324c0bab6d564cdf868f33ceee515eee747e5856b62cfa0cc7", "0x8b801ba8e2ff019ee62f64b8cb8a5f601fc35423eb0f9494b401050103e1307dc584e4e4b21249cd2c686e32475e96c3", "0xa9e7338d6d4d9bfec91b2af28a8ed13b09415f57a3a00e5e777c93d768fdb3f8e4456ae48a2c6626b264226e911a0e28", "0x99c05fedf40ac4726ed585d7c1544c6e79619a0d3fb6bda75a08c7f3c0008e8d5e19ed4da48de3216135f34a15eba17c", "0xa61cce8a1a8b13a4a650fdbec0eeea8297c352a8238fb7cac95a0df18ed16ee02a3daa2de108fa122aca733bd8ad7855", "0xb97f37da9005b440b4cb05870dd881bf8491fe735844f2d5c8281818583b38e02286e653d9f2e7fa5e74c3c3eb616540", "0xa72164a8554da8e103f692ac5ebb4aece55d5194302b9f74b6f2a05335b6e39beede0bf7bf8c5bfd4d324a784c5fb08c", "0xb87e8221c5341cd9cc8bb99c10fe730bc105550f25ed4b96c0d45e6142193a1b2e72f1b3857373a659b8c09be17b3d91", "0xa41fb1f327ef91dcb7ac0787918376584890dd9a9675c297c45796e32d6e5985b12f9b80be47fc3a8596c245f419d395", "0x90dafa3592bdbb3465c92e2a54c2531822ba0459d45d3e7a7092fa6b823f55af28357cb51896d4ec2d66029c82f08e26", "0xa0a9adc872ebc396557f484f1dd21954d4f4a21c4aa5eec543f5fa386fe590839735c01f236574f7ff95407cd12de103", "0xb8c5c940d58be7538acf8672852b5da3af34f82405ef2ce8e4c923f1362f97fc50921568d0fd2fe846edfb0823e62979", "0x85aaf06a8b2d0dac89dafd00c28533f35dbd074978c2aaa5bef75db44a7b12aeb222e724f395513b9a535809a275e30b", "0x81f3cbe82fbc7028c26a6c1808c604c63ba023a30c9f78a4c581340008dbda5ec07497ee849a2183fcd9124f7936af32", "0xa11ac738de75fd60f15a34209d3825d5e23385796a4c7fc5931822f3f380af977dd0f7b59fbd58eed7777a071e21b680", "0x85a279c493de03db6fa6c3e3c1b1b29adc9a8c4effc12400ae1128da8421954fa8b75ad19e5388fe4543b76fb0812813", "0x83a217b395d59ab20db6c4adb1e9713fc9267f5f31a6c936042fe051ce8b541f579442f3dcf0fa16b9e6de9fd3518191", "0x83a0b86e7d4ed8f9ccdc6dfc8ff1484509a6378fa6f09ed908e6ab9d1073f03011dc497e14304e4e3d181b57de06a5ab", "0xa63ad69c9d25704ce1cc8e74f67818e5ed985f8f851afa8412248b2df5f833f83b95b27180e9e7273833ed0d07113d3b", "0x99b1bc2021e63b561fe44ddd0af81fcc8627a91bfeecbbc989b642bc859abc0c8d636399701aad7bbaf6a385d5f27d61", "0xb53434adb66f4a807a6ad917c6e856321753e559b1add70824e5c1e88191bf6993fccb9b8b911fc0f473fb11743acacd", "0x97ed3b9e6fb99bf5f945d4a41f198161294866aa23f2327818cdd55cb5dc4c1a8eff29dd8b8d04902d6cd43a71835c82", "0xb1e808260e368a18d9d10bdea5d60223ba1713b948c782285a27a99ae50cc5fc2c53d407de07155ecc16fb8a36d744a0", "0xa3eb4665f18f71833fec43802730e56b3ee5a357ea30a888ad482725b169d6f1f6ade6e208ee081b2e2633079b82ba7d", "0xab8beb2c8353fc9f571c18fdd02bdb977fc883313469e1277b0372fbbb33b80dcff354ca41de436d98d2ed710faa467e", "0xaa9071cfa971e4a335a91ad634c98f2be51544cb21f040f2471d01bb97e1df2277ae1646e1ea8f55b7ba9f5c8c599b39", "0x80b7dbfdcaf40f0678012acc634eba44ea51181475180d9deb2050dc4f2de395289edd0223018c81057ec79b04b04c49", "0x89623d7f6cb17aa877af14de842c2d4ab7fd576d61ddd7518b5878620a01ded40b6010de0da3cdf31d837eecf30e9847", "0xa773bb024ae74dd24761f266d4fb27d6fd366a8634febe8235376b1ae9065c2fe12c769f1d0407867dfbe9f5272c352f", "0x8455a561c3aaa6ba64c881a5e13921c592b3a02e968f4fb24a2243c36202795d0366d9cc1a24e916f84d6e158b7aeac7", "0x81d8bfc4b283cf702a40b87a2b96b275bdbf0def17e67d04842598610b67ea08c804d400c3e69fa09ea001eaf345b276", "0xb8f8f82cb11fea1c99467013d7e167ff03deb0c65a677fab76ded58826d1ba29aa7cf9fcd7763615735ea3ad38e28719", "0x89a6a04baf9cccc1db55179e1650b1a195dd91fb0aebc197a25143f0f393524d2589975e3fbfc2547126f0bced7fd6f2", "0xb81b2162df045390f04df07cbd0962e6b6ca94275a63edded58001a2f28b2ae2af2c7a6cba4ecd753869684e77e7e799", "0xa3757f722776e50de45c62d9c4a2ee0f5655a512344c4cbec542d8045332806568dd626a719ef21a4eb06792ca70f204", "0x8c5590df96ec22179a4e8786de41beb44f987a1dcc508eb341eecbc0b39236fdfad47f108f852e87179ccf4e10091e59", "0x87502f026ed4e10167419130b88c3737635c5b9074c364e1dd247cef5ef0fc064b4ae99b187e33301e438bbd2fe7d032", "0xaf925a2165e980ced620ff12289129fe17670a90ae0f4db9d4b39bd887ccb1f5d2514ac9ecf910f6390a8fc66bd5be17", "0x857fca899828cf5c65d26e3e8a6e658542782fc72762b3b9c73514919f83259e0f849a9d4838b40dc905fe43024d0d23", "0x87ffebdbfb69a9e1007ebac4ffcb4090ff13705967b73937063719aa97908986effcb7262fdadc1ae0f95c3690e3245d", "0xa9ff6c347ac6f4c6ab993b748802e96982eaf489dc69032269568412fc9a79e7c2850dfc991b28211b3522ee4454344b", "0xa65b3159df4ec48bebb67cb3663cd744027ad98d970d620e05bf6c48f230fa45bf17527fe726fdf705419bb7a1bb913e", "0x84b97b1e6408b6791831997b03cd91f027e7660fd492a93d95daafe61f02427371c0e237c75706412f442991dfdff989", "0xab761c26527439b209af0ae6afccd9340bbed5fbe098734c3145b76c5d2cd7115d9227b2eb523882b7317fbb09180498", "0xa0479a8da06d7a69c0b0fee60df4e691c19c551f5e7da286dab430bfbcabf31726508e20d26ea48c53365a7f00a3ad34", "0xa732dfc9baa0f4f40b5756d2e8d8937742999623477458e0bc81431a7b633eefc6f53b3b7939fe0a020018549c954054", "0x901502436a1169ba51dc479a5abe7c8d84e0943b16bc3c6a627b49b92cd46263c0005bc324c67509edd693f28e612af1", "0xb627aee83474e7f84d1bab9b7f6b605e33b26297ac6bbf52d110d38ba10749032bd551641e73a383a303882367af429b", "0x95108866745760baef4a46ef56f82da6de7e81c58b10126ebd2ba2cd13d339f91303bf2fb4dd104a6956aa3b13739503", "0x899ed2ade37236cec90056f3569bc50f984f2247792defafcceb49ad0ca5f6f8a2f06573705300e07f0de0c759289ff5", "0xa9f5eee196d608efe4bcef9bf71c646d27feb615e21252cf839a44a49fd89da8d26a758419e0085a05b1d59600e2dc42", "0xb36c6f68fed6e6c85f1f4a162485f24817f2843ec5cbee45a1ebfa367d44892e464949c6669f7972dc7167af08d55d25", "0xaaaede243a9a1b6162afbc8f571a52671a5a4519b4062e3f26777664e245ba873ed13b0492c5dbf0258c788c397a0e9e", "0x972b4fb39c31cbe127bf9a32a5cc10d621ebdd9411df5e5da3d457f03b2ab2cd1f6372d8284a4a9400f0b06ecdbfd38e", "0x8f6ca1e110e959a4b1d9a5ce5f212893cec21db40d64d5ac4d524f352d72198f923416a850bf845bc5a22a79c0ea2619", "0xa0f3c93b22134f66f04b2553a53b738644d1665ceb196b8494b315a4c28236fb492017e4a0de4224827c78e42f9908b7", "0x807fb5ee74f6c8735b0b5ca07e28506214fe4047dbeb00045d7c24f7849e98706aea79771241224939cb749cf1366c7d", "0x915eb1ff034224c0b645442cdb7d669303fdc00ca464f91aaf0b6fde0b220a3a74ff0cb043c26c9f3a5667b3fdaa9420", "0x8fda6cef56ed33fefffa9e6ac8e6f76b1af379f89761945c63dd448801f7bb8ca970504a7105fac2f74f652ccff32327", "0x87380cffdcffb1d0820fa36b63cc081e72187f86d487315177d4d04da4533eb19a0e2ff6115ceab528887819c44a5164", "0x8cd89e03411a18e7f16f968b89fb500c36d47d229f6487b99e62403a980058db5925ce249206743333538adfad168330", "0x974451b1df33522ce7056de9f03e10c70bf302c44b0741a59df3d6877d53d61a7394dcee1dd46e013d7cb9d73419c092", "0x98c35ddf645940260c490f384a49496a7352bb8e3f686feed815b1d38f59ded17b1ad6e84a209e773ed08f7b8ff1e4c2", "0x963f386cf944bb9b2ddebb97171b64253ea0a2894ac40049bdd86cda392292315f3a3d490ca5d9628c890cfb669f0acb", "0x8d507712152babd6d142ee682638da8495a6f3838136088df9424ef50d5ec28d815a198c9a4963610b22e49b4cdf95e9", "0x83d4bc6b0be87c8a4f1e9c53f257719de0c73d85b490a41f7420e777311640937320557ff2f1d9bafd1daaa54f932356", "0x82f5381c965b7a0718441131c4d13999f4cdce637698989a17ed97c8ea2e5bdb5d07719c5f7be8688edb081b23ede0f4", "0xa6ebecab0b72a49dfd01d69fa37a7f74d34fb1d4fef0aa10e3d6fceb9eccd671225c230af89f6eb514250e41a5f91f52", "0x846d185bdad6e11e604df7f753b7a08a28b643674221f0e750ebdb6b86ec584a29c869e131bca868972a507e61403f6a", "0x85a98332292acb744bd1c0fd6fdcf1f889a78a2c9624d79413ffa194cc8dfa7821a4b60cde8081d4b5f71f51168dd67f", "0x8f7d97c3b4597880d73200d074eb813d95432306e82dafc70b580b8e08cb8098b70f2d07b4b3ac6a4d77e92d57035031", "0x8185439c8751e595825d7053518cbe121f191846a38d4dbcb558c3f9d7a3104f3153401adaaaf27843bbe2edb504bfe3", "0xb3c00d8ece1518fca6b1215a139b0a0e26d9cba1b3a424f7ee59f30ce800a5db967279ed60958dd1f3ee69cf4dd1b204", "0xa2e6cb6978e883f9719c3c0d44cfe8de0cc6f644b98f98858433bea8bbe7b612c8aca5952fccce4f195f9d54f9722dc2", "0x99663087e3d5000abbec0fbda4e7342ec38846cc6a1505191fb3f1a337cb369455b7f8531a6eb8b0f7b2c4baf83cbe2b", "0xab0836c6377a4dbc7ca6a4d6cf021d4cd60013877314dd05f351706b128d4af6337711ed3443cb6ca976f40d74070a9a", "0x87abfd5126152fd3bac3c56230579b489436755ea89e0566aa349490b36a5d7b85028e9fb0710907042bcde6a6f5d7e3", "0x974ba1033f75f60e0cf7c718a57ae1da3721cf9d0fb925714c46f027632bdd84cd9e6de4cf4d00bc55465b1c5ebb7384", "0xa607b49d73689ac64f25cec71221d30d53e781e1100d19a2114a21da6507a60166166369d860bd314acb226596525670", "0xa7c2b0b915d7beba94954f2aa7dd08ec075813661e2a3ecca5d28a0733e59583247fed9528eb28aba55b972cdbaf06eb", "0xb8b3123e44128cc8efbe3270f2f94e50ca214a4294c71c3b851f8cbb70cb67fe9536cf07d04bf7fe380e5e3a29dd3c15", "0xa59a07e343b62ad6445a0859a32b58c21a593f9ddbfe52049650f59628c93715aa1f4e1f45b109321756d0eeec8a5429", "0x94f51f8a4ed18a6030d0aaa8899056744bd0e9dc9ac68f62b00355cddab11da5da16798db75f0bfbce0e5bdfe750c0b6", "0x97460a97ca1e1fa5ce243b81425edc0ec19b7448e93f0b55bc9785eedeeafe194a3c8b33a61a5c72990edf375f122777", "0x8fa859a089bc17d698a7ee381f37ce9beadf4e5b44fce5f6f29762bc04f96faff5d58c48c73631290325f05e9a1ecf49", "0xabdf38f3b20fc95eff31de5aa9ef1031abfa48f1305ee57e4d507594570401503476d3bcc493838fc24d6967a3082c7f", "0xb8914bfb82815abb86da35c64d39ab838581bc0bf08967192697d9663877825f2b9d6fbdcf9b410463482b3731361aef", "0xa8187f9d22b193a5f578999954d6ec9aa9b32338ccadb8a3e1ce5bad5ea361d69016e1cdfac44e9d6c54e49dd88561b9", "0xaac262cb7cba7fd62c14daa7b39677cabc1ef0947dd06dd89cac8570006a200f90d5f0353e84f5ff03179e3bebe14231", "0xa630ef5ece9733b8c46c0a2df14a0f37647a85e69c63148e79ffdcc145707053f9f9d305c3f1cf3c7915cb46d33abd07", "0xb102c237cb2e254588b6d53350dfda6901bd99493a3fbddb4121d45e0b475cf2663a40d7b9a75325eda83e4ba1e68cb3", "0x86a930dd1ddcc16d1dfa00aa292cb6c2607d42c367e470aa920964b7c17ab6232a7108d1c2c11fc40fb7496547d0bbf8", "0xa832fdc4500683e72a96cce61e62ac9ee812c37fe03527ad4cf893915ca1962cee80e72d4f82b20c8fc0b764376635a1", "0x88ad985f448dabb04f8808efd90f273f11f5e6d0468b5489a1a6a3d77de342992a73eb842d419034968d733f101ff683", "0x98a8538145f0d86f7fbf9a81c9140f6095c5bdd8960b1c6f3a1716428cd9cca1bf8322e6d0af24e6169abcf7df2b0ff6", "0x9048c6eba5e062519011e177e955a200b2c00b3a0b8615bdecdebc217559d41058d3315f6d05617be531ef0f6aef0e51", "0x833bf225ab6fc68cdcacf1ec1b50f9d05f5410e6cdcd8d56a3081dc2be8a8d07b81534d1ec93a25c2e270313dfb99e3b", "0xa84bcd24c3da5e537e64a811b93c91bfc84d7729b9ead7f79078989a6eb76717d620c1fad17466a0519208651e92f5ff", "0xb7cdd0a3fbd79aed93e1b5a44ca44a94e7af5ed911e4492f332e3a5ed146c7286bde01b52276a2fcc02780d2109874dd", "0x8a19a09854e627cb95750d83c20c67442b66b35896a476358f993ba9ac114d32c59c1b3d0b8787ee3224cf3888b56c64", "0xa9abd5afb8659ee52ada8fa5d57e7dd355f0a7350276f6160bec5fbf70d5f99234dd179eb221c913e22a49ec6d267846", "0x8c13c4274c0d30d184e73eaf812200094bbbd57293780bdadbceb262e34dee5b453991e7f37c7333a654fc71c69d6445", "0xa4320d73296ff8176ce0127ca1921c450e2a9c06eff936681ebaffb5a0b05b17fded24e548454de89aca2dcf6d7a9de4", "0xb2b8b3e15c1f645f07783e5628aba614e60157889db41d8161d977606788842b67f83f361eae91815dc0abd84e09abd5", "0xad26c3aa35ddfddc15719b8bb6c264aaec7065e88ac29ba820eb61f220fef451609a7bb037f3722d022e6c86e4f1dc88", "0xb8615bf43e13ae5d7b8dd903ce37190800cd490f441c09b22aa29d7a29ed2c0417b7a08ead417868f1de2589deaadd80", "0x8d3425e1482cd1e76750a76239d33c06b3554c3c3c87c15cb7ab58b1cee86a4c5c4178b44e23f36928365a1b484bde02", "0x806893a62e38c941a7dd6f249c83af16596f69877cc737d8f73f6b8cd93cbc01177a7a276b2b8c6b0e5f2ad864db5994", "0x86618f17fa4b0d65496b661bbb5ba3bc3a87129d30a4b7d4f515b904f4206ca5253a41f49fd52095861e5e065ec54f21", "0x9551915da1304051e55717f4c31db761dcdcf3a1366c89a4af800a9e99aca93a357bf928307f098e62b44a02cb689a46", "0x8f79c4ec0ec1146cb2a523b52fe33def90d7b5652a0cb9c2d1c8808a32293e00aec6969f5b1538e3a94cd1efa3937f86", "0xa0c03e329a707300081780f1e310671315b4c6a4cedcb29697aedfabb07a9d5df83f27b20e9c44cf6b16e39d9ded5b98", "0x86a7cfa7c8e7ce2c01dd0baec2139e97e8e090ad4e7b5f51518f83d564765003c65968f85481bbb97cb18f005ccc7d9f", "0xa33811770c6dfda3f7f74e6ad0107a187fe622d61b444bbd84fd7ef6e03302e693b093df76f6ab39bb4e02afd84a575a", "0x85480f5c10d4162a8e6702b5e04f801874d572a62a130be94b0c02b58c3c59bdcd48cd05f0a1c2839f88f06b6e3cd337", "0x8e181011564b17f7d787fe0e7f3c87f6b62da9083c54c74fd6c357a1f464c123c1d3d8ade3cf72475000b464b14e2be3", "0x8ee178937294b8c991337e0621ab37e9ffa4ca2bdb3284065c5e9c08aad6785d50cf156270ff9daf9a9127289710f55b", "0x8bd1e8e2d37379d4b172f1aec96f2e41a6e1393158d7a3dbd9a95c8dd4f8e0b05336a42efc11a732e5f22b47fc5c271d", "0x8f3da353cd487c13136a85677de8cedf306faae0edec733cf4f0046f82fa4639db4745b0095ff33a9766aba50de0cbcf", "0x8d187c1e97638df0e4792b78e8c23967dac43d98ea268ca4aabea4e0fa06cb93183fd92d4c9df74118d7cc27bf54415e", "0xa4c992f08c2f8bac0b74b3702fb0c75c9838d2ce90b28812019553d47613c14d8ce514d15443159d700b218c5a312c49", "0xa6fd1874034a34c3ea962a316c018d9493d2b3719bb0ec4edbc7c56b240802b2228ab49bee6f04c8a3e9f6f24a48c1c2", "0xb2efed8e799f8a15999020900dc2c58ece5a3641c90811b86a5198e593d7318b9d53b167818ccdfbe7df2414c9c34011", "0x995ff7de6181ddf95e3ead746089c6148da3508e4e7a2323c81785718b754d356789b902e7e78e2edc6b0cbd4ff22c78", "0x944073d24750a9068cbd020b834afc72d2dde87efac04482b3287b40678ad07588519a4176b10f2172a2c463d063a5cd", "0x99db4b1bb76475a6fd75289986ef40367960279524378cc917525fb6ba02a145a218c1e9caeb99332332ab486a125ac0", "0x89fce4ecd420f8e477af4353b16faabb39e063f3f3c98fde2858b1f2d1ef6eed46f0975a7c08f233b97899bf60ccd60a", "0x8c09a4f07a02b80654798bc63aada39fd638d3e3c4236ccd8a5ca280350c31e4a89e5f4c9aafb34116e71da18c1226b8", "0x85325cfa7ded346cc51a2894257eab56e7488dbff504f10f99f4cd2b630d913003761a50f175ed167e8073f1b6b63fb0", "0xb678b4fbec09a8cc794dcbca185f133578f29e354e99c05f6d07ac323be20aecb11f781d12898168e86f2e0f09aca15e", "0xa249cfcbca4d9ba0a13b5f6aac72bf9b899adf582f9746bb2ad043742b28915607467eb794fca3704278f9136f7642be", "0x9438e036c836a990c5e17af3d78367a75b23c37f807228362b4d13e3ddcb9e431348a7b552d09d11a2e9680704a4514f", "0x925ab70450af28c21a488bfb5d38ac994f784cf249d7fd9ad251bb7fd897a23e23d2528308c03415074d43330dc37ef4", "0xa290563904d5a8c0058fc8330120365bdd2ba1fdbaef7a14bc65d4961bb4217acfaed11ab82669e359531f8bf589b8db", "0xa7e07a7801b871fc9b981a71e195a3b4ba6b6313bc132b04796a125157e78fe5c11a3a46cf731a255ac2d78a4ae78cd0", "0xb26cd2501ee72718b0eebab6fb24d955a71f363f36e0f6dff0ab1d2d7836dab88474c0cef43a2cc32701fca7e82f7df3", "0xa1dc3b6c968f3de00f11275092290afab65b2200afbcfa8ddc70e751fa19dbbc300445d6d479a81bda3880729007e496", "0xa9bc213e28b630889476a095947d323b9ac6461dea726f2dc9084473ae8e196d66fb792a21905ad4ec52a6d757863e7d", "0xb25d178df8c2df8051e7c888e9fa677fde5922e602a95e966db9e4a3d6b23ce043d7dc48a5b375c6b7c78e966893e8c3", "0xa1c8d88d72303692eaa7adf68ea41de4febec40cc14ae551bb4012afd786d7b6444a3196b5d9d5040655a3366d96b7cd", "0xb22bd44f9235a47118a9bbe2ba5a2ba9ec62476061be2e8e57806c1a17a02f9a51403e849e2e589520b759abd0117683", "0xb8add766050c0d69fe81d8d9ea73e1ed05f0135d093ff01debd7247e42dbb86ad950aceb3b50b9af6cdc14ab443b238f", "0xaf2cf95f30ef478f018cf81d70d47d742120b09193d8bb77f0d41a5d2e1a80bfb467793d9e2471b4e0ad0cb2c3b42271", "0x8af5ef2107ad284e246bb56e20fef2a255954f72de791cbdfd3be09f825298d8466064f3c98a50496c7277af32b5c0bc", "0x85dc19558572844c2849e729395a0c125096476388bd1b14fa7f54a7c38008fc93e578da3aac6a52ff1504d6ca82db05", "0xae8c9b43c49572e2e166d704caf5b4b621a3b47827bb2a3bcd71cdc599bba90396fd9a405261b13e831bb5d44c0827d7", "0xa7ba7efede25f02e88f6f4cbf70643e76784a03d97e0fbd5d9437c2485283ad7ca3abb638a5f826cd9f6193e5dec0b6c", "0x94a9d122f2f06ef709fd8016fd4b712d88052245a65a301f5f177ce22992f74ad05552b1f1af4e70d1eac62cef309752", "0x82d999b3e7cf563833b8bc028ff63a6b26eb357dfdb3fd5f10e33a1f80a9b2cfa7814d871b32a7ebfbaa09e753e37c02", "0xaec6edcde234df502a3268dd2c26f4a36a2e0db730afa83173f9c78fcb2b2f75510a02b80194327b792811caefda2725", "0x94c0bfa66c9f91d462e9194144fdd12d96f9bbe745737e73bab8130607ee6ea9d740e2cfcbbd00a195746edb6369ee61", "0xab7573dab8c9d46d339e3f491cb2826cabe8b49f85f1ede78d845fc3995537d1b4ab85140b7d0238d9c24daf0e5e2a7e", "0x87e8b16832843251fe952dadfd01d41890ed4bb4b8fa0254550d92c8cced44368225eca83a6c3ad47a7f81ff8a80c984", "0x9189d2d9a7c64791b19c0773ad4f0564ce6bea94aa275a917f78ad987f150fdb3e5e26e7fef9982ac184897ecc04683f", "0xb3661bf19e2da41415396ae4dd051a9272e8a2580b06f1a1118f57b901fa237616a9f8075af1129af4eabfefedbe2f1c", "0xaf43c86661fb15daf5d910a4e06837225e100fb5680bd3e4b10f79a2144c6ec48b1f8d6e6b98e067d36609a5d038889a", "0x82ac0c7acaa83ddc86c5b4249aae12f28155989c7c6b91e5137a4ce05113c6cbc16f6c44948b0efd8665362d3162f16a", "0x8f268d1195ab465beeeb112cd7ffd5d5548559a8bc01261106d3555533fc1971081b25558d884d552df0db1cddda89d8", "0x8ef7caa5521f3e037586ce8ac872a4182ee20c7921c0065ed9986c047e3dda08294da1165f385d008b40d500f07d895f", "0x8c2f98f6880550573fad46075d3eba26634b5b025ce25a0b4d6e0193352c8a1f0661064027a70fe8190b522405f9f4e3", "0xb7653f353564feb164f0f89ec7949da475b8dad4a4d396d252fc2a884f6932d027b7eb2dc4d280702c74569319ed701a", "0xa026904f4066333befd9b87a8fad791d014096af60cdd668ef919c24dbe295ff31f7a790e1e721ba40cf5105abca67f4", "0x988f982004ada07a22dd345f2412a228d7a96b9cae2c487de42e392afe1e35c2655f829ce07a14629148ce7079a1f142", "0x9616add009067ed135295fb74d5b223b006b312bf14663e547a0d306694ff3a8a7bb9cfc466986707192a26c0bce599f", "0xad4c425de9855f6968a17ee9ae5b15e0a5b596411388cf976df62ecc6c847a6e2ddb2cea792a5f6e9113c2445dba3e5c", "0xb698ac9d86afa3dc69ff8375061f88e3b0cff92ff6dfe747cebaf142e813c011851e7a2830c10993b715e7fd594604a9", "0xa386fa189847bb3b798efca917461e38ead61a08b101948def0f82cd258b945ed4d45b53774b400af500670149e601b7", "0x905c95abda2c68a6559d8a39b6db081c68cef1e1b4be63498004e1b2f408409be9350b5b5d86a30fd443e2b3e445640a", "0x9116dade969e7ce8954afcdd43e5cab64dc15f6c1b8da9d2d69de3f02ba79e6c4f6c7f54d6bf586d30256ae405cd1e41", "0xa3084d173eacd08c9b5084a196719b57e47a0179826fda73466758235d7ecdb87cbcf097bd6b510517d163a85a7c7edd", "0x85bb00415ad3c9be99ff9ba83672cc59fdd24356b661ab93713a3c8eab34e125d8867f628a3c3891b8dc056e69cd0e83", "0x8d58541f9f39ed2ee4478acce5d58d124031338ec11b0d55551f00a5a9a6351faa903a5d7c132dc5e4bb026e9cbd18e4", "0xa622adf72dc250e54f672e14e128c700166168dbe0474cecb340da175346e89917c400677b1bc1c11fcc4cc26591d9db", "0xb3f865014754b688ca8372e8448114fff87bf3ca99856ab9168894d0c4679782c1ced703f5b74e851b370630f5e6ee86", "0xa7e490b2c40c2446fcd91861c020da9742c326a81180e38110558bb5d9f2341f1c1885e79b364e6419023d1cbdc47380", "0xb3748d472b1062e54572badbb8e87ac36534407f74932e7fc5b8392d008e8e89758f1671d1e4d30ab0fa40551b13bb5e", "0x89898a5c5ec4313aabc607b0049fd1ebad0e0c074920cf503c9275b564d91916c2c446d3096491c950b7af3ac5e4b0ed", "0x8eb8c83fef2c9dd30ea44e286e9599ec5c20aba983f702e5438afe2e5b921884327ad8d1566c72395587efac79ca7d56", "0xb92479599e806516ce21fb0bd422a1d1d925335ebe2b4a0a7e044dd275f30985a72b97292477053ac5f00e081430da80", "0xa34ae450a324fe8a3c25a4d653a654f9580ed56bbea213b8096987bbad0f5701d809a17076435e18017fea4d69f414bc", "0x81381afe6433d62faf62ea488f39675e0091835892ecc238e02acf1662669c6d3962a71a3db652f6fe3bc5f42a0e5dc5", "0xa430d475bf8580c59111103316fe1aa79c523ea12f1d47a976bbfae76894717c20220e31cf259f08e84a693da6688d70", "0xb842814c359754ece614deb7d184d679d05d16f18a14b288a401cef5dad2cf0d5ee90bad487b80923fc5573779d4e4e8", "0x971d9a2627ff2a6d0dcf2af3d895dfbafca28b1c09610c466e4e2bff2746f8369de7f40d65b70aed135fe1d72564aa88", "0x8f4ce1c59e22b1ce7a0664caaa7e53735b154cfba8d2c5cc4159f2385843de82ab58ed901be876c6f7fce69cb4130950", "0x86cc9dc321b6264297987000d344fa297ef45bcc2a4df04e458fe2d907ad304c0ea2318e32c3179af639a9a56f3263cf", "0x8229e0876dfe8f665c3fb19b250bd89d40f039bbf1b331468b403655be7be2e104c2fd07b9983580c742d5462ca39a43", "0x99299d73066e8eb128f698e56a9f8506dfe4bd014931e86b6b487d6195d2198c6c5bf15cccb40ccf1f8ddb57e9da44a2", "0xa3a3be37ac554c574b393b2f33d0a32a116c1a7cfeaf88c54299a4da2267149a5ecca71f94e6c0ef6e2f472b802f5189", "0xa91700d1a00387502cdba98c90f75fbc4066fefe7cc221c8f0e660994c936badd7d2695893fde2260c8c11d5bdcdd951", "0x8e03cae725b7f9562c5c5ab6361644b976a68bada3d7ca508abca8dfc80a469975689af1fba1abcf21bc2a190dab397d", "0xb01461ad23b2a8fa8a6d241e1675855d23bc977dbf4714add8c4b4b7469ccf2375cec20e80cedfe49361d1a30414ac5b", "0xa2673bf9bc621e3892c3d7dd4f1a9497f369add8cbaa3472409f4f86bd21ac67cfac357604828adfee6ada1835365029", "0xa042dff4bf0dfc33c178ba1b335e798e6308915128de91b12e5dbbab7c4ac8d60a01f6aea028c3a6d87b9b01e4e74c01", "0x86339e8a75293e4b3ae66b5630d375736b6e6b6b05c5cda5e73fbf7b2f2bd34c18a1d6cefede08625ce3046e77905cb8", "0xaf2ebe1b7d073d03e3d98bc61af83bf26f7a8c130fd607aa92b75db22d14d016481b8aa231e2c9757695f55b7224a27f", "0xa00ee882c9685e978041fd74a2c465f06e2a42ffd3db659053519925be5b454d6f401e3c12c746e49d910e4c5c9c5e8c", "0x978a781c0e4e264e0dad57e438f1097d447d891a1e2aa0d5928f79a9d5c3faae6f258bc94fdc530b7b2fa6a9932bb193", "0xaa4b7ce2e0c2c9e9655bf21e3e5651c8503bce27483017b0bf476be743ba06db10228b3a4c721219c0779747f11ca282", "0xb003d1c459dacbcf1a715551311e45d7dbca83a185a65748ac74d1800bbeaba37765d9f5a1a221805c571910b34ebca8", "0x95b6e531b38648049f0d19de09b881baa1f7ea3b2130816b006ad5703901a05da57467d1a3d9d2e7c73fb3f2e409363c", "0xa6cf9c06593432d8eba23a4f131bb7f72b9bd51ab6b4b772a749fe03ed72b5ced835a349c6d9920dba2a39669cb7c684", "0xaa3d59f6e2e96fbb66195bc58c8704e139fa76cd15e4d61035470bd6e305db9f98bcbf61ac1b95e95b69ba330454c1b3", "0xb57f97959c208361de6d7e86dff2b873068adb0f158066e646f42ae90e650079798f165b5cd713141cd3a2a90a961d9a", "0xa76ee8ed9052f6a7a8c69774bb2597be182942f08115baba03bf8faaeaee526feba86120039fe8ca7b9354c3b6e0a8e6", "0x95689d78c867724823f564627d22d25010f278674c6d2d0cdb10329169a47580818995d1d727ce46c38a1e47943ebb89", "0xab676d2256c6288a88e044b3d9ffd43eb9d5aaee00e8fc60ac921395fb835044c71a26ca948e557fed770f52d711e057", "0x96351c72785c32e5d004b6f4a1259fb8153d631f0c93fed172f18e8ba438fbc5585c1618deeabd0d6d0b82173c2e6170", "0x93dd8d3db576418e22536eba45ab7f56967c6c97c64260d6cddf38fb19c88f2ec5cd0e0156f50e70855eee8a2b879ffd", "0xad6ff16f40f6de3d7a737f8e6cebd8416920c4ff89dbdcd75eabab414af9a6087f83ceb9aff7680aa86bff98bd09c8cc", "0x84de53b11671abc9c38710e19540c5c403817562aeb22a88404cdaff792c1180f717dbdfe8f54940c062c4d032897429", "0x872231b9efa1cdd447b312099a5c164c560440a9441d904e70f5abfc3b2a0d16be9a01aca5e0a2599a61e19407587e3d", "0x88f44ac27094a2aa14e9dc40b099ee6d68f97385950f303969d889ee93d4635e34dff9239103bdf66a4b7cbba3e7eb7a", "0xa59afebadf0260e832f6f44468443562f53fbaf7bcb5e46e1462d3f328ac437ce56edbca617659ac9883f9e13261fad7", "0xb1990e42743a88de4deeacfd55fafeab3bc380cb95de43ed623d021a4f2353530bcab9594389c1844b1c5ea6634c4555", "0x85051e841149a10e83f56764e042182208591396d0ce78c762c4a413e6836906df67f38c69793e158d64fef111407ba3", "0x9778172bbd9b1f2ec6bbdd61829d7b39a7df494a818e31c654bf7f6a30139899c4822c1bf418dd4f923243067759ce63", "0x9355005b4878c87804fc966e7d24f3e4b02bed35b4a77369d01f25a3dcbff7621b08306b1ac85b76fe7b4a3eb5f839b1", "0x8f9dc6a54fac052e236f8f0e1f571ac4b5308a43acbe4cc8183bce26262ddaf7994e41cf3034a4cbeca2c505a151e3b1", "0x8cc59c17307111723fe313046a09e0e32ea0cce62c13814ab7c6408c142d6a0311d801be4af53fc9240523f12045f9ef", "0x8e6057975ed40a1932e47dd3ac778f72ee2a868d8540271301b1aa6858de1a5450f596466494a3e0488be4fbeb41c840", "0x812145efbd6559ae13325d56a15940ca4253b17e72a9728986b563bb5acc13ec86453796506ac1a8f12bd6f9e4a288c3", "0x911da0a6d6489eb3dab2ec4a16e36127e8a291ae68a6c2c9de33e97f3a9b1f00da57a94e270a0de79ecc5ecb45d19e83", "0xb72ea85973f4b2a7e6e71962b0502024e979a73c18a9111130e158541fa47bbaaf53940c8f846913a517dc69982ba9e1", "0xa7a56ad1dbdc55f177a7ad1d0af78447dc2673291e34e8ab74b26e2e2e7d8c5fe5dc89e7ef60f04a9508847b5b3a8188", "0xb52503f6e5411db5d1e70f5fb72ccd6463fa0f197b3e51ca79c7b5a8ab2e894f0030476ada72534fa4eb4e06c3880f90", "0xb51c7957a3d18c4e38f6358f2237b3904618d58b1de5dec53387d25a63772e675a5b714ad35a38185409931157d4b529", "0xb86b4266e719d29c043d7ec091547aa6f65bbf2d8d831d1515957c5c06513b72aa82113e9645ad38a7bc3f5383504fa6", "0xb95b547357e6601667b0f5f61f261800a44c2879cf94e879def6a105b1ad2bbf1795c3b98a90d588388e81789bd02681", "0xa58fd4c5ae4673fa350da6777e13313d5d37ed1dafeeb8f4f171549765b84c895875d9d3ae6a9741f3d51006ef81d962", "0x9398dc348d078a604aadc154e6eef2c0be1a93bb93ba7fe8976edc2840a3a318941338cc4d5f743310e539d9b46613d2", "0x902c9f0095014c4a2f0dccaaab543debba6f4cc82c345a10aaf4e72511725dbed7a34cd393a5f4e48a3e5142b7be84ed", "0xa7c0447849bb44d04a0393a680f6cd390093484a79a147dd238f5d878030d1c26646d88211108e59fe08b58ad20c6fbd", "0x80db045535d6e67a422519f5c89699e37098449d249698a7cc173a26ccd06f60238ae6cc7242eb780a340705c906790c", "0x8e52b451a299f30124505de2e74d5341e1b5597bdd13301cc39b05536c96e4380e7f1b5c7ef076f5b3005a868657f17c", "0x824499e89701036037571761e977654d2760b8ce21f184f2879fda55d3cda1e7a95306b8abacf1caa79d3cc075b9d27f", "0x9049b956b77f8453d2070607610b79db795588c0cec12943a0f5fe76f358dea81e4f57a4692112afda0e2c05c142b26f", "0x81911647d818a4b5f4990bfd4bc13bf7be7b0059afcf1b6839333e8569cdb0172fd2945410d88879349f677abaed5eb3", "0xad4048f19b8194ed45b6317d9492b71a89a66928353072659f5ce6c816d8f21e69b9d1817d793effe49ca1874daa1096", "0x8d22f7b2ddb31458661abd34b65819a374a1f68c01fc6c9887edeba8b80c65bceadb8f57a3eb686374004b836261ef67", "0x92637280c259bc6842884db3d6e32602a62252811ae9b019b3c1df664e8809ffe86db88cfdeb8af9f46435c9ee790267", "0xa2f416379e52e3f5edc21641ea73dc76c99f7e29ea75b487e18bd233856f4c0183429f378d2bfc6cd736d29d6cadfa49", "0x882cb6b76dbdc188615dcf1a8439eba05ffca637dd25197508156e03c930b17b9fed2938506fdd7b77567cb488f96222", "0xb68b621bb198a763fb0634eddb93ed4b5156e59b96c88ca2246fd1aea3e6b77ed651e112ac41b30cd361fadc011d385e", "0xa3cb22f6b675a29b2d1f827cacd30df14d463c93c3502ef965166f20d046af7f9ab7b2586a9c64f4eae4fad2d808a164", "0x8302d9ce4403f48ca217079762ce42cee8bc30168686bb8d3a945fbd5acd53b39f028dce757b825eb63af2d5ae41169d", "0xb2eef1fbd1a176f1f4cd10f2988c7329abe4eb16c7405099fb92baa724ab397bc98734ef7d4b24c0f53dd90f57520d04", "0xa1bbef0bd684a3f0364a66bde9b29326bac7aa3dde4caed67f14fb84fed3de45c55e406702f1495a3e2864d4ee975030", "0x976acdb0efb73e3a3b65633197692dedc2adaed674291ae3df76b827fc866d214e9cac9ca46baefc4405ff13f953d936", "0xb9fbf71cc7b6690f601f0b1c74a19b7d14254183a2daaafec7dc3830cba5ae173d854bbfebeca985d1d908abe5ef0cda", "0x90591d7b483598c94e38969c4dbb92710a1a894bcf147807f1bcbd8aa3ac210b9f2be65519aa829f8e1ccdc83ad9b8cf", "0xa30568577c91866b9c40f0719d46b7b3b2e0b4a95e56196ac80898a2d89cc67880e1229933f2cd28ee3286f8d03414d7", "0x97589a88c3850556b359ec5e891f0937f922a751ac7c95949d3bbc7058c172c387611c0f4cb06351ef02e5178b3dd9e4", "0x98e7bbe27a1711f4545df742f17e3233fbcc63659d7419e1ca633f104cb02a32c84f2fac23ca2b84145c2672f68077ab", "0xa7ddb91636e4506d8b7e92aa9f4720491bb71a72dadc47c7f4410e15f93e43d07d2b371951a0e6a18d1bd087aa96a5c4", "0xa7c006692227a06db40bceac3d5b1daae60b5692dd9b54772bedb5fea0bcc91cbcdb530cac31900ffc70c5b3ffadc969", "0x8d3ec6032778420dfa8be52066ba0e623467df33e4e1901dbadd586c5d750f4ccde499b5197e26b9ea43931214060f69", "0x8d9a8410518ea64f89df319bfd1fc97a0971cdb9ad9b11d1f8fe834042ea7f8dce4db56eeaf179ff8dda93b6db93e5ce", "0xa3c533e9b3aa04df20b9ff635cb1154ce303e045278fcf3f10f609064a5445552a1f93989c52ce852fd0bbd6e2b6c22e", "0x81934f3a7f8c1ae60ec6e4f212986bcc316118c760a74155d06ce0a8c00a9b9669ec4e143ca214e1b995e41271774fd9", "0xab8e2d01a71192093ef8fafa7485e795567cc9db95a93fb7cc4cf63a391ef89af5e2bfad4b827fffe02b89271300407f", "0x83064a1eaa937a84e392226f1a60b7cfad4efaa802f66de5df7498962f7b2649924f63cd9962d47906380b97b9fe80e1", "0xb4f5e64a15c6672e4b55417ee5dc292dcf93d7ea99965a888b1cc4f5474a11e5b6520eacbcf066840b343f4ceeb6bf33", "0xa63d278b842456ef15c278b37a6ea0f27c7b3ffffefca77c7a66d2ea06c33c4631eb242bbb064d730e70a8262a7b848a", "0x83a41a83dbcdf0d22dc049de082296204e848c453c5ab1ba75aa4067984e053acf6f8b6909a2e1f0009ed051a828a73b", "0x819485b036b7958508f15f3c19436da069cbe635b0318ebe8c014cf1ef9ab2df038c81161b7027475bcfa6fff8dd9faf", "0xaa40e38172806e1e045e167f3d1677ef12d5dcdc89b43639a170f68054bd196c4fae34c675c1644d198907a03f76ba57", "0x969bae484883a9ed1fbed53b26b3d4ee4b0e39a6c93ece5b3a49daa01444a1c25727dabe62518546f36b047b311b177c", "0x80a9e73a65da99664988b238096a090d313a0ee8e4235bc102fa79bb337b51bb08c4507814eb5baec22103ec512eaab0", "0x86604379aec5bddda6cbe3ef99c0ac3a3c285b0b1a15b50451c7242cd42ae6b6c8acb717dcca7917838432df93a28502", "0xa23407ee02a495bed06aa7e15f94cfb05c83e6d6fba64456a9bbabfa76b2b68c5c47de00ba169e710681f6a29bb41a22", "0x98cff5ecc73b366c6a01b34ac9066cb34f7eeaf4f38a5429bad2d07e84a237047e2a065c7e8a0a6581017dadb4695deb", "0x8de9f68a938f441f3b7ab84bb1f473c5f9e5c9e139e42b7ccee1d254bd57d0e99c2ccda0f3198f1fc5737f6023dd204e", "0xb0ce48d815c2768fb472a315cad86aa033d0e9ca506f146656e2941829e0acb735590b4fbc713c2d18d3676db0a954ac", "0x82f485cdefd5642a6af58ac6817991c49fac9c10ace60f90b27f1788cc026c2fe8afc83cf499b3444118f9f0103598a8", "0x82c24550ed512a0d53fc56f64cc36b553823ae8766d75d772dacf038c460f16f108f87a39ceef7c66389790f799dbab3", "0x859ffcf1fe9166388316149b9acc35694c0ea534d43f09dae9b86f4aa00a23b27144dda6a352e74b9516e8c8d6fc809c", "0xb8f7f353eec45da77fb27742405e5ad08d95ec0f5b6842025be9def3d9892f85eb5dd0921b41e6eff373618dba215bca", "0x8ccca4436f9017e426229290f5cd05eac3f16571a4713141a7461acfe8ae99cd5a95bf5b6df129148693c533966145da", "0xa2c67ecc19c0178b2994846fea4c34c327a5d786ac4b09d1d13549d5be5996d8a89021d63d65cb814923388f47cc3a03", "0xaa0ff87d676b418ec08f5cbf577ac7e744d1d0e9ebd14615b550eb86931eafd2a36d4732cc5d6fab1713fd7ab2f6f7c0", "0x8aef4730bb65e44efd6bb9441c0ae897363a2f3054867590a2c2ecf4f0224e578c7a67f10b40f8453d9f492ac15a9b2d", "0x86a187e13d8fba5addcfdd5b0410cedd352016c930f913addd769ee09faa6be5ca3e4b1bdb417a965c643a99bd92be42", "0xa0a4e9632a7a094b14b29b78cd9c894218cdf6783e61671e0203865dc2a835350f465fbaf86168f28af7c478ca17bc89", "0xa8c7b02d8deff2cd657d8447689a9c5e2cd74ef57c1314ac4d69084ac24a7471954d9ff43fe0907d875dcb65fd0d3ce5", "0x97ded38760aa7be6b6960b5b50e83b618fe413cbf2bcc1da64c05140bcc32f5e0e709cd05bf8007949953fac5716bad9", "0xb0d293835a24d64c2ae48ce26e550b71a8c94a0883103757fb6b07e30747f1a871707d23389ba2b2065fa6bafe220095", "0x8f9e291bf849feaa575592e28e3c8d4b7283f733d41827262367ea1c40f298c7bcc16505255a906b62bf15d9f1ba85fb", "0x998f4e2d12708b4fd85a61597ca2eddd750f73c9e0c9b3cf0825d8f8e01f1628fd19797dcaed3b16dc50331fc6b8b821", "0xb30d1f8c115d0e63bf48f595dd10908416774c78b3bbb3194192995154d80ea042d2e94d858de5f8aa0261b093c401fd", "0xb5d9c75bb41f964cbff3f00e96d9f1480c91df8913f139f0d385d27a19f57a820f838eb728e46823cbff00e21c660996", "0xa6edec90b5d25350e2f5f0518777634f9e661ec9d30674cf5b156c4801746d62517751d90074830ac0f4b09911c262f1", "0x82f98da1264b6b75b8fbeb6a4d96d6a05b25c24db0d57ba3a38efe3a82d0d4e331b9fc4237d6494ccfe4727206457519", "0xb89511843453cf4ecd24669572d6371b1e529c8e284300c43e0d5bb6b3aaf35aeb634b3cb5c0a2868f0d5e959c1d0772", "0xa82bf065676583e5c1d3b81987aaae5542f522ba39538263a944bb33ea5b514c649344a96c0205a3b197a3f930fcda6c", "0xa37b47ea527b7e06c460776aa662d9a49ff4149d3993f1a974b0dd165f7171770d189b0e2ea54fd5fccb6a14b116e68a", "0xa1017677f97dda818274d47556d09d0e4ccacb23a252f82a6cfe78c630ad46fb9806307445a59fb61262182de3a2b29c", "0xb01e9fcac239ba270e6877b79273ddd768bf8a51d2ed8a051b1c11e18eff3de5920e2fcbfbd26f06d381eddd3b1f1e1b", "0x82fcd53d803b1c8e4ed76adc339b7f3a5962d37042b9683aabac7513ac68775d4a566a9460183926a6a95dbe7d551a1f", "0xa763e78995d55cd21cdb7ef75d9642d6e1c72453945e346ab6690c20a4e1eeec61bb848ef830ae4b56182535e3c71d8f", "0xb769f4db602251d4b0a1186782799bdcef66de33c110999a5775c50b349666ffd83d4c89714c4e376f2efe021a5cfdb2", "0xa59cbd1b785efcfa6e83fc3b1d8cf638820bc0c119726b5368f3fba9dce8e3414204fb1f1a88f6c1ff52e87961252f97", "0x95c8c458fd01aa23ecf120481a9c6332ebec2e8bb70a308d0576926a858457021c277958cf79017ddd86a56cacc2d7db", "0x82eb41390800287ae56e77f2e87709de5b871c8bdb67c10a80fc65f3acb9f7c29e8fa43047436e8933f27449ea61d94d", "0xb3ec25e3545eb83aed2a1f3558d1a31c7edde4be145ecc13b33802654b77dc049b4f0065069dd9047b051e52ab11dcdd", "0xb78a0c715738f56f0dc459ab99e252e3b579b208142836b3c416b704ca1de640ca082f29ebbcee648c8c127df06f6b1e", "0xa4083149432eaaf9520188ebf4607d09cf664acd1f471d4fb654476e77a9eaae2251424ffda78d09b6cb880df35c1219", "0x8c52857d68d6e9672df3db2df2dbf46b516a21a0e8a18eec09a6ae13c1ef8f369d03233320dd1c2c0bbe00abfc1ea18b", "0x8c856089488803066bff3f8d8e09afb9baf20cecc33c8823c1c0836c3d45498c3de37e87c016b705207f60d2b00f8609", "0x831a3df39be959047b2aead06b4dcd3012d7b29417f642b83c9e8ce8de24a3dbbd29c6fdf55e2db3f7ea04636c94e403", "0xaed84d009f66544addabe404bf6d65af7779ce140dc561ff0c86a4078557b96b2053b7b8a43432ffb18cd814f143b9da", "0x93282e4d72b0aa85212a77b336007d8ba071eea17492da19860f1ad16c1ea8867ccc27ef5c37c74b052465cc11ea4f52", "0xa7b78b8c8d057194e8d68767f1488363f77c77bddd56c3da2bc70b6354c7aa76247c86d51f7371aa38a4aa7f7e3c0bb7", "0xb1c77283d01dcd1bde649b5b044eac26befc98ff57cbee379fb5b8e420134a88f2fc7f0bf04d15e1fbd45d29e7590fe6", "0xa4aa8de70330a73b2c6458f20a1067eed4b3474829b36970a8df125d53bbdda4f4a2c60063b7cccb0c80fc155527652f", "0x948a6c79ba1b8ad7e0bed2fae2f0481c4e41b4d9bbdd9b58164e28e9065700e83f210c8d5351d0212e0b0b68b345b3a5", "0x86a48c31dcbbf7b082c92d28e1f613a2378a910677d7db3a349dc089e4a1e24b12eee8e8206777a3a8c64748840b7387", "0x976adb1af21e0fc34148917cf43d933d7bfd3fd12ed6c37039dcd5a4520e3c6cf5868539ba5bf082326430deb8a4458d", "0xb93e1a4476f2c51864bb4037e7145f0635eb2827ab91732b98d49b6c07f6ac443111aa1f1da76d1888665cb897c3834e", "0x8afd46fb23bf869999fa19784b18a432a1f252d09506b8dbb756af900518d3f5f244989b3d7c823d9029218c655d3dc6", "0x83f1e59e3abeed18cdc632921672673f1cb6e330326e11c4e600e13e0d5bc11bdc970ae12952e15103a706fe720bf4d6", "0x90ce4cc660714b0b673d48010641c09c00fc92a2c596208f65c46073d7f349dd8e6e077ba7dcef9403084971c3295b76", "0x8b09b0f431a7c796561ecf1549b85048564de428dac0474522e9558b6065fede231886bc108539c104ce88ebd9b5d1b0", "0x85d6e742e2fb16a7b0ba0df64bc2c0dbff9549be691f46a6669bca05e89c884af16822b85faefefb604ec48c8705a309", "0xa87989ee231e468a712c66513746fcf03c14f103aadca0eac28e9732487deb56d7532e407953ab87a4bf8961588ef7b0", "0xb00da10efe1c29ee03c9d37d5918e391ae30e48304e294696b81b434f65cf8c8b95b9d1758c64c25e534d045ba28696f", "0x91c0e1fb49afe46c7056400baa06dbb5f6e479db78ee37e2d76c1f4e88994357e257b83b78624c4ef6091a6c0eb8254d", "0x883fb797c498297ccbf9411a3e727c3614af4eccde41619b773dc7f3259950835ee79453debf178e11dec4d3ada687a0", "0xa14703347e44eb5059070b2759297fcfcfc60e6893c0373eea069388eba3950aa06f1c57cd2c30984a2d6f9e9c92c79e", "0xafebc7585b304ceba9a769634adff35940e89cd32682c78002822aab25eec3edc29342b7f5a42a56a1fec67821172ad5", "0xaea3ff3822d09dba1425084ca95fd359718d856f6c133c5fabe2b2eed8303b6e0ba0d8698b48b93136a673baac174fd9", "0xaf2456a09aa777d9e67aa6c7c49a1845ea5cdda2e39f4c935c34a5f8280d69d4eec570446998cbbe31ede69a91e90b06", "0x82cada19fed16b891ef3442bafd49e1f07c00c2f57b2492dd4ee36af2bd6fd877d6cb41188a4d6ce9ec8d48e8133d697", "0x82a21034c832287f616619a37c122cee265cc34ae75e881fcaea4ea7f689f3c2bc8150bbf7dbcfd123522bfb7f7b1d68", "0x86877217105f5d0ec3eeff0289fc2a70d505c9fdf7862e8159553ef60908fb1a27bdaf899381356a4ef4649072a9796c", "0x82b196e49c6e861089a427c0b4671d464e9d15555ffb90954cd0d630d7ae02eb3d98ceb529d00719c2526cd96481355a", "0xa29b41d0d43d26ce76d4358e0db2b77df11f56e389f3b084d8af70a636218bd3ac86b36a9fe46ec9058c26a490f887f7", "0xa4311c4c20c4d7dd943765099c50f2fd423e203ccfe98ff00087d205467a7873762510cac5fdce7a308913ed07991ed7", "0xb1f040fc5cc51550cb2c25cf1fd418ecdd961635a11f365515f0cb4ffb31da71f48128c233e9cc7c0cf3978d757ec84e", "0xa9ebae46f86d3bd543c5f207ed0d1aed94b8375dc991161d7a271f01592912072e083e2daf30c146430894e37325a1b9", "0x826418c8e17ad902b5fe88736323a47e0ca7a44bce4cbe27846ec8fe81de1e8942455dda6d30e192cdcc73e11df31256", "0x85199db563427c5edcbac21f3d39fec2357be91fb571982ddcdc4646b446ad5ced84410de008cb47b3477ee0d532daf8", "0xb7eed9cd400b2ca12bf1d9ae008214b8561fb09c8ad9ff959e626ffde00fee5ff2f5b6612e231f2a1a9b1646fcc575e3", "0x8b40bf12501dcbac78f5a314941326bfcddf7907c83d8d887d0bb149207f85d80cd4dfbd7935439ea7b14ea39a3fded7", "0x83e3041af302485399ba6cd5120e17af61043977083887e8d26b15feec4a6b11171ac5c06e6ad0971d4b58a81ff12af3", "0x8f5b9a0eecc589dbf8c35a65d5e996a659277ef6ea509739c0cb7b3e2da9895e8c8012de662e5b23c5fa85d4a8f48904", "0x835d71ed5e919d89d8e6455f234f3ff215462c4e3720c371ac8c75e83b19dfe3ae15a81547e4dc1138e5f5997f413cc9", "0x8b7d2e4614716b1db18e9370176ea483e6abe8acdcc3dcdf5fb1f4d22ca55d652feebdccc171c6de38398d9f7bfdec7a", "0x93eace72036fe57d019676a02acf3d224cf376f166658c1bf705db4f24295881d477d6fdd7916efcfceff8c7a063deda", "0xb1ac460b3d516879a84bc886c54f020a9d799e7c49af3e4d7de5bf0d2793c852254c5d8fe5616147e6659512e5ccb012", "0xacd0947a35cb167a48bcd9667620464b54ac0e78f9316b4aa92dcaab5422d7a732087e52e1c827faa847c6b2fe6e7766", "0x94ac33d21c3d12ff762d32557860e911cd94d666609ddcc42161b9c16f28d24a526e8b10bb03137257a92cec25ae637d", "0x832e02058b6b994eadd8702921486241f9a19e68ed1406dad545e000a491ae510f525ccf9d10a4bba91c68f2c53a0f58", "0x9471035d14f78ff8f463b9901dd476b587bb07225c351161915c2e9c6114c3c78a501379ab6fb4eb03194c457cbd22bf", "0xab64593e034c6241d357fcbc32d8ea5593445a5e7c24cac81ad12bd2ef01843d477a36dc1ba21dbe63b440750d72096a", "0x9850f3b30045e927ad3ec4123a32ed2eb4c911f572b6abb79121873f91016f0d80268de8b12e2093a4904f6e6cab7642", "0x987212c36b4722fe2e54fa30c52b1e54474439f9f35ca6ad33c5130cd305b8b54b532dd80ffd2c274105f20ce6d79f6e", "0x8b4d0c6abcb239b5ed47bef63bc17efe558a27462c8208fa652b056e9eae9665787cd1aee34fbb55beb045c8bfdb882b", "0xa9f3483c6fee2fe41312d89dd4355d5b2193ac413258993805c5cbbf0a59221f879386d3e7a28e73014f10e65dd503d9", "0xa2225da3119b9b7c83d514b9f3aeb9a6d9e32d9cbf9309cbb971fd53c4b2c001d10d880a8ad8a7c281b21d85ceca0b7c", "0xa050be52e54e676c151f7a54453bbb707232f849beab4f3bf504b4d620f59ed214409d7c2bd3000f3ff13184ccda1c35", "0xadbccf681e15b3edb6455a68d292b0a1d0f5a4cb135613f5e6db9943f02181341d5755875db6ee474e19ace1c0634a28", "0x8b6eff675632a6fad0111ec72aacc61c7387380eb87933fd1d098856387d418bd38e77d897e65d6fe35951d0627c550b", "0xaabe2328ddf90989b15e409b91ef055cb02757d34987849ae6d60bef2c902bf8251ed21ab30acf39e500d1d511e90845", "0x92ba4eb1f796bc3d8b03515f65c045b66e2734c2da3fc507fdd9d6b5d1e19ab3893726816a32141db7a31099ca817d96", "0x8a98b3cf353138a1810beb60e946183803ef1d39ac4ea92f5a1e03060d35a4774a6e52b14ead54f6794d5f4022b8685c", "0x909f8a5c13ec4a59b649ed3bee9f5d13b21d7f3e2636fd2bb3413c0646573fdf9243d63083356f12f5147545339fcd55", "0x9359d914d1267633141328ed0790d81c695fea3ddd2d406c0df3d81d0c64931cf316fe4d92f4353c99ff63e2aefc4e34", "0xb88302031681b54415fe8fbfa161c032ea345c6af63d2fb8ad97615103fd4d4281c5a9cae5b0794c4657b97571a81d3b", "0x992c80192a519038082446b1fb947323005b275e25f2c14c33cc7269e0ec038581cc43705894f94bad62ae33a8b7f965", "0xa78253e3e3eece124bef84a0a8807ce76573509f6861d0b6f70d0aa35a30a123a9da5e01e84969708c40b0669eb70aa6", "0x8d5724de45270ca91c94792e8584e676547d7ac1ac816a6bb9982ee854eb5df071d20545cdfd3771cd40f90e5ba04c8e", "0x825a6f586726c68d45f00ad0f5a4436523317939a47713f78fd4fe81cd74236fdac1b04ecd97c2d0267d6f4981d7beb1" ], "g2_monomial": [ "0x93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8", "0xb5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2", "0xb5337ba0ce5d37224290916e268e2060e5c14f3f9fc9e1ec3af5a958e7a0303122500ce18f1a4640bf66525bd10e763501fe986d86649d8d45143c08c3209db3411802c226e9fe9a55716ac4a0c14f9dcef9e70b2bb309553880dc5025eab3cc", "0xb3c1dcdc1f62046c786f0b82242ef283e7ed8f5626f72542aa2c7a40f14d9094dd1ebdbd7457ffdcdac45fd7da7e16c51200b06d791e5e43e257e45efdf0bd5b06cd2333beca2a3a84354eb48662d83aef5ecf4e67658c851c10b13d8d87c874", "0x954d91c7688983382609fca9e211e461f488a5971fd4e40d7e2892037268eacdfd495cfa0a7ed6eb0eb11ac3ae6f651716757e7526abe1e06c64649d80996fd3105c20c4c94bc2b22d97045356fe9d791f21ea6428ac48db6f9e68e30d875280", "0x88a6b6bb26c51cf9812260795523973bb90ce80f6820b6c9048ab366f0fb96e48437a7f7cb62aedf64b11eb4dfefebb0147608793133d32003cb1f2dc47b13b5ff45f1bb1b2408ea45770a08dbfaec60961acb8119c47b139a13b8641e2c9487", "0x85cd7be9728bd925d12f47fb04b32d9fad7cab88788b559f053e69ca18e463113ecc8bbb6dbfb024835f901b3a957d3108d6770fb26d4c8be0a9a619f6e3a4bf15cbfd48e61593490885f6cee30e4300c5f9cf5e1c08e60a2d5b023ee94fcad0", "0x80477dba360f04399821a48ca388c0fa81102dd15687fea792ee8c1114e00d1bc4839ad37ac58900a118d863723acfbe08126ea883be87f50e4eabe3b5e72f5d9e041db8d9b186409fd4df4a7dde38c0e0a3b1ae29b098e5697e7f110b6b27e4", "0xb7a6aec08715a9f8672a2b8c367e407be37e59514ac19dd4f0942a68007bba3923df22da48702c63c0d6b3efd3c2d04e0fe042d8b5a54d562f9f33afc4865dcbcc16e99029e25925580e87920c399e710d438ac1ce3a6dc9b0d76c064a01f6f7", "0xac1b001edcea02c8258aeffbf9203114c1c874ad88dae1184fadd7d94cd09053649efd0ca413400e6e9b5fa4eac33261000af88b6bd0d2abf877a4f0355d2fb4d6007adb181695201c5432e50b850b51b3969f893bddf82126c5a71b042b7686", "0x90043fda4de53fb364fab2c04be5296c215599105ecff0c12e4917c549257125775c29f2507124d15f56e30447f367db0596c33237242c02d83dfd058735f1e3c1ff99069af55773b6d51d32a68bf75763f59ec4ee7267932ae426522b8aaab6", "0xa8660ce853e9dc08271bf882e29cd53397d63b739584dda5263da4c7cc1878d0cf6f3e403557885f557e184700575fee016ee8542dec22c97befe1d10f414d22e84560741cdb3e74c30dda9b42eeaaf53e27822de2ee06e24e912bf764a9a533", "0x8fe3921a96d0d065e8aa8fce9aa42c8e1461ca0470688c137be89396dd05103606dab6cdd2a4591efd6addf72026c12e065da7be276dee27a7e30afa2bd81c18f1516e7f068f324d0bad9570b95f6bd02c727cd2343e26db0887c3e4e26dceda", "0x8ae1ad97dcb9c192c9a3933541b40447d1dc4eebf380151440bbaae1e120cc5cdf1bcea55180b128d8e180e3af623815191d063cc0d7a47d55fb7687b9d87040bf7bc1a7546b07c61db5ccf1841372d7c2fe4a5431ffff829f3c2eb590b0b710", "0x8c2fa96870a88150f7876c931e2d3cc2adeaaaf5c73ef5fa1cf9dfa0991ae4819f9321af7e916e5057d87338e630a2f21242c29d76963cf26035b548d2a63d8ad7bd6efefa01c1df502cbdfdfe0334fb21ceb9f686887440f713bf17a89b8081", "0xb9aa98e2f02bb616e22ee5dd74c7d1049321ac9214d093a738159850a1dbcc7138cb8d26ce09d8296368fd5b291d74fa17ac7cc1b80840fdd4ee35e111501e3fa8485b508baecda7c1ab7bd703872b7d64a2a40b3210b6a70e8a6ffe0e5127e3", "0x9292db67f8771cdc86854a3f614a73805bf3012b48f1541e704ea4015d2b6b9c9aaed36419769c87c49f9e3165f03edb159c23b3a49c4390951f78e1d9b0ad997129b17cdb57ea1a6638794c0cca7d239f229e589c5ae4f9fe6979f7f8cba1d7", "0x91cd9e86550f230d128664f7312591fee6a84c34f5fc7aed557bcf986a409a6de722c4330453a305f06911d2728626e611acfdf81284f77f60a3a1595053a9479964fd713117e27c0222cc679674b03bc8001501aaf9b506196c56de29429b46", "0xa9516b73f605cc31b89c68b7675dc451e6364595243d235339437f556cf22d745d4250c1376182273be2d99e02c10eee047410a43eff634d051aeb784e76cb3605d8e079b9eb6ad1957dfdf77e1cd32ce4a573c9dfcc207ca65af6eb187f6c3d", "0xa9667271f7d191935cc8ad59ef3ec50229945faea85bfdfb0d582090f524436b348aaa0183b16a6231c00332fdac2826125b8c857a2ed9ec66821cfe02b3a2279be2412441bc2e369b255eb98614e4be8490799c4df22f18d47d24ec70bba5f7", "0xa4371144d2aa44d70d3cb9789096d3aa411149a6f800cb46f506461ee8363c8724667974252f28aea61b6030c05930ac039c1ee64bb4bd56532a685cae182bf2ab935eee34718cffcb46cae214c77aaca11dbb1320faf23c47247db1da04d8dc", "0x89a7eb441892260b7e81168c386899cd84ffc4a2c5cad2eae0d1ab9e8b5524662e6f660fe3f8bfe4c92f60b060811bc605b14c5631d16709266886d7885a5eb5930097127ec6fb2ebbaf2df65909cf48f253b3d5e22ae48d3e9a2fd2b01f447e", "0x9648c42ca97665b5eccb49580d8532df05eb5a68db07f391a2340769b55119eaf4c52fe4f650c09250fa78a76c3a1e271799b8333cc2628e3d4b4a6a3e03da1f771ecf6516dd63236574a7864ff07e319a6f11f153406280d63af9e2b5713283", "0x9663bf6dd446ea7a90658ee458578d4196dc0b175ef7fcfa75f44d41670850774c2e46c5a6be132a2c072a3c0180a24f0305d1acac49d2d79878e5cda80c57feda3d01a6af12e78b5874e2a4b3717f11c97503b41a4474e2e95b179113726199", "0xb212aeb4814e0915b432711b317923ed2b09e076aaf558c3ae8ef83f9e15a83f9ea3f47805b2750ab9e8106cb4dc6ad003522c84b03dc02829978a097899c773f6fb31f7fe6b8f2d836d96580f216fec20158f1590c3e0d7850622e15194db05", "0x925f005059bf07e9ceccbe66c711b048e236ade775720d0fe479aebe6e23e8af281225ad18e62458dc1b03b42ad4ca290d4aa176260604a7aad0d9791337006fbdebe23746f8060d42876f45e4c83c3643931392fde1cd13ff8bddf8111ef974", "0x9553edb22b4330c568e156a59ef03b26f5c326424f830fe3e8c0b602f08c124730ffc40bc745bec1a22417adb22a1a960243a10565c2be3066bfdb841d1cd14c624cd06e0008f4beb83f972ce6182a303bee3fcbcabc6cfe48ec5ae4b7941bfc", "0x935f5a404f0a78bdcce709899eda0631169b366a669e9b58eacbbd86d7b5016d044b8dfc59ce7ed8de743ae16c2343b50e2f925e88ba6319e33c3fc76b314043abad7813677b4615c8a97eb83cc79de4fedf6ccbcfa4d4cbf759a5a84e4d9742", "0xa5b014ab936eb4be113204490e8b61cd38d71da0dec7215125bcd131bf3ab22d0a32ce645bca93e7b3637cf0c2db3d6601a0ddd330dc46f9fae82abe864ffc12d656c88eb50c20782e5bb6f75d18760666f43943abb644b881639083e122f557", "0x935b7298ae52862fa22bf03bfc1795b34c70b181679ae27de08a9f5b4b884f824ef1b276b7600efa0d2f1d79e4a470d51692fd565c5cf8343dd80e5d3336968fc21c09ba9348590f6206d4424eb229e767547daefa98bc3aa9f421158dee3f2a", "0x9830f92446e708a8f6b091cc3c38b653505414f8b6507504010a96ffda3bcf763d5331eb749301e2a1437f00e2415efb01b799ad4c03f4b02de077569626255ac1165f96ea408915d4cf7955047620da573e5c439671d1fa5c833fb11de7afe6", "0x840dcc44f673fff3e387af2bb41e89640f2a70bcd2b92544876daa92143f67c7512faf5f90a04b7191de01f3e2b1bde00622a20dc62ca23bbbfaa6ad220613deff43908382642d4d6a86999f662efd64b1df448b68c847cfa87630a3ffd2ec76", "0x92950c895ed54f7f876b2fda17ecc9c41b7accfbdd42c210cc5b475e0737a7279f558148531b5c916e310604a1de25a80940c94fe5389ae5d6a5e9c371be67bceea1877f5401725a6595bcf77ece60905151b6dfcb68b75ed2e708c73632f4fd", "0x8010246bf8e94c25fd029b346b5fbadb404ef6f44a58fd9dd75acf62433d8cc6db66974f139a76e0c26dddc1f329a88214dbb63276516cf325c7869e855d07e0852d622c332ac55609ba1ec9258c45746a2aeb1af0800141ee011da80af175d4", "0xb0f1bad257ebd187bdc3f37b23f33c6a5d6a8e1f2de586080d6ada19087b0e2bf23b79c1b6da1ee82271323f5bdf3e1b018586b54a5b92ab6a1a16bb3315190a3584a05e6c37d5ca1e05d702b9869e27f513472bcdd00f4d0502a107773097da", "0x9636d24f1ede773ce919f309448dd7ce023f424afd6b4b69cb98c2a988d849a283646dc3e469879daa1b1edae91ae41f009887518e7eb5578f88469321117303cd3ac2d7aee4d9cb5f82ab9ae3458e796dfe7c24284b05815acfcaa270ff22e2", "0xb373feb5d7012fd60578d7d00834c5c81df2a23d42794fed91aa9535a4771fde0341c4da882261785e0caca40bf83405143085e7f17e55b64f6c5c809680c20b050409bf3702c574769127c854d27388b144b05624a0e24a1cbcc4d08467005b", "0xb15680648949ce69f82526e9b67d9b55ce5c537dc6ab7f3089091a9a19a6b90df7656794f6edc87fb387d21573ffc847062623685931c2790a508cbc8c6b231dd2c34f4d37d4706237b1407673605a604bcf6a50cc0b1a2db20485e22b02c17e", "0x8817e46672d40c8f748081567b038a3165f87994788ec77ee8daea8587f5540df3422f9e120e94339be67f186f50952504cb44f61e30a5241f1827e501b2de53c4c64473bcc79ab887dd277f282fbfe47997a930dd140ac08b03efac88d81075", "0xa6e4ef6c1d1098f95aae119905f87eb49b909d17f9c41bcfe51127aa25fee20782ea884a7fdf7d5e9c245b5a5b32230b07e0dbf7c6743bf52ee20e2acc0b269422bd6cf3c07115df4aa85b11b2c16630a07c974492d9cdd0ec325a3fabd95044", "0x8634aa7c3d00e7f17150009698ce440d8e1b0f13042b624a722ace68ead870c3d2212fbee549a2c190e384d7d6ac37ce14ab962c299ea1218ef1b1489c98906c91323b94c587f1d205a6edd5e9d05b42d591c26494a6f6a029a2aadb5f8b6f67", "0x821a58092900bdb73decf48e13e7a5012a3f88b06288a97b855ef51306406e7d867d613d9ec738ebacfa6db344b677d21509d93f3b55c2ebf3a2f2a6356f875150554c6fff52e62e3e46f7859be971bf7dd9d5b3e1d799749c8a97c2e04325df", "0x8dba356577a3a388f782e90edb1a7f3619759f4de314ad5d95c7cc6e197211446819c4955f99c5fc67f79450d2934e3c09adefc91b724887e005c5190362245eec48ce117d0a94d6fa6db12eda4ba8dde608fbbd0051f54dcf3bb057adfb2493", "0xa32a690dc95c23ed9fb46443d9b7d4c2e27053a7fcc216d2b0020a8cf279729c46114d2cda5772fd60a97016a07d6c5a0a7eb085a18307d34194596f5b541cdf01b2ceb31d62d6b55515acfd2b9eec92b27d082fbc4dc59fc63b551eccdb8468", "0xa040f7f4be67eaf0a1d658a3175d65df21a7dbde99bfa893469b9b43b9d150fc2e333148b1cb88cfd0447d88fa1a501d126987e9fdccb2852ecf1ba907c2ca3d6f97b055e354a9789854a64ecc8c2e928382cf09dda9abde42bbdf92280cdd96", "0x864baff97fa60164f91f334e0c9be00a152a416556b462f96d7c43b59fe1ebaff42f0471d0bf264976f8aa6431176eb905bd875024cf4f76c13a70bede51dc3e47e10b9d5652d30d2663b3af3f08d5d11b9709a0321aba371d2ef13174dcfcaf", "0x95a46f32c994133ecc22db49bad2c36a281d6b574c83cfee6680b8c8100466ca034b815cfaedfbf54f4e75188e661df901abd089524e1e0eb0bf48d48caa9dd97482d2e8c1253e7e8ac250a32fd066d5b5cb08a8641bdd64ecfa48289dca83a3", "0xa2cce2be4d12144138cb91066e0cd0542c80b478bf467867ebef9ddaf3bd64e918294043500bf5a9f45ee089a8d6ace917108d9ce9e4f41e7e860cbce19ac52e791db3b6dde1c4b0367377b581f999f340e1d6814d724edc94cb07f9c4730774", "0xb145f203eee1ac0a1a1731113ffa7a8b0b694ef2312dabc4d431660f5e0645ef5838e3e624cfe1228cfa248d48b5760501f93e6ab13d3159fc241427116c4b90359599a4cb0a86d0bb9190aa7fabff482c812db966fd2ce0a1b48cb8ac8b3bca", "0xadabe5d215c608696e03861cbd5f7401869c756b3a5aadc55f41745ad9478145d44393fec8bb6dfc4ad9236dc62b9ada0f7ca57fe2bae1b71565dbf9536d33a68b8e2090b233422313cc96afc7f1f7e0907dc7787806671541d6de8ce47c4cd0", "0xae7845fa6b06db53201c1080e01e629781817f421f28956589c6df3091ec33754f8a4bd4647a6bb1c141ac22731e3c1014865d13f3ed538dcb0f7b7576435133d9d03be655f8fbb4c9f7d83e06d1210aedd45128c2b0c9bab45a9ddde1c862a5", "0x9159eaa826a24adfa7adf6e8d2832120ebb6eccbeb3d0459ffdc338548813a2d239d22b26451fda98cc0c204d8e1ac69150b5498e0be3045300e789bcb4e210d5cd431da4bdd915a21f407ea296c20c96608ded0b70d07188e96e6c1a7b9b86b", "0xa9fc6281e2d54b46458ef564ffaed6944bff71e389d0acc11fa35d3fcd8e10c1066e0dde5b9b6516f691bb478e81c6b20865281104dcb640e29dc116daae2e884f1fe6730d639dbe0e19a532be4fb337bf52ae8408446deb393d224eee7cfa50", "0x84291a42f991bfb36358eedead3699d9176a38f6f63757742fdbb7f631f2c70178b1aedef4912fed7b6cf27e88ddc7eb0e2a6aa4b999f3eb4b662b93f386c8d78e9ac9929e21f4c5e63b12991fcde93aa64a735b75b535e730ff8dd2abb16e04", "0xa1b7fcacae181495d91765dfddf26581e8e39421579c9cbd0dd27a40ea4c54af3444a36bf85a11dda2114246eaddbdd619397424bb1eb41b5a15004b902a590ede5742cd850cf312555be24d2df8becf48f5afba5a8cd087cb7be0a521728386", "0x92feaaf540dbd84719a4889a87cdd125b7e995a6782911931fef26da9afcfbe6f86aaf5328fe1f77631491ce6239c5470f44c7791506c6ef1626803a5794e76d2be0af92f7052c29ac6264b7b9b51f267ad820afc6f881460521428496c6a5f1", "0xa525c925bfae1b89320a5054acc1fa11820f73d0cf28d273092b305467b2831fab53b6daf75fb926f332782d50e2522a19edcd85be5eb72f1497193c952d8cd0bcc5d43b39363b206eae4cb1e61668bde28a3fb2fc1e0d3d113f6dfadb799717", "0x98752bb6f5a44213f40eda6aa4ff124057c1b13b6529ab42fe575b9afa66e59b9c0ed563fb20dff62130c436c3e905ee17dd8433ba02c445b1d67182ab6504a90bbe12c26a754bbf734665c622f76c62fe2e11dd43ce04fd2b91a8463679058b", "0xa9aa9a84729f7c44219ff9e00e651e50ddea3735ef2a73fdf8ed8cd271961d8ed7af5cd724b713a89a097a3fe65a3c0202f69458a8b4c157c62a85668b12fc0d3957774bc9b35f86c184dd03bfefd5c325da717d74192cc9751c2073fe9d170e", "0xb221c1fd335a4362eff504cd95145f122bf93ea02ae162a3fb39c75583fc13a932d26050e164da97cff3e91f9a7f6ff80302c19dd1916f24acf6b93b62f36e9665a8785413b0c7d930c7f1668549910f849bca319b00e59dd01e5dec8d2edacc", "0xa71e2b1e0b16d754b848f05eda90f67bedab37709550171551050c94efba0bfc282f72aeaaa1f0330041461f5e6aa4d11537237e955e1609a469d38ed17f5c2a35a1752f546db89bfeff9eab78ec944266f1cb94c1db3334ab48df716ce408ef", "0xb990ae72768779ba0b2e66df4dd29b3dbd00f901c23b2b4a53419226ef9232acedeb498b0d0687c463e3f1eead58b20b09efcefa566fbfdfe1c6e48d32367936142d0a734143e5e63cdf86be7457723535b787a9cfcfa32fe1d61ad5a2617220", "0x8d27e7fbff77d5b9b9bbc864d5231fecf817238a6433db668d5a62a2c1ee1e5694fdd90c3293c06cc0cb15f7cbeab44d0d42be632cb9ff41fc3f6628b4b62897797d7b56126d65b694dcf3e298e3561ac8813fbd7296593ced33850426df42db", "0xa92039a08b5502d5b211a7744099c9f93fa8c90cedcb1d05e92f01886219dd464eb5fb0337496ad96ed09c987da4e5f019035c5b01cc09b2a18b8a8dd419bc5895388a07e26958f6bd26751929c25f89b8eb4a299d822e2d26fec9ef350e0d3c", "0x92dcc5a1c8c3e1b28b1524e3dd6dbecd63017c9201da9dbe077f1b82adc08c50169f56fc7b5a3b28ec6b89254de3e2fd12838a761053437883c3e01ba616670cea843754548ef84bcc397de2369adcca2ab54cd73c55dc68d87aec3fc2fe4f10" ] } ================================================ FILE: testing/files/spec.toml ================================================ # Devnet Chain Spec Configuration # Gwei value constants max-effective-balance = 4_000_000_000_000 effective-balance-increment = 1_000_000_000 # Hysteresis parameters hysteresis-quotient = 4 hysteresis-downward-multiplier = 1 hysteresis-upward-multiplier = 5 # Time parameters slots-per-epoch = 32 slots-per-historical-root = 8 min-epochs-to-inactivity-penalty = 4 # Signature domains domain-type-beacon-proposer = "0x00000000" domain-type-beacon-attester = "0x01000000" domain-type-randao = "0x02000000" domain-type-deposit = "0x03000000" domain-type-voluntary-exit = "0x04000000" domain-type-selection-proof = "0x05000000" domain-type-aggregate-and-proof = "0x06000000" domain-type-application-mask = "0x00000001" # Eth1-related values deposit-contract-address = "0x4242424242424242424242424242424242424242" max-deposits-per-block = 16 deposit-eth1-chain-id = 80087 eth1-follow-distance = 1 target-seconds-per-eth1-block = 2 # Fork-related values genesis-time = 0 deneb-one-fork-time = 0 electra-fork-time = 0 electra-one-fork-time = 0 fulu-fork-time = 0 # State list lengths epochs-per-historical-vector = 8 epochs-per-slashings-vector = 8 historical-roots-limit = 8 validator-registry-limit = 1_099_511_627_776 # Capella values max-withdrawals-per-payload = 16 max-validators-per-withdrawals-sweep = 31 # Deneb values min-epochs-for-blobs-sidecars-request = 4096 max-blob-commitments-per-block = 4096 max-blobs-per-block = 6 field-elements-per-blob = 4096 bytes-per-blob = 131072 # Berachain genesis values validator-set-cap = 69 evm-inflation-address = "0x6942069420694206942069420694206942069420" evm-inflation-per-block = 10_000_000_000 # Deneb1 value changes evm-inflation-address-deneb-one = "0x4206942069420694206942069420694206942069" evm-inflation-per-block-deneb-one = 11_000_000_000 # Electra values min-activation-balance = 32_000_000_000 min-validator-withdrawability-delay = 32 # Fulu values (BRIP-0008 hysteresis + PoL vNext) hysteresis-quotient-fulu = 100 hysteresis-upward-multiplier-fulu = 10 evm-inflation-address-fulu = "0x4206942069420694206942069420694206942069" evm-inflation-per-block-fulu = 12_000_000_000 [block-delay-configuration] max-block-delay = 300_000_000_000 target-block-time = 2_000_000_000 const-block-delay = 500_000_000 consensus-update-height = 1 consensus-enable-height = 2 ================================================ FILE: testing/files/test_data.json ================================================ { "input": { "blob": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "commitment": "0x93efc82d2017e9c57834a1246463e64774e56183bb247c8fc9dd98c56817e878d97b05f5c8d900acf1fbbbca6f146556", "proof": "0x9720099d507280aba6a9c9e8c31187336d10dc6a4b04646d1aa42c8d38f891de36f939313cb99e9e7953606555db269a" } } ================================================ FILE: testing/files/test_data_batch.json ================================================ { "input": { "blobs": [ "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002", "0x1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffe304962b3598a0adf33189fdfd9789feab1096ff40006900400000003fffffffc6092c566b31415be66313fbfb2f13fd56212dfe8000d200800000007fffffff84d37e37a3c8aae349928a7775c40a7a570681bcd001be41100000010ffffffef26821fa14f77df20ff1776e6aedf77458d12939700396c2300000022ffffffdd4d043f429eefbe41fe2eedcd5dbeee8b1a25272e0072d84600000045ffffffba261ad7321441ff3bc9240392b1dc0510e08caa5900e7548d0000008cffffff734c35ae642883fe779248072563b80a21c11954b201cea91a00000119fffffee6247db575276a7fa6f1563642bdce3c3e2e750561039ef63500000234fffffdcb48fb6aea4ed4ff4de2ac6c857b9c787c5cea0ac2073dec6a00000469fffffb961e092e81740c8153921f0102ed9718f3661671810e7d7cd5000008d4fffff72b3c125d02e81902a7243e0205db2e31e6cc2ce3021cfaf9aa000011a9ffffee56043712b2a694880615422c03acba8bc8449c220139f7975500002354ffffdcab086e25654d29100c2a845807597517908938440273ef2eaa000046a9ffffb95610dc4aca9a5220185508b00eb2ea2f2112708804e7de5d5400008d53ffff72ac21b8959534a44030aa11601d65d45e4224e11009cfbcbaa800011aa7fffee55843712b2a694880615422c03acba8bc8449c220139f7975500002354ffffdcab012f4af01a8f3837a750ba86d8dafa1033fc69c243ef48ea100046aa0fffb955f25e95e0351e706f4ea1750db1b5f42067f8d38487de91d420008d541fff72abe4bd2bc06a3ce0de9d42ea1b636be840cff1a7090fbd23a840011aa83ffee557c23b7d0ba1dfe9e8b75236b6463db3014aa773d1ef7a6190900235508ffdcaaf7476fa1743bfd3d16ea46d6c8c7b6602954ee7a3def4c32120046aa11ffb955ee1af19b954e5cfce5a153d58985cae84d561f5078de9a0825008d5424ff72abdb35e3372a9cb9f9cb42a7ab130b95d09aac3ea0f1bd34104a011aa849fee557b66bc66e553973f396854f5626172ba135587d41e37a68209402355093fdcaaf6c639f3557494a69e4d764d44424b56a655d3cdfc3f4d1e529046aa128fb955ed75350c35b68f756817b8fd0803fc8fcc566bc1b84e9a56e5308d54252f72abdad32b3df63a8512fbac3e5c8f875f0218579ba9306d34c80a711aa84a6ee557b596567bec750a25f7587cb91f0ebe0430af375260da699014e2355094ddcaaf6b256e1d63b77a741a2dc5d4bd9ce1eae10932ca8184d33a69d46aa129cb955ed6339d60523c5b105fd8580bfab929b841bd29bac2d9a68f13b8d54253a72abdac573ac0a478b620bfb0b017f5725370837a537585b34d1e2771aa84a74e557b58a736a6d3bed269aade2c926a640cc3869f6b10cb369a568ef355094eacaaf6b1372e73324b0afb8139258754477f698ce99a47563d34c75df6aa129d6955ed62571e0bef637c1f2def1771280e64b5997df8b46c4a69a8fbfd54253ae2abdac496fd3d69945e66875afb44cf9c2f4db2a6b58e9864d36c380aa84a75d557b58916bba05df622f53a32c2ec1eb7c47de4f82f42f099a6f2b0255094ebbaaf6b1216386646b9ac129fe2523abceeeede499b22aba1034dffa05aa129d7855ed6241531f21840be4d6b4170d7f95d439f12e1097d01d69c1980c54253af1abdac48132509bb4ee2c301ffae127239ed20a56cd71fc37d384d419a84a75e457b5890164a13769dc58603ff5c24e473da414ad9ae3f86fa709a8335094ebc8af6b12025554c7808f134337b84ac48671a65155e20a4cdc4e14f467a129d7925ed6240336bbe7adf48909273d5bb104d9aacaa67056f5b59c2b8cd04253af25bdac48056d77cf5be912124e7ab76209b355954ce0adeb6b385719a084a75e4b7b58900a6701f764a886a754c234ec0b5d0952946d9e32d370afd742094ebc97f6b120135a164776276fd1615130000eb070cd23877ec1a3e1615285129d7930ed624025403ee7992542257a6f262815573fc241bb3fdf44c2c4490b253af262dac480490c9027df20e6cdacab127822a4ddac7e22c21a86858a36174a75e4c6b589009119204fbe41cd9b595624f04549bb58fc4584350d0b146c2e94ebc98d6b12012232409f7c839b36b2ac49e08a9376b1f88b086a1a1628d85d29d7931ad624024464813ef907366d655893c11526ed63f11610d4342c51b0ba53af2635ac4804885514d69ee4cf5d827dedaa224438efdcd864046558a50575a75e4c6c5890090f363c05eaa0013dbcc8a17c3c7ed007b45d0a64c7b14baeec4ebc98d9b120121d6c780bd540027b799142f878fda00f68ba14c98f62975dd89d7931b36240243a65027057566779aaef4c18e9f19e46cc206bef1bc5305fb23af26367c48048735617395b8331760dab5e59cbd99ab592ed1a3a348a62636575e4c6d0890090e53840cb63dcc56ed32382db8fa99393208676d06614c66acbebc98da2120121c9708196c7b98adda64705b71f532726410ceda0cc298cd597d7931b44240243926d15863c49783e045ad196369cac747cc61d9d95531b4f30af26368948048723663d65256952fec0826954652fb710f4387d9727a63842625e4c6d1390090e45588d22f7a9088038d198d0c255cc49e31d3d8a4c4c7228c5bc98da2820121c893d2c9e9c287383296ff7c97ca1f6bbc0e6bd709598e5f58c7931b45140243911066b95e52749890aacb5baf13a4b9f7c79bd3d2831cd8f19f26368a3804872210cd72bca4e931215596b75e274973ef8f37a7a50639b1e33e4c6d1470090e44219ae57949d26242ab2d6ebc4e92e7df1e6f4f4a0c7363c67c98da28e0121c884335caf293a4c485565add789d25cfbe3cde9e9418e6c78cf931b451c0243910866b95e52749890aacb5baf13a4b9f7c79bd3d2831cd8f19f26368a380487221059851551bf93a40d637d861f3fd21789e3ea010339b3873f4c6d1471090e441f3f1c83505589cad293c134367602570e74165e037368b27f98da28e3121c883d0a4b5f4d8176185cf4489064e262d617946f1803e6d3090031b451c7243910791496be9b02ec30b9e89120c9c4c5ac2f28de3007cda612006368a38e487220f2292d7d3605d86173d1224193898b585e51bc600f9b4c2400c6d1471c90e441e4525afa6c0bb0c2e7a24483271316b0bca378c01f369848018da28e3921c883c830c84d84edc40887114f2e461c8b8973f333dc3b6d3234041b451c734391078f61909b09db88110e229e5c8c391712e7e667b876da646808368a38e687220f1e4f338ec08d72a4d41202e110688c4dca7911cceab4ca74116d1471ce0e441e3b2a79762df147cc5ff0cbea18c776c38f9e65f5d269968c23da28e39d1c883c7554f2ec5be28f98bfe197d4318eed871f3ccbeba4d32d1847b451c73a391078ea35f831649b81b4378ff5d05b1439363925da3346a65bd49068a38e757220f1d36bf062c93703686f1feba0b628726c724bb4668d4cb7a920d1471ceae441e3a663f31e3f446953960c9d6964474300df43ab29179970f642a28e39d6c883c74b53f8952b5f3529e3e600fac084e429b93398ae2c32e39086451c73ae91078e953403830394ccd67f98c81d7900267b6d1373b85565c8c50d8a38e75e220f1d29680706072999acff31903af2004cf6da26e770aacb918a1b1471cebc441e3a525c2064bb2995dcb62fe69ddbf6f815aefa113d529724b83728e39d79883c74a344532223298e3c242c9363afe44e5358a064d6a22e4b146f51c73af41078e94514b89cf3297efb0025ecef57befaceabed0c09415c97ccdfa38e75e920f1d289297139e652fdf6004bd9deaf7df59d57da181282b92f99bf471cebd241e3a51252e273cca5fbec0097b3bd5efbeb3aafb4302505725f337e8e39d7a483c74a2431d74046225a5ab8fc2da2b5ee349d5a14a2a607e4c00afe1c73af4a078e944763ae808c44b4b571f85b456bdc693ab429454c0fc98015fc38e75e940f1d288e536f59c55fcbed9bbd7cb2cfaf309d62feccf41c9301cff971cebd291e3a511b32f10c3795fa5def47bf8d9754bf62c0a9dc4436260543f3e39d7a533c74a23565e2186f2bf4bbde8f7f1b2ea97ec58153b8886c4c0a87e7c73af4a678e9446a57d6898b2e4bfa74ebc45e55495bb2fd53b36cd59816b3d08e75e94df1d288d33bbf6bc332fa77a1a44ee4a289158df553a935a8302f0ba21cebd29ce3a511a5039130333c5771fb1563f13d088943e55394c74d605fbb4539d7a53ac74a23490722606678aee3f62ac7e27a111287caa7298e9ac0bf768a73af4a758e9446920e44c0ccf15dc7ec558fc4f422250f954e531d35817eed14e75e94eb1d288d241c898199e2bb8fd8ab1f89e8444a1f2a9ca63a6b02fdda29cebd29d63a511a4839130333c5771fb1563f13d088943e55394c74d605fbb4539d7a53ac74a23490722606678aee3f62ac7e27a111287caa7298e9ac0bf768a73af4a758e9446920705e657bec3f017d25c2773a18af214f91742f5517f0754f75e94eb2d288d23f6ccf23a4aee085b2184b166c27bc6a99cf2abaa72fe28e9febd29d66a511a47d65b09ff634238e1bfd5c54d045d6fd2e4a97d14b5fc6c140d7a53ace4a2348f9577398993ea99eefc77ed198820c22574171fe93bf8f2682af4a759d944691f13af989df53b5c0975bc3cb28fa766ca92f2659247f1ff1065e94eb3c288d23e102056c6b7dce03e6844dbe49eb4b014d0a8f0e45fe41860dbd29d679511a47c1040ad8d6fb9c07cd089b7c93d696029a151e1c8bfc830c1b7a53acf2a2348f820815b1adf7380f9a1136f927ad2c05342a3c3917f9061836f4a759e544691f04102b635bee701f34226df24f5a580a685478722ff20c306de94eb3ca88d23e082056c6b7dce03e6844dbe49eb4b014d0a8f0e45fe41860dbd29d679511a47c1040ad8d6fb9c07cd089b7c93d696029a151e1c8bfc830c1b7a53acf2a2348f8200d6d738c49e37c58e035ba72c91e7b3d5005ed7c906327704a759e554691f03f1adae71893c6f8b1c06b74e5923cf67aa00bdaf920c64ee094eb3caa8d23e07e35b5ce31278df16380d6e9cb2479ecf54017b5f2418c9dc129d679551a47c0fc6b6b9c624f1be2c701add39648f3d9ea802f6be483193b8253acf2aa348f81f862e99171749a4845d021cf248845dbcfaca133c606341b05a759e555691f03ef51e57b8fbf9713436d09c64106e9df9a0584c3890c69da0c4eb3caabd23e07dd2fdd4fcc5590a93ea6d9b47a0431e72eb74be30f18d558199d679558a47c0fb95fba9f98ab21527d4db368f40863ce5d6e97c61e31aab0333acf2ab148f81f724b8797de2ca527b2682cf9e00725c4b58971e83963570467759e556391f03ee3232188692facd21c9d201bb804a9b165bf262c6fc6afaccfeb3caac823e07dc5464310d25f59a4393a403770095362cb7e4c58df8d5f599fd679559047c0fb8a18987a519515cb2a414696d80904ed91a8db0dbc1ac05740acf2ab218f81f7133130f4a32a2b9654828d2db01209db2351b61b783580ae8159e556431f03ee266261e94654572ca9051a5b602413b646a36c36f06b015d02b3caac863e07dc4c50d62b397f10dc09d6fadeb83e859487f31ac9ddd6045e066795590d7c0fb8972dbeaf1fd4843acb7abbe5687369510a9277efb8ac0a600dcf2ab21bf81f712d5b7d5e3fa9087596f577cad0e6d2a21524efdf715814c01b9e556437f03ee25a430d152c28736de5b7b5bd99c4036c24f6221adfb02b24383caac870e07dc4b3122c830527495e833c31a32b7e650044988691bc6057ec71795590e2c0fb89652459060a4e92bd0678634656fcca0089310d2378c0afd8e2f2ab21c581f712ca48b20c149d257a0cf0c68cadf9940112621a46f1815fb1c5e556438b03ee25941d7670d610ad76d1ae534153e9862a1f7076e9e002c1078ccaac871707dc4b273aece1ac215aeda35ca682a7d30c543ee0edd3c005820f1995590e2e0fb8964e01ec1c0519185dfe86132d479c76d0786e1e037d0b05c2342ab21c5d1f712c9b03d8380a3230bbfd0c265a8f38eda0f0dc3c06fa160b8468556438ba3ee2593607b07014646177fa184cb51e71db41e1b8780df42c1708d0aac871747dc4b26c0f60e028c8c2eff430996a3ce3b683c370f01be8582e11a15590e2e8fb8964d81ec1c0519185dfe86132d479c76d0786e1e037d0b05c2342ab21c5d1f712c9b03d8380a3230bbfd0c265a8f38eda0f0dc3c06fa160b8468556438ba3ee259360071959f31c7a0259519179df1412461633c33b3fc172310bac871748dc4b26bf0e32b3e638f404b2a322f3be28248c2c6786767f82e46217590e2e91b8964d7e1c6567cc71e809654645e77c50491858cf0cecff05c8c42eb21c5d23712c9afc38cacf98e3d012ca8c8bcef8a09230b19e19d9fe0b91885d6438ba46e25935f871959f31c7a0259519179df1412461633c33b3fc172310bac871748dc4b26bf06f3d971065a2cde1fef563da78a6eac124a9c3f52e47c57690e2e91c8964d7df6a8d86cda1a81e7bcab0eface7abfd7cf595e3e75c912eee21c5d23a12c9afbd612d664819b2bfaf62280751c5b622f4976e23cbb92401dd438ba47525935f794e6d253d09c802169116369b81ca6de3db1ea3947249a7bb871748eb4b26bef128eca326e9f286e4eef2952ef9f303c2627fa325e494f3780e2e91d7964d7de151d9464dd3e50dc9dde52a5df3e60784c4ff464bc929e6f01c5d23af2c9afbc22fc4e5487e2c9e4b88907cb3de2a37043640e894925571e138ba475f5935f7835f89ca90fc593c971120f967bc546e086c81d12924aae3c271748ebeb26bef064b25edcecf14fbe5ef081ac76f07040b8545fe4f49576b85e2e91d7e64d7de0b225e344a748c7a83aad65d86d46c3011b6ce589b92b07b0cc5d23afdc9afbc1544bc6894e918f50755acbb0da8d860236d9cb1372560f6198ba475fb935f782a158b29d6a8946cc6781f9e13480ee841877bbe6b4ac390341748ebf826bef0532b1653ad5128d98cf03f3c26901dd0830ef77cd6958720682e91d7f04d7de0a6562ca75aa251b319e07e784d203ba1061deef9ad2b0e40d05d23afe09afbc14c386ba7621b05e8eb8dc3189236d56a06e8204f57561e25a1ba475fc235f7829770d74ec4360bd1d71b8631246daad40dd0409eaeac3c4b43748ebf846bef052e6dc0f635427a266603d28a40d1b3d0164cc3995a587a3a87e91d7f09d7de0a5b679445175b56cf83d46b3c7999c5c82745c98eb1b0f61910d23afe14afbc14b55b3ae2db8d1021bf759ca0eb29e9b84937d5796061edd622a475fc2a5f78296942881e63f082c636b7ff69ce4a31988d1bed4ebdc3dd504648ebf855bef052d111229574b7680f253cc4fb948ac15914e41cf97887bc448d91d7f0ac7de0a5a122452ae96ed01e4a7989f7291582b229c839f2f10f78891b23afe158fbc14b42448a55d2dda03c94f313ee522b0564539073e5e21ef11236475fc2b1f78296841527045291a2fbe1b2ee049c4c68f0a1cd2a27c13de3c86d8ebf8564ef052d072a4e08a52345f7c365dc093898d1e1439a544f827bc790db1d7f0ac9de0a5a0e549c114a468bef86cbb8127131a3c28734a89f04f78f21b63afe1593bc14b41c354a7b41637a61c564364cda59a5ad0915939a06ef1fe76d75fc2b28782968376a94f682c6f4c38ac86c99b4b34b5a122b27340dde3fcedaebf85650f052d06e613c45b2644c09cd5d9f5b615cf4dc1f0290c418bc8141b6d7f0aca2e0a5a0db4e8ae4119efa96528804debab047e038b163e42e7904276eafe15946c14b41b5292820d01457af5cdccfe56d56ede86c0f0a2459f209f2de5fc2b28e82968369525041a028af5eb9b99fcadaaddbd0d81e1448b3e413e5bcbf85651d052d06d230b2dbed27c1402b4005bdad5215c9aae86aed64c8296f7a7f0aca3b0a5a0da36165b7da4f828056800b7b5aa42b9355d0d5dac99052def4fe15947614b41b464eddc86175678364ccdd1ead3eb54ea64dee119020a761eafc2b28ed2968368b29cde96fc13189816680655273c8c547481e7f1d415067d6f85651db52d06d15539bd2df82631302cd00caa4e7918a8e903cfe3a82a0cfadf0aca3b6a5a0da2a3349fe6bdb28a8bd66c7bd41c5813d17ccbc58720543435ce159476e4b41b4536693fcd7b651517acd8f7a838b027a2f9978b0e40a8686b9c2b28edc968368a6593a525c430525ad67e51cff0c631c59df33bdc5150eb17485651dba2d06d14b3e86fd655c6cce129c9061f60f2460ae6aa9d7872a1f06ea0aca3b755a0da295092053778f3c1edd05e6ebe414a6e95781960b0b543fb1d5159476ebb41b45291240a6ef1e783dba0bcdd7c8294dd2af032c1616a87f63aa2b28edd768368a5224814dde3cf07b74179baf90529ba55e06582c2d50fec7545651dbaed06d14a449029bbc79e0f6e82f375f20a5374abc0cb0585aa1fd8ea8aca3b75da0da29481e179025ca2470882b34e63940ccbd72c5a30cb243fcc15259476ebc41b4528f3c2f204b9448e1105669cc7281997ae58b46196487f982a4b28edd788368a51e04709943fef444d87999c0dcf9911dc5c2ce8ec60ff4a94a651dbaf206d14a3b08e13287fde889b0f33381b9f3223b8b859d1d8c1fe95294ca3b75e40da2947611c2650ffbd11361e6670373e64477170b3a3b183fd2a5299476ebc81b4528ec2384ca1ff7a226c3ccce06e7cc88ee2e167476307fa54a5328edd790368a51d84709943fef444d87999c0dcf9911dc5c2ce8ec60ff4a94a651dbaf206d14a3b01a25812cb4eb1dc6fffe43972881e0b3061434befe96cd4da3b75e41da29475f344b025969d63b8dfffc872e5103c1660c28697dfd2d9a9b476ebc83b4528ebe689604b2d3ac771bfff90e5ca20782cc1850d2fbfa5b35368edd790768a51d7c5d3e62127dbb70efccb844b13a6d2d92dce401f4f4b80e6e1dbaf20fd14a3af7468f1cd1d1d964976636b15a6b388320660a5fe6e971c0dd3b75e420a29475ed193092507a154be699338aaccccf2e3b78571bcad2e525bb76ebc8424528ebd9326124a0f42a97cd32671559999e5c76f0ae3795a5ca4b76edd790848a51d7b264c24941e8552f9a64ce2ab3333cb8ede15c6f2b4b9496eddbaf210914a3af645596eb30a70ce1ec96627d5e5cd799d66efb3a53972ad1dcb75e421329475ec737402f0e247c4690f98b22b4b00d5ba78a38d0a42e5747ba6ebc8427528ebd8d6e805e1c48f88d21f3164569601ab74f1471a1485cae8f74dd79084ea51d7b1a691314e568539cfbb2f2b2cab6939698d5259e8db95ec2eabaf2109e4a3af6335e388277a709bcaf32ab8d8d6385552c568d991872bf29d675e4213d9475ec6548835d9c2475fc16321d4312bd68d253595d8e2de57ff7adebc8427c28ebd8c91d1913e51f4e7ae43100ae1d712fcca15efd7858cb01935cd79084f951d7b1913a3227ca3e9cf5c862015c3ae25f9942bdfaf0b1960326b9af2109f2a3af63220076a841539c6e4890c8e06dbb1d5a8028383d602c07f1745e4213e6475ec64300ed5082a738dc912191c0db763ab50050707ac0580fe2e8bc8427cc8ebd8c8601daa1054e71b922432381b6ec756a00a0e0f580b01fc5d179084f991d7b190c03b5420a9ce372448647036dd8ead40141c1eb01603f8ba2f2109f323af63218076a841539c6e4890c8e06dbb1d5a8028383d602c07f1745e4213e6475ec64300ed5082a738dc912191c0db763ab50050707ac0580fe2e8bc8427cc8ebd8c8601daa1054e71b922432381b6ec756a00a0e0f580b01fc5d179084f991d7b190c03b5420a9ce372448647036dd8ead40141c1eb01603f8ba2f2109f323af63218002ba9a0072d0cb4895a695b313b8a822e47fbc2907f3185f4213e6485ec642ff05753400e5a196912b4d2b6627715045c8ff78520fe630be8427cc90bd8c85fe0aea6801cb432d22569a56cc4ee2a08b91fef0a41fcc617d084f99217b190bfc15d4d00396865a44ad34ad989dc5411723fde1483f98c2fa109f3242f63217f82ba9a0072d0cb4895a695b313b8a822e47fbc2907f3185f4213e6485ec642ff05753400e5a196912b4d2b6627715045c8ff78520fe630be8427cc90bd8c85fe03ab8d8c98a9554dd366b94bce48830b3cc31663efcc7bbd184f99218b190bfbf01840a3feb8d2c72399d5171bf6e896244a5287af9911ba409f3243263217f7d0308147fd71a58e4733aa2e37edd12c4894a50f5f322374813e64864c642fefa061028ffae34b1c8e67545c6fdba25891294a1ebe6446e9027cc90c98c85fdf40c2051ff5c696391ccea8b8dfb744b12252943d7cc88dd204f992193190bfbe81840a3feb8d2c72399d5171bf6e896244a5287af9911ba409f3243263217f7d0308147fd71a58e4733aa2e37edd12c4894a50f5f322374813e64864c642fefa061028ffae34b1c8e67545c6fdba25891294a1ebe6446e9027cc90c98c85fdf404e1778a29cf8bbd49b6ee0d7ada2d91cfed69979c88f7605f992193290bfbe7f284149f21053fa6103a3e9a751a3da34a9ef8ef09120900cf3243266217f7cfd508293e420a7f4c20747d34ea347b46953df1de122412019e64864cc42fef9fa2d17807517b26c3bdb55ce953ced90cd540097bf4483e434cc90c99985fdf3f35a2f00ea2f64d877b6ab9d2a79db219aa8012f7e8907c869992193330bfbe7e640705a81352c33a73a1d624cea146b2ffc44bafa121134d43243266717f7cfcb0cf30daf40baea064100ec91ca86fe5aa4cbd1f124240da964864ccf2fef9f9519e61b5e8175d40c8201d923950dfcb54997a3e248481b52c90c999e5fdf3f2a33cc36bd02eba8190403b2472a1bf96a932f47c4909036a59219333cbfbe7e5467986d7a05d750320807648e5437f2d5265e8f8921206d4b243266797f7cfca85b4333a0e211231bdcd4f1149ece0da4f8ff7b0f42427e974864ccf3fef9f94f4298bfee9a84c8ef86700a2133fa43449e41521b8486a12f90c999e8fdf3f29d1143d88a0b6c1496d9a63c3a5e52ae83e8c50034090ee660219333d2fbe7e5392287b11416d8292db34c7874bca55d07d18a0068121dccc0432667a5f7cfca72450f62282db0525b6698f0e9794aba0fa31400d0243b9980864ccf4bef9f94e416311cfd31c3276e99f809cae8f39c19f26a5d9d4878d7020c999e98df3f29c72c6239fa63864edd33f01395d1e73833e4d4bb3a90f1ae0419333d31be7e538e58c473f4c70c9dba67e0272ba3ce7067c9a9767521e35c0832667a637cfca71c3d9b4096647bbe2c9c86764f3dfb08ca3f9548e743c85c1164ccf4c7f9f94e370748d9d99f59ff1105d314967254398f2b6cedcb87925c23c999e990f3f29c6d0e91b3b33eb3fe220ba6292ce4a8731e56d9db970f24b8479333d321e7e538da1d2367667d67fc44174c5259c950e63cadb3b72e1e49708f2667a643cfca71b43a46ceccfacff8882e98a4b392a1cc795b676e5c3c92e11e4ccf4c879f94e368009ff646cc0273c829f7715f1ba1c0ed631138b57927663d999e99103f29c6cf013fec8d9804e79053eee2be374381dac622716af24ecc7b333d32207e538d9e027fd91b3009cf20a7ddc57c6e8703b58c44e2d5e49d98f6667a6440fca71b3c04ffb23660139e414fbb8af8dd0e076b1889c5abc93b31ecccf4c881f94e367809ff646cc0273c829f7715f1ba1c0ed631138b57927663d999e99103f29c6cf013fec8d9804e79053eee2be374381dac622716af24ecc7b333d32207e538d9e027fd91b3009cf20a7ddc57c6e8703b58c44e2d5e49d98f6667a6440fca71b3c04ffb23660139e414fbb8af8dd0e076b1889c5abc93b31ecccf4c881f94e367802c089f78d8d64ae1c4378713981f155dbd7b11762767e19a9e99104029c6ceff58113ef1b1ac95c3886f0e27303e2abb7af622ec4ecfc3353d322080538d9dfe3c34d69039bbae3edda4444656da7d71a22ea1d59da12a6b7a644101a71b3bfb047c05cd49d9df35880eb084a41322ddf09f9fa83b43f8d7f4c882044e3677f508f80b9a93b3be6b101d6109482645bbe13f3f507687f1afe99104089c6cefea11f0173527677cd6203ac212904c8b77c27e7ea0ed0fe35fd322081138d9dfd423e02e6a4ecef9ac40758425209916ef84fcfd41da1fc6bfa644102271b3bfa847c05cd49d9df35880eb084a41322ddf09f9fa83b43f8d7f4c882044e3677f501b931256119e6968ce9c388c78c283b8c03651046880beff9910408ac6cefe9f372624ac233cd2d19d387118f1850771806ca208d1017dff322081158d9dfd3e6e4c49584679a5a33a70e231e30a0ee300d94411a202fbfe6441022b1b3bfa7c68aaeb5d6355cdfe41a7ec5bbc7245c0adf4e42044079bfdc88204573677f4f75d682f679d0e1eb4501600af6f42b37c082c243d8810dbfc910408af6cefe9ed46e2b77c107ec0206cf22956d4e38ef2bc9aa47810235bfa2208115fd9dfd3d919d7c7a4f76002f8a6aa7aa5a02545e02577a4ed20485bf5441022c0b3bfa7b133af8f49eec005f14d54f54b404a8bc04aef49da4090b7ea88204581677f4f62675f1e93dd800be29aa9ea968095178095de93b481216fd510408b02cefe9ec45ad095d491629a7d0219fd24f78856fbd7ff8366024483ab208116069dfd3d8741b38455f927b7b1d0fa2241e56ed5f25c4162c9048aab5741022c0e3bfa7b0d0f796158c8b1f21b6eba6c7bc13bd3df64c5218f0916faaf8204581d77f4f6191ef2c2b19163e436dd74d8f78277a7bec98a431e122df55f0408b03aefe9ec323de5856322c7c86dbae9b1ef04ef4f7d9314863c245beabe08116075dfd3d86407dd63731bf2139342998bd6003cc6f5d26b687548b9797d1022c0ecbfa7b0c70fbac6e637e42726853317ac00798deba4d6d0ea9172f2fa204581d97f4f618e1f758dcc6fc84e4d0a662f5800f31bd749ada1d522e5e5f4408b03b2fe9ec31c3eeb1b98df909c9a14cc5eb001e637ae935b43aa45cbcbe881160765fd3d863809e88fde9583bbebf65ee557fa2a9757d2f8e3518b993bd2022c0eccfa7b0c6f13d11fbd2b0777d7ecbdcaaff4552eafa5f1c6a3173277a404581d99f4f618de27a23f7a560eefafd97b955fe8aa5d5f4be38d462e64ef4808b03b33e9ec31bc4f447ef4ac1ddf5fb2f72abfd154babe97c71a8c5cc9de9011607667d3d863782a9b56962e9e417732b47d7799079d77dbd09115b995612122c0ecd0a7b0c6ef5536ad2c5d3c82ee6568faef320f3aefb7a1222b732ac2424581d9a14f618dde367fb30590db889497981dd65a7c9dda1b84a053e65728858b03b3439ec31bbb6cff660b21b711292f303bacb4f93bb4370940a7ccae510b160766873d863776661124c319d0a50a2b269f5160509f631a54dd4c995e46172c0ecd0f7b0c6eeb5834a2330a03cccc2313669ab6ff66c0e0ec169632be302f581d9a1ff618ddd53c7b9d12ea6a1c5012ecf52d645cf57c6e1a8929657e045fb03b3440ec31bba9050992d2ab36bb57f2a01252bf1812f388776e4fcafdacc060766882d86377510a1325a5566d76afe54024a57e3025e710eedc9f95fb5980c0ecd105b0c6eea214264b4aacdaed5fca80494afc604bce21ddb93f2bf6b30181d9a20b618ddd44284c969559b5dabf95009295f8c0979c43bb727e57ed660303b34416c31bba8850992d2ab36bb57f2a01252bf1812f388776e4fcafdacc060766882d863775102d44b3023d39edb620c8724fd960866bbb3025f65fb73c0d0ecd105c0c6eea1f5a8966047a73db6c4190e49fb2c10cd776604becbf6e781a1d9a20b818ddd43e412524b5cb4a39904fe7f1375be041a99902f3d67ede94353b34417131bba87b0e5ca2186cf6f5d86c960a66ae1eab4dde4843a9fdbecc6b766882e3637750f51cb94430d9edebb0d92c14cd5c3d569bbc908753fb7d98d6ecd105c6c6eea1ea39728861b3dbd761b258299ab87aad3779210ea7f6fb31add9a20b8d8ddd43d472e510c367b7aec364b0533570f55a6ef2421d4fedf6635bb344171b1bba87a871dc7a33a5d1e03e9626ce62d848dcd890c6969cdbee6ab866882e3737750f4f6fcb4d1422064334f913c4bda6efe1abcdcf8936b7de7971cd105c6f6eea1e9d6ba8f2d51a6f0921beedb173443deb5247e16e6a6fbe96e49a20b8dfddd43d3963643e570b4094fb4aa18ade7ed9fe9f3c0538d1df7ed1ca344171c0bba87a7152dad55aece3acae62093db4f4122539244ccda0beff47956882e3827750f4e131c80362b029dc1490d8a361de82726cf4dbf73e7e00332bd105c705eea1e9c1639006c56053b82921b146c3bd04e4d9e9b7ee7cfc006657a20b8e0bdd43d382533266379709f30a1028b57f7067f1ae7fb238f6f80270b044171c18ba87a7033277251c047668cbed1792f6d72e0b57aba6cdeaf0068561882e3832750f4e0564ee4a3808ecd197da2f25edae5c16af574d9bd5e00d0ac3105c7064ea1e9c0a55eeed1ce83c25e7812473d3531655595add93a8c01bb98720b8e0cad43d381337f032e6a6dace86cf0f0f9e9c8ad2ad61fd834e8039170f4171c196a87a70256fe065cd4db59d0d9e1e1f3d3915a55ac3fb069d00722e1e82e3832d50f4e04a6bd3244771cdbcd309026672688972b03438693700e6003e05c7065ba1e9c09363b8a13bb9fdfc5ddecaf4dcc7710d5b14b32e6b01cda47d0b8e0cb843d3812553839b244a5e7b738a5c11b1854042b0d5a8b8d3039cecfb171c197187a7024933198ef56b1f799ee17e4b5b00dead5c5793cda3073b7df72e3832e40f4e049166331dead63ef33dc2fc96b601bd5ab8af279b460e76fbee5c7065c81e9c09225878948282e0693352bf5563f9d8dd6c0a9192891cef9bddb8e0cb913d3812433d0381b1dc23551e7244d2bfea0fe2d2c165810f39e0dbbc71c197237a70248506195c108ea92cf4b14fcd77ca7deda02f0d5e1b73c35b79e3832e47f4e049090c32b8211d5259e9629f9aef94fbdb405e1abc36e786b6f3c7065c8fe9c09212186570423aa4b3d2c53f35df29f7b680bc35786dcf0d6de78e0cb91fd381242430cae084754967a58a7e6bbe53ef6d01786af0db9e1adbcf1c19723fa70248486195c108ea92cf4b14fcd77ca7deda02f0d5e1b73c35b79e3832e47f4e0490904f3ddabeab88214df6bfd6f1461bdc008dee1f6b786d133d7065c8ff9c09211f2a8e0e2a2d72c553ba45d5da8295dffbc81e9ad3f0dbca7be0cb92003812423d551c1c545ae58aa7748babb5052bbff7903d35a7e1b794f7c19724007024847a364a91558c2d9806b5dd7f6200b5a7e9ccbcc74cc370cdf0832e4801e04908f36c9522ab185b300d6bbafec4016b4fd399798e9986e19be1065c9003c09211e6653c9e030718e2d2a43c257ff934c7a1df3579300dc4dbc30cb92008812423cb568b94b2e494485d153e72f7e8c7b73e6aad4e5d1b8b5b871972401202484795392982129f8b1371f7430de7c7ed9677819cf8b737185b0f32e4802504908f29725304253f1626e3ee861bcf8fdb2cef0339f16e6e30b61e65c9004a09211e5270b860f7548ed07fa9d25f97161481d8b2b63ed9dc63103dcb92009512423ca36d831a9b7f8023b7206ae72622872bac11aed9b0b8c7c47c9724012b2484794567188de3d562ca260d9bf6443b6c7f52cfa00f5e71912cfa2e4802574908f2895a43747481281703e7fe14806d3726a04b827ab9e323fdf55c9004af9211e51140994195d8b2b0bf9cc250f8d0cc753b43475170c6499febb92009602423ca210d44dbd887c7e437064ac9e997f7127132d0fede8c94e3d8724012c1484794411a89b7b10f8fc86e0c9593d32fee24e265a1fdbd1929c7b0e4802582908f288235136f621f1f90dc192b27a65fdc49c4cb43fb7a32538f61c9004b05211e51046a26dec43e3f21b832564f4cbfb893899687f6f464a71ec39200960a423ca2086060163552e0c6283172c69175cf4f0dd95249e5c94fe18824012c158479440f4cd285177c240f082fabb51ae1fcc6165ee6efc892a167114802582c08f2881d25b762dbceaaa0c82c1d922dba57b4276a103b8e254472239004b05911e510394b6ec5b79d554190583b245b74af684ed420771c4a88e447200960b223ca207222efe41c110d05d87d3c70aedfbcf89854834a3595136c8f4012c165479440e345dfc838221a0bb0fa78e15dbf79f130a906946b2a26d91e802582ca8f2881c617d1e91d1a969a19c1b7eab375520a5bfe4f84d3544f563e004b05961e51038b2fa3d23a352d3433836fd566eaa414b7fc9f09a6a89eac7c00960b2c3ca207165f47a4746a5a686706dfaacdd548296ff93e134d513d58f8012c165879440e2c4aa1a195ab175385da857d93a0ee7ada9ebe8297a27c55f102582cb1f2881c5721559bd82c9129c381d1231f383b1dafe9bf612c44fa4fe304b05964e51038ad42ab37b05922538703a2463e70763b5fd37ec25889f49fc60960b2c9ca20715a1168c80d88a729c5d40ab474d74a9eba533fe0ae13eae38d12c165949440e2b322d1901b114e538ba81568e9ae953d74a67fc15c27d5c71a2582cb292881c56645a32036229ca717502ad1d35d2a7ae94cff82b84fab8e344b05965251038acc175899191b9bd0e66d1bcb9eb0b31dcd4641616d9f58c069960b2ca5a20715972eb132323737a1ccda37973d61663b9a8c82c2db3eb180d32c16594b440e2b2e5d6264646e6f4399b46f2e7ac2cc7735190585b67d6301a6582cb296881c565c46d72175b34109eb35a484ed7bf71664de4d6769fac7a74db059652e1038acb719c09b983ce4968e380f31d2ee4c54c468dd2ad0f590f29c60b2ca5d2071596d3381373079c92d1c701e63a5dc98a988d1ba55a1eb21e538c16594ba40e2b2da67026e60f3925a38e03cc74bb9315311a374ab43d643ca7182cb297481c565b45a17356ebd8737298d3fb68f68c0ce1df32bb284ac8938e4059652ea038acb674040c38a5170f10ae7459516c7dfc4369299c106591415c90b2ca5d5071596cd0c93dfc1794464cd9b515225861db067d175de09b229cf9316594bab0e2b2d991927bf82f288c99b36a2a44b0c3b60cfa2ebbc1364539f262cb297561c565b32324f7f05e51193366d4548961876c19f45d77826c8a73e4c59652eac38acb664649efe0bca23266cda8a912c30ed833e8baef04d914e7c98b2ca5d5871596cc8555054c46aa8cf9181db4a5058392e77c3a03c98229e9d326594bab1e2b2d98f36b30235abb421dad07cbc98a6d084ea3382d52d453ede65cb297564c565b31d6d66046b576843b5a0f979314da109d46705aa5a8a7dbccb9652eac98acb663a66de618385330a230eb91a5a91a03ba37a4db0b214fd1d982ca5d5941596cc7359cf1bb3e0c896fdea385cad199e9f41a0ddbd6129fbdf31594bab292b2d98e53fb0901497f3b0b3a136e152299b667dedfdd6bf53f96263b2975653565b31c90b7378d60649e41f0f33ea9c4994f4f6883e097ba7f468c8652eaca7acb6639116e6f1ac0c93c83e1e67d5389329e9ed107c12f74fe8d190ca5d594f596cc7222dcde3581927907c3ccfaa712653d3da20f825ee9fd1a32194bab29eb2d98e445b9bc6b0324f20f8799f54e24ca7a7b441f04bdd3fa346432975653d65b31c884349e60d3b00c4a8c004d1bc8fad77633022f3b77f48308752eaca7bcb66390f12a624c74c640c094ccfcb7115b916c10c88436bfe92050fa5d594f896cc721d254c498e98c81812999f96e22b722d82191086d7fd240a1f4bab29f12d98e43a4a98931d31903025333f2dc456e45b0432210daffa48143e975653e25b31c87421437ee73982e30233448380a426de031084775cf491cc7e2eaca7c5b66390e74286fdce7305c60466890701484dbc062108eeb9e92398fc5d594f8b6cc721ce11205449bc6e0ec099d835fa86f9a006ee543970d248d5f9bab29f17d98e439b2240a89378dc1d8133b06bf50df3400ddca872e1a491abf375653e2fb31c873644815126f1b83b026760d7ea1be6801bb950e5c3492357e6eaca7c5f66390e6c1514fafab9d2f8bc9b87d7cc2e2b28321ee42783924853ced594f8bfcc721cd72a29f5f573a5f179370faf985c5650643dc84f072490a79dab29f17f98e439ae5453ebeae74be2f26e1f5f30b8aca0c87b909e0e49214f3b5653e2ff31c8735c34ba3082a4fa489ca904e65967b7698ba363981992444277aca7c5ff6390e6b76974610549f491395209ccb2cf6ed31746c73033248884ef594f8bfec721cd6e5efb1ab76a4ba52a70d9c15d953bce2939d0bc634912addfb29f17fe8e439adb4a088e1baaf9cd0cae79aab320d5c44d1fe3d4c39226ffc0653e2ffe1c8735b5202374e42c561cd129b97d5e3809b094ec0a0584244fa381ca7c5ffd390e6b694046e9c858ac39a25372fabc70136129d8140b08489f470394f8bffa721cd6d20ca02c3d87baf5fc73ac1d70d684ea4e5c6a720d9140320829f17ff5e439ada31940587b0f75ebf8e7583ae1ad09d49cb8d4e41b2280641053e2ffebc8735b463280b0f61eebd7f1ceb075c35a13a93971a9c8364500c820a7c5ffd790e6b68c650161ec3dd7afe39d60eb86b4275272e353906c8a0190414f8bffaf21cd6d1856151c855211e27f0787ff055eaccce072e97cd61404c4839f17ff5f439ada2f383c91b77a8647b5dbd62602b3b7c1bb921555a9280b2d083e2ffebf8735b45d7079236ef50c8f6bb7ac4c05676f8377242aab5250165a107c5ffd7f0e6b68ba6d049f8ac07ba18f3c1ec002c53d2ee8f497b2a1a02e5821f8bffaff1cd6d173661b97c25759c5d64503a7fd80d885cc9571c140405e5444f17ff5ff39ada2e55849883185160e6456cd77f2f80f3393d725de7d80be4c8ae2ffebff735b45c93ca5690fe08e9f807a6117dde67c8f225a8e18f8017e3d16c5ffd7ffe6b68b91055d2acc977fc1b8c18857b3c357463f615e8ded02fe1e2e8bffb000cd6d17210aba55992eff83718310af6786ae8c7ec2bd1bda05fc3c5d17ff60019ada2e421574ab325dff06e306215ecf0d5d18fd857a37b40bf878ba2ffec00335b45c842ae95664bbfe0dc60c42bd9e1aba31fb0af46f6817f0f1745ffd80066b68b90855d2acc977fc1b8c18857b3c357463f615e8ded02fe1e2e8bffb000cd6d1721037b7b23fc65ab9cffdd11e706146efe6d814199d5fc569d27ff6001aada2e41f6f6f647f8cb5739ffba23ce0c28ddfcdb028333abf8ad3a4ffec00355b45c83e6af121abefcd69f7c40aa1b97b79e7960c92c2727f174b4affd8006bb68b907b61f49c04b5fd56a754db6b6aed51f726c567e0e1fe303a96ffb000d86d1720f54ffb90b6425d3006767cfecdd102164837121dc0fc62192eff6001b1da2e41e92c097a195b1ce2c4b9c025939862548b1a66977ef8c5d65efec00364b45c83d15812f432b639c58973804b2730c4a91634cd2efdf18bacbdfd8006c968b907a23c38411242d60dcab3c6be4657e77a2715dcb9f8e318fd7cfb000d93d1720f430482dad15c0e9e4d3453a484a62d1c48d7fbcfeec6339efaf6001b28a2e41e850905b5a2b81d3c9a68a749094c5a3891aff79fdd8c673df5ec00365145c83d0a120b6b45703a7934d14e921298b471235fef3fbb18ce7bebd8006ca28b907a142416d68ae074f269a29d24253168e246bfde7f76319cf7d7b000d9451720f428482dad15c0e9e4d3453a484a62d1c48d7fbcfeec6339efaf6001b28a2e41e8501c6db2d858364c5e573ab88cbc01b115abbc59d5c675835fc00365155c83d09f38db65b0b06c98bcae7571197803622b5778b3ab8ceb06bf8006ca2ab907a13e71b6cb6160d931795ceae232f006c456aef1675719d60d7f000d9455720f427c6f7fef6f9814e5aa869bec5dd66bb0a80a252aab33adbeff001b28abe41e84f76b12378c068c4e0cd9fe00b3a335894ac08cb153675d21ff00365158c83d09ed6236c7c4e37b1ed180c2295f3cc93a902d5bbea3cebbe7ff006ca2b2907a13d9507fe8369d58c05ace4a7ab66ff09d1b06f9d9449d7973ff00d9456620f427b12d12291a1114036d695b1d64d63f6230ba360e863af48bff01b28acd41e84f615a245234222806dad2b63ac9ac7ec461746c1d0c75e917fe0365159a83d09ec2405afd151ab2906d72329d8b4f5bb0bd951a9615ebd3d3fd06ca2b3607a13d830cc852d70bc7a392b12b630e95158975d6778828d7a94bfb0d94566d0f427b051990a5ae178f47256256c61d2a2b12ebacef1051af5297f61b28acda1e84f60a33214b5c2f1e8e4ac4ad8c3a545625d759de20a35ea52fec365159b43d09ec14664296b85e3d1c95895b1874a8ac4baeb3bc4146bd4a5fd86ca2b3687a13d8285897861d92dcbbe2df7c58e147b6bf5813bade8a7a9663b1d94566d1f427b04f3d4164e7fc1bfa7d8bbed9ba85cba6aad3b81911f52e6b64b28acda4e84f609d0695227cce9a77b2e443db6d01f5755053b28e20ea5e7aca65159b4ad09ec1390d2a44f99d34ef65c887b6da03eaeaa0a7651c41d4bcf594ca2b3695a13d82721a5489f33a69decb910f6db407d5d5414eca3883a979eb2994566d2b427b04e434a913e674d3bd97221edb680fabaa829d94710752f3d65328acda5684f609c8695227cce9a77b2e443db6d01f5755053b28e20ea5e7aca65159b4ad09ec13905eb6a846a9b1791455419598350cd2052294201a4bd0fd4da2b3695b13d8271f497fa93a29c574e0774953286077cc04f16a9c3197a39e9c4566d2b727b04e3d1f11ab2129ed6c78bb58ce48b74dc0048f1794602f48e1398acda56f4f609c793e23564253dad8f176b19c916e9b80091e2f28c05e91c273159b4ade9ec138f2085905317e18349aba29611ad395280ce8a0ad7dbd2528e72b3695be3d8271e310b20a62fc3069357452c235a72a5019d1415afb7a4a51ce566d2b7c7b04e3c6216414c5f860d26ae8a5846b4e54a033a282b5f6f494a39cacda56f8f609c78c42c8298bf0c1a4d5d14b08d69ca9406745056bede929473959b4adf1ec138f1811a2abc4b7e5cc636f5c39a52fb0a8c9364d33d8d2543273b3695be4d8271e2f234557896fcb98c6deb8734a5f6151926c9a67b1a4a864e766d2b7c9b04e3c5e468aaf12df97318dbd70e694bec2a324d934cf634950c9cecda56f93609c78bc1927b6d29590e5d347a7f52173e36e445eabfac392a3379e9b4adf27c138f177324f6da52b21cba68f4fea42e7c6dc88bd57f58725466f3d3695be4f8271e2ee649edb4a5643974d1e9fd485cf8db9117aafeb0e4a8cde7a6d2b7c9f04e3c5dc55500f4182e9b1520a05d10395799a1da1a23219951b60f5da56f93f09c78bb736b2772fdc35e55be0d1c9ff21515c35ef86c0302a3865ecb4adf27f138f176d6d64ee5fb86bcab7c1a393fe42a2b86bdf0d80605470cbd9695be4fe271e2eda66dc356c473a1827500d4ff47ba398d26a5d5cbda8e33bb3d2b7c9fd4e3c5db359cac38564d6b3066ce0c7e0eda5599f80fd157851c81b68a56f93fb9c78bb653fa7dfb7a00fe8c4a687b7b9d1a8db39ae3c86eda391dad24adf27f838f176c90b62181c1682544119d5976b99afde6e08bb69d8472559a595be4ff171e2ed9116c430382d04a88233ab2ed7335fbcdc1176d3b08e4ab34b2b7c9fe2e3c5db222d8860705a09510467565dae66bf79b822eda7611c95669656f93fc5c78bb6445b10c0e0b412a208ceacbb5ccd7ef37045db4ec2392acd2cadf27f8b8f176c884233da6e3e87c6c96a1f9eb1915c0edb37f8f98172573e5a5be4ff181e2ed90f107a0d895372104aa105655b191645b11c344effe4b020b5b7c9fe313c5db21d20f41b12a6e42095420acab6322c8b6238689dffc960416b6f93fc6278bb643a41e836254dc8412a8415956c645916c470d13bff92c082d6df27f8c4f176c8740fe2c4f771f3050cd4f152d0bf1055838de4d3fc2582a9aebe4ff18ae2ed90e71fc589eee3e60a19a9e2a5a17e20ab071bc9a7f84b05535d7c9fe315c5db21ce3f8b13ddc7cc143353c54b42fc41560e37934ff0960aa6baf93fc62b8bb6439c0b28806865faab1e7450be7deee0d4171b68fbde2c16f176f27f8c58176c8737165100d0cbf5563ce8a17cfbddc1a82e36d1f7bc582de2ede4ff18b02ed90e6e2ca201a197eaac79d142f9f7bb83505c6da3ef78b05bc5dbc9fe31605db21cdc594403432fd558f3a285f3ef7706a0b8db47def160b78bb793fc62c0bb6439b83e9a5f33360d349f11d20fd6e46b696c62d219dfc170bb7027f8c58276c8736f09471713427cebf5f06a47a5bf34fad371e68fbc82e31ae14ff18b05ed90e6dd128e2e2684f9d7ebe0d48f4b7e69f5a6e3cd1f7905c635c29fe3160bdb21cdba251c5c4d09f3afd7c1a91e96fcd3eb4dc79a3ef20b8c6b853fc62c17b6439b744a38b89a13e75faf83523d2df9a7d69b8f347de41718d70a7f8c582f6c8736e82083c9e0fe314216d36aa253e9add531caab57c52e335215ff18b05fd90e6dcf410793c1fc62842da6d544a7d35baa639556af8a5c66a42bfe3160bfb21cdb9e0e218030cf278b131a70b1479d157cc1d6efbb11b8ceec58fc62c1806439b73b1c4300619e4f162634e1628f3a2af983addf7623719dd8b1f8c58300c8736e76388600c33c9e2c4c69c2c51e7455f3075bbeec46e33bb163f18b060190e6dcec710c0186793c5898d3858a3ce8abe60eb77dd88dc67762c7e3160c0321cdb9d86e2a5bb9c8db33e973d13c71c7b5f4181b3e0d188cf06990c62c1807439b73af686710206818ea8ab468a0db85ca102ae2be762e19e277228c58300f8736e75d5ce078eda69457cd359769af01f2485071bf485933c6924618b060200e6dceb945d34a88238b325237f4fb55fa42b89b8fc0ecaf678ec88d3160c0411cdb9d7117b8edbd1d78e75c3cb01ea3eae39931cbc4355bcf1f351b62c1808339b73ae12f71db7a3af1ceb879603d47d5c7326397886ab79e3e6a36c5830106736e75c25ee3b6f475e39d70f2c07a8fab8e64c72f10d56f3c7cd46d8b06020ce6dceb8449d9c695c229bd99b2471d174d7af1890a6406db78fb4cdc160c041acdb9d7071fc5e5d85ab5fdeb3154622691540b0cc10a69b3f1f83db92c1808369b73ae0d3f8bcbb0b56bfbd662a8c44d22a816198214d367e3f07b725830106d36e75c1a0b29f00e413a7a649217b0923bae542db06c02ccc7e29ae5b06020db6dceb8331653e01c8274f4c9242f6124775ca85b60d805998fc535cb60c041b6db9d70662ca7c03904e9e992485ec248eeb950b6c1b00b331f8a6b96c180836db73ae0cc594f807209d3d32490bd8491dd72a16d836016663f14d72d830106db6e75c1983eb15990ea0a2900ee41311bb1436ad5b30288c97e2b525c06020db7dceb832f09750bceaa76d4b9a9488a2f58e4fda612476d8ffc5848b90c041b70b9d7065d12ea179d54eda9735291145eb1c9fb4c248edb1ff8b09172180836e173ae0cba25d42f3aa9db52e6a52228bd6393f698491db63ff16122e430106dc2e75c19744ba85e7553b6a5cd4a44517ac727ed30923b6c7fe2c245c86020db85ceb832e8236315977dcfce52614ecaed84ae025bd0b934fcc5862f91c041b70c9d7065cf46c62b2efb9f9ca4c29d95db095c04b7a17269f98b0c5f2380836e193ae0cb9e199eaf0acda1bc01520153ae09163169ef272ff0161a62480106dc3375c1973b333d5e159b437802a402a75c122c62d3de4e5fe02c34c490020db866eb832e76667abc2b3686f00548054eb82458c5a7bc9cbfc058698920041b70cdd7065cec5907d103437062c25cd0c5683f0fb34a257bdb7db0d4b6410836e19cae0cb9d73e21fab35d43483c8667b2c8747d8e8ef73a12f861ab1083106dc33a5c1973ad08564e1390e91330d9958d88df5945189ab681edc357c50720db8675b832e75910ac9c2721d22661b32b1b11beb28a31356d03db86af8a0e41b70ceb7065ceb22159384e43a44cc3665636237d6514626ada07b70d5f141c836e19d6e0cb9d6442b2709c87489986ccac6c46faca28c4d5b40f6e1abe283906dc33adc1973ac8117739e5e4f3b5c5661f0085ebf2798457aa7ad9357df4730db8675c832e758f22ee73cbc9e76b8acc3e010bd7e4f308af54f5b26afbe8e61b70ceb9065ceb1e45dce79793ced715987c0217afc9e6115ea9eb64d5f7d1cc36e19d720cb9d63c17cc27dbfe0030e2fdbe2c2755f1f41d699632c6abf147996dc33ae51973ac772f984fb7fc0061c5fb7c584eabe3e83ad32c658d57e28f32db8675ca32e758ee5f309f6ff800c38bf6f8b09d57c7d075a658cb1aafc51e65b70ceb9465ceb1dc4a73978cc66409cfbab78932a5edc8e5f8f3f2325f8be0cc6e19d729cb9d63b720f987c6632a965742353a5d4239b9c69e2a4061bf196599dc33ae54973ac76d41f30f8cc6552cae846a74ba8473738d3c5480c37e32cb33b8675ca92e758eda0ff877c6630cdc14d59b116cff450f1524eb5d83fc673a6870ceb9535ceb1db31ff0ef8cc619b829ab3622d9fe8a1e2a49d6bb07f8ce74d0e19d72a6b9d63b663fe1df198c337053566c45b3fd143c5493ad760ff19ce9a1c33ae54d73ac76cc0bd616dfeec9635e799eb35ff086a0a3d39d481ce33b77448675ca9be758ed9717ac2dbfdd92c6bcf33d66bfe10d4147a73a9039c676ee890ceb9537ceb1db2e2f585b7fbb258d79e67acd7fc21a828f4e7520738ceddd1219d72a6f9d63b65c5eb0b6ff764b1af3ccf59aff8435051e9cea40e719dbba2433ae54df3ac76cb84973c6abc2f8b89f66b15df6fec83237e616ddcb33b91849675ca9bf758ed96f1ef9e6045c53f3f69a28e3e5f3ee8c6a787017936773d493ceb9537feb1db2dd3df3cc08b8a7e7ed3451c7cbe7dd18d4f0e02f26cee7a9279d72a6ffd63b65ba07f9f0be47b252923569b78fc61859a48e02ba4a9dd0f6503ae54e00ac76cb730ff3e17c8f64a5246ad36f1f8c30b3491c0574953ba1eca075ca9c0158ed96e61fe7c2f91ec94a48d5a6de3f18616692380ae92a7743d940eb953802b1db2dcc3fcf85f23d929491ab4dbc7e30c2cd247015d254ee87b281d72a700563b65b980bb164915187abdb2361a0f457e3c2438c6e00a6dd110904ae54e00bc76cb72f1762c922a30f57b646c341e8afc7848718dc014dba2212095ca9c0178ed96e5e2ec59245461eaf6c8d8683d15f8f090e31b8029b74442412b953802f1db2dcbc5d8b248a8c3d5ed91b0d07a2bf1e121c63700536e888482572a7005e3b65b9784728a1c1eedd406a02e0373d749a4c337322666ad112344be54e00bd76cb72ef1a639c30b41d038bd2869672df92c061928728d2a2260c98ca9c017bed96e5dd34c73861683a0717a50d2ce5bf2580c3250e51a5444c1931953802f7db2dcbba698e70c2d0740e2f4a1a59cb7e4b01864a1ca34a889832632a7005efb65b97745f2f3a32774a9f1660fadb8ef2f42b07407ba292113208c754e00be06cb72ee74a70cd11c4f7c0e48ebbdf15dc467e092d39a1212265b58fa9c017c1d96e5dcd20f3f2d060520480ea3de623aeeb240d06b59e3f44cd0f2053802f84b2dcbb9941e7e5a0c0a40901d47bcc475dd6481a0d6b3c7e899a1e40a7005f0965b977320fe223ee57aa94bb75bdc086b20ab82ec718d4fa1335e0824e00be13cb72ee631fc447dcaf552976eb7b810d6415705d8e31a9f4266bc1049c017c2796e5dcc63f888fb95eaa52edd6f7021ac82ae0bb1c6353e84cd782093802f84f2dcbb98c0b23781f93b728937ab42c2d86b3e970e50903cd99b0a8137005f09f5b9773171646f03f276e5126f568585b0d67d2e1ca12079b33615026e00be13eb72ee62e2c8de07e4edca24dead0b0b61acfa5c394240f3666c2a04dc017c27d6e5dcc5c591bc0fc9db9449bd5a1616c359f4b8728481e6ccd85409b802f84fadcbb98b83e49daa611d50bef7808ead0619cbf08fcd298d69b0c2538005f09f6b977316f08a60df8fa0c9a96bcd7fd98b997a60ca5e78daa3619ee7100be13ee72ee62dd114c1bf1f419352d79affb31732f4c194bcf1b546c33dce2017c27dce5dcc5ba229837e3e8326a5af35ff662e65e9832979e36a8d867b9c402f84fb9cbb98b7445306fc7d064d4b5e6bfecc5ccbd30652f3c6d51b0cf738805f09f73977316e81673383c772c2c239a4601838fd888c50abb36a061a08b110be13ee82ee62dcf2ce67078ee585847348c03071fb1118a15766d40c341162217c27dd05dcc5b9e59cce0f1dcb0b08e6918060e3f6223142aecda8186822c442f84fba0bb98b73c3fac1a908fc3e3d49ef6341475226e23021c11000d05fc895f09f74277316e770b6a8dcdf5ea4a610ab29020e0a30440b07a7dfd1a0d9d13be13ee85ee62dced16d51b9bebd494c215652041c146088160f4fbfa341b3a277c27dd0bdcc5b9da2daa3737d7a929842aca4083828c1102c1e9f7f46836744ef84fba17b98b73b45b546e6faf525308559481070518220583d3efe8d06ce89df09f742f7316e76842bb358c350728c877ef2a06008e6c05b3ea3bcea0db753ce13ee85fe62dcecf1188c3c54070d448bca47c03f77b00061416d39a41b88e7ac27dd0c0cc5b9d9d2311878a80e1a8917948f807eef6000c282da73483711cf584fba18198b73b3a46230f1501c35122f291f00fddec0018505b4e6906e239eb09f74303316e7674185876d6d9e924fdb1ea0817b236282b4cf8f8cf0dc617d713ee860762dcece730b0edadb3d249fb63d4102f646c505699f1f19e1b8c2fae27dd0c0ec5b9d9ce6161db5b67a493f6c7a8205ec8d8a0ad33e3e33c37185f5c4fba181d8b73b39c4ed60f63a5abaaa55c1668b5880f6955140a22756e3262b99f74303c16e7673729be777421b9d80284f2f963067cfaa4d456a0e7dc6669743ee860792dcece6d537ceee84373b00509e5f2c60cf9f549a8ad41cfb8ccd2e87dd0c0f25b9d9cda330c367d5d49e2c1e0920d841052128dfd9cdf9c719b49d1fba181e5b73b39b366186cfaba93c583c1241b0820a4251bfb39bf38e33693a3f74303cb6e767366584332a24b8a0dbf4f0e5e0837a67232a2b5da6ec66ecb48ee860797dcece6cb3c98bdf16d769e366ae2e40865ab0c5ff1ae10da8cdf3a92dd0c0f30b9d9cd950543d48fb14fbf24a28bf008c1b440ba8f9e7db219c01926ba181e6273b39b290a87a91f629f7e494517e011836881751f3cfb643380324d74303cc4e7673652150f523ec53efc928a2fc02306d102ea3e79f6c86700649ae8607989cece6ca42a1ea47d8a7df925145f80460da205d47cf3ed90ce00c935d0c0f3139d9cd948543d48fb14fbf24a28bf008c1b440ba8f9e7db219c01926ba181e6273b39b290348ceaa3005a674c1e4429102ce63f4ca01212403804c8d84303cc4f7673651f6919d54600b4ce983c88522059cc7e9940242480700991b08607989eece6ca3e5e460338d7cc1fe845d6cc38a9f7252d2c8aa4fde014c7620c0f313ed9cd947b489e5f1e85fac2885873c0694a4c72550557a5f8c02b32c5181e627eb39b28f51d4f16e9e25807c87dada8ca8af70ca4b6f1a7ee8058098b303cc4fe673651e93a9e2dd3c4b00f90fb5b519515ee19496de34fdd00b01316607989fcce6ca3d2014eb4545fc2a1d9c37ccb22223a5a8d8808fbb70161ca2dc0f313fa9cd947a3029d68a8bf8543b386f996444474b51b1011f76e02c3945b81e627f539b28f46053ad1517f0a87670df32c8888e96a362023eedc058728b703cc4fea73651e8c0a75a2a2fe150ece1be6591111d2d46c4047ddb80b0e516e07989fd4e6ca3d1814eb4545fc2a1d9c37ccb22223a5a8d8808fbb70161ca2dc0f313fa9cd947a3029d68a8bf8543b386f996444474b51b1011f76e02c3945b81e627f539b28f46053ad1517f0a87670df32c8888e96a362023eedc058728b703cc4fea73651e8c0336c82dcb7b36f998b2bb909138b6ebeb0c0377db0e6bae17989fd4f6ca3d17f66d905b96f66df33165772122716dd7d61806efb61cd75c2f313fa9ed947a2fe59c4641fb530411df9750c1c448be2f56f4339f3c39c8f86e627f53eb28f45fb3f9b20ec40c304f3bfb040307f75ede58ac8cfe4873ac30ecc4fea7e651e8bf50b489a8557e88c9f4c26a858f54a03c5c1d3fbc60e772a1e989fd4fdca3d17e91691350aafd1193e984d50b1ea94078b83a7f78c1cee543d313fa9fb947a2fd22d226a155fa2327d309aa163d5280f17074fef1839dca87a627f53f728f45fa45a44d42abf4464fa613542c7aa501e2e0e9fde3073b950f4c4fea7ee51e8bf48409c010254eb4cac8f30ad874afe6456c982185de77445ea89fd4fdda3d17e8f0d4a5ab180391c10eb2783068c5af0a83f468cb8ceea2fd613fa9fbc47a2fd1d1a94b56300723821d64f060d18b5e1507e8d19719dd45fac27f53f788f45fa3a35296ac600e47043ac9e0c1a316bc2a0fd1a32e33ba8bf584fea7ef11e8bf4746a52d58c01c8e087593c183462d78541fa3465c677517eb09fd4fde23d17e8e860b803c4d9f443c67f3e5860bc0d327ea0ab2789eea4a1623fa9fbc57a2fd1cf4d8260368a4b0a44cb42d8b96e788cf7ed98ab10dd4ae6c57f53f78bf45fa39d27171919eaf89741634bd96ad34f41ea8773b21eba97718bfea7ef18e8bf47394e2e3233d5f12e82c697b2d5a69e83d50ee7643d752ee317fd4fde31d17e8e72286ebd148244dfbd59f58da3439b2fa4ca112477ea5f6a30fa9fbc64a2fd1ce350dd7a290489bf7ab3eb1b4687365f49942248efd4bed461f53f78c945fa39c62dcd4cfedf7601ad349c5e8504cae68dd486eddca97f4cc4ea7ef1938bf4738b5b9a99fdbeec035a6938bd0a0995cd1ba90ddbb952fe9989d4fde32717e8e71643478ca8543a896c9f37a20c0989c231fe5e136fa5fed714a9fbc64f2fd1ce2b12a171fd7ed795910b356c100971ac5ea8fe82dc4bff522a53f78c9f5fa39c552542e3fafdaf2b22166ad82012e358bd51fd05b897fea454a7ef193ebf4738aa4a85c7f5fb5e56442cd5b04025c6b17aa3fa0b712ffd48a94fde327d7e8e7154211de898cd1f2f402671887841eb8aeff43672df5ffc35539fbc64fbfd1ce2a7423bd1319a3e5e804ce310f083d715dfe86ce5bebff86aa73f78c9f7fa39c54e1089fb100adf3fb8668c49d8fe0c53ba7d1c277a7ff2794f7ef193f0f4738a9b2113f62015be7f70cd1893b1fc18a774fa384ef4ffe4f29efde327e1e8e715364227ec402b7cfee19a312763f8314ee9f4709de9ffc9e53dfbc64fc3d1ce2a6c1062312d2d5c807b012876bfe6c0c5ce952397d0ff956e7cf78c9f88a39c54d720c4625a5ab900f60250ed7fcd818b9d2a472fa1ff2adcf9ef193f114738a9ae4188c4b4b57201ec04a1daff9b03173a548e5f43fe55b9f3de327e228e71535c0f23e2164146868fd609ddf72c64566f555f1a84fcad17e8bc64fc461ce2a6b71e47c42c828d0d1fac13bbee58c8acdeaabe3509f95a2fd178c9f88c39c54d6e3c8f8859051a1a3f582777dcb19159bd557c6a13f2b45fa2f193f118738a9adc0531695ee096b7367d1517b15980db75573b3024e56a6346e327e231e71535b70a62d2bdc12d6e6cfa2a2f62b301b6eaae766049cad4c68dc64fc463ce2a6b6e14c5a57b825adcd9f4545ec566036dd55cecc09395a98d1b8c9f88c79c54d6dc298b4af704b5b9b3e8a8bd8acc06dbaab9d981272b531a37193f118f38a9adb8531695ee096b7367d1517b15980db75573b3024e56a6346e327e231e71535b70323f8488e93969876f691e23267996a593a86099ad4e0cdd64fc463de2a6b6df647f0911d272d30eded23c464cf32d4b2750c1335a9c19bac9f88c7bc54d6dbe55106ad07b4828d58a6aa08490448290fae3de63b539d77693f118f88a9adb7b36332e4dccf2d462e19b690116e72d1ca20a18c46a7552ee27e231f21535b6f56c665c9b99e5a8c5c336d2022dce5a3944143188d4eaa5dc4fc463e42a6b6dea64df11e40a2dd4435333cbfc51fadc6d346abf0ea9d6efb99f88c7c954d6dbd355d07c74eabe2b3e732dbff09a53e0d51517da1a53af83743f118f93a9adb7a537b35196abded934b321a7d92b05e9a4d6721031a760aae97e231f28535b6f496f66a32d57bdb26966434fb2560bd349ace420634ec155d2fc463e50a6b6de926adf9f0785dde78a994cc75ca275ce8e060a9cc39d844fa6f88c7ca24d6dbd2361d196bbe21e51ccff5fb6b13b49c516b85795843b0a434ef118f9459adb7a454fb586249a9f2651cb85955a6cf1b2281cf1870576162a9ee231f28c35b6f4892b7d64f60ba0cf5b63d152acd0418c4ae6256a07ec2df93ec463e5196b6de91156fac9ec17419eb6c7a2a559a0831895cc4ad40fd85bf27d88c7ca32d6dbd2223a07ec8504e5c0255c0b72ab3764592644d8041cb0b988fc118f9466adb7a443002231b6e02e030284dd0d4e6526da4735f264366174b5f9231f28ce5b6f48850044636dc05c060509ba1a9cca4db48e6be4c86cc2e96bf2463e519cb6de910a0088c6db80b80c0a13743539949b691cd7c990d985d2d7e48c7ca3396dbd221401118db70170181426e86a732936d239af9321b30ba5afc918f94672db7a442802231b6e02e030284dd0d4e6526da4735f264366174b5f9231f28ce5b6f48850044636dc05c060509ba1a9cca4db48e6be4c86cc2e96bf2463e519cb6de910a0088c6db80b80c0a13743539949b691cd7c990d985d2d7e48c7ca3396dbd221401118db70170181426e86a732936d239af9321b30ba5afc918f94672db7a442802231b6e02e030284dd0d4e6526da4735f264366174b5f9231f28ce5b6f48850044636dc05c060509ba1a9cca4db48e6be4c86cc2e96bf2463e519cb6de910a0014d9342d8e6e8ccb40fb618c91c744d275d33582d2d9888d7ca3396ebd2213ff29b2685b1cdd199681f6c319238e89a4eba66b05a5b3111af94672dd7a4427fe5364d0b639ba332d03ed8632471d1349d74cd60b4b662235f28ce5baf4884ffc32dbfa1949d6e911d4a1345c84984e8e5adc081396cde86ce519cb76e9109ff765b7f43293add223a94268b909309d1cb5b810272d9bd0d9ca3396edd2213fee57824111fdbe26ff1f4af96a08bf623417b27c4b5b3945b494672ddca4427fdb3b16dad0d1ded0b60b5c1acc07dcec62dba75493b6742f6a28ce5bba4884ffb502400e4e7a202423e37e5d90061800c0639105246cea02d5519cb7759109ff6904801c9cf4404847c6fcbb200c300180c7220a48d9d405aaa3396eeb2213fed209003939e880908f8df97640186003018e441491b3a80b554672ddd64427fda412007273d101211f1bf2ec8030c006031c882923675016aa8ce5bbac884ffb482400e4e7a202423e37e5d90061800c0639105246cea02d5519cb7759109ff6904801c9cf4404847c6fcbb200c300180c7220a48d9d405aaa3396eeb2213fed201c15ec4b5e6b8bb0ac5d8bf97c5e58139083a5183a825955672ddd65427fda3f382bd896bcd7176158bb17f2f8bcb02721074a307504b2aace5bbaca84ffb47e7057b12d79ae2ec2b1762fe5f179604e420e9460ea0965559cb7759509ff68fc6cc1bb07c9bee03d2fb287c3d950e897305f84bed4146eac396eeb2b13fed1f76595cebc69e043322c2b377fa8fff9290d01657aa82a815972ddd65727fda3ed573df625aa23091c251c96f7485e1a4cc64526f25056a6b3e5bbacaf4ffb47d93a8e44f82aa894f016ff55e6871a5c9438cca9e1a0aef168cb77595f9ff68fb1012ee29d2bb3ac97fac4d3c50492e1231ddbafc0415f86d296eeb2c03fed1f61025dc53a5767592ff589a78a0925c2463bb75f8082bf0da52ddd65807fda3ec204bb8a74aeceb25feb134f14124b848c776ebf01057e1b4a5bbacb00ffb47d84097714e95d9d64bfd6269e2824970918eedd7e020afc3694b7759601ff68fb0812ee29d2bb3ac97fac4d3c50492e1231ddbafc0415f86d296eeb2c03fed1f61025dc53a5767592ff589a78a0925c2463bb75f8082bf0da52ddd65807fda3ec204bb8a74aeceb25feb134f14124b848c776ebf01057e1b4a5bbacb00ffb47d8402383a742b038ceb52f300a7a3fceb9899a1a3c1dafc50d4c77596020f68fb07f47074e8560719d6a5e6014f47f9d73133434783b5f8a1a98eeb2c041ed1f60fe1a20f5b79745bd8c898651e0f5990e2114ab4c73bf15d932dd658084da3ec1fb3441eb6f2e8b7b19130ca3c1eb321c42295698e77e2bb265bacb0109b47d83f66883d6de5d16f63226194783d664388452ad31cefc5764cb7596021368fb07ec5d1a066990906f1c18f8b6ffa3269903519cbf9af8b06d97eb2c0427d1f60fd74646657ff78360effeb795f73cab5a014f7bdb32f1627f30d6580850a3ec1fad189f23acc5694497ca3553e66fb4dbfd4b3a1262e2c6a262acb010a247d83f59313e47598ad2892f946aa7ccdf69b7fa967424c5c58d44c5596021448fb07eb2627c8eb315a5125f28d54f99bed36ff52ce8498b8b1a898ab2c042891f60fd64510b761301aca7761e70c72b740507e50612ef141636b716658085133ec1fac72e2944d2d9bbd1a409a7b64ede6837c4b8683a252c6f122dcb010a277d83f58d5c5289a5b377a348134f6c9dbcd06f8970d0744a58de245b9602144efb07eb1a44b76bf83d51c947f36501336fff070d8de34491b1bdecb82c04289ef60fd6331581309d51061547b3902a5ed65c3615c808e520637d7d715808513eec1fac652b02613aa20c2a8f672054bdacb86c2b9011ca40c6fafae2b010a27dd83f58ca5604c2754418551ece40a97b5970d857202394818df5f5c5602144fbb07eb194381bdd975e932cf569477aeea93fd8a8ec8985001bed8f8bc04289f860fd63277037bb2ebd2659ead28ef5dd527fb151d9130a0037db1f17808513f0c1fac64e6c81cf0a50af368d71e413b29b5d8a9e5e686ffd6fb7e230010a27e283f58c9b6515f6c177c0efd2b08e4f5d2d193d3769133bf7df71686102144fc607eb1935563e462fc5e4625d2de2c6b25090a2697e68d3ecbee474c304289f8d0fd63269388ee50c622b4772288bb55c977f6ccda91403d67dca8d8708513f1b1fac64d1711dca18c4568ee451176ab92efed99b522807acfb951b0e10a27e363f58c9a26e4decde5f0fa0806ef4fd6a545bdb3150926b56f72bda1d2144fc6d7eb1934368ae32699481c3b8aab022cc9f15de5d4d6732aaee59583b4289f8dbfd6326855d6ebd7fff660a2922266d913489e4b54710c152dcb454778513f1b8fac64d0946efd3acd52e970a1113031a5f71f1653a63dea2b96a4cf00a27e372f58c9a1119f2000680bfb0cbeeec2e2cb5420ac5210a194272d63de1144fc6e6eb19342133e4000d017f6197ddd85c596a84158a42143284e5ac7bc2289f8dcdd632684267c8001a02fec32fbbb0b8b2d5082b1484286509cb58f784513f1b9bac64d0845ba258e0dc6009174427995da06e7e23b493261096b39309a27e373858c9a10743570a6e8f2294e655155ab3373b24421568a81e2d68ca1444fc6e71b193420d12c06d89f4a7ac8476f0dd5e64d4707ed713ac395ad3382989f8dce4632684192580db13e94f5908ede1babcc9a8e0fdae275872b5a6705313f1b9c8c64d08324b01b627d29eb211dbc375799351c1fb5c4eb0e56b4ce0a627e373918c9a10642215c4fc7b9fe6db844d12eb1d01abf164dfbdc7d69b654d4fc6e724193420c7442b89f8f73fcdb7089a25d63a0357e2c9bf7b8fad36ca9a9f8dce483268418e14696c9ec4e21e25ddfa73a46a64d7c03fc1531c5a6f39363f1b9c9164d0831b28d2d93d89c43c4bbbf4e748d4c9af807f82a638b4de726c7e373922c9a1063651a5b27b1388789777e9ce91a9935f00ff054c7169bce4d8fc6e724593420c6c2f5dbda2fd7373e6bc99c51b4984e5fcaa4cf4dfd37b6db2f8dce48c268418d75ebb7b45fae6e7cd79338a369309cbf95499e9bfa6f6db65f1b9c9184d0831ae49894f38cc305252bf2d3c651c71bfed55762f7c4def5acce37392319a10635b1f24f71e6ec3275d4b20a0c22f41a7d5572ebaf59be0599ac6e724643420c6b53e49ee3cdd864eba964141845e834faaae5d75eb37c0b3358dce48c868418d6a08a63526916f202cf948ab00b364c75008fd47d36f830a6c1b9c9191d0831ad3114c6a4d22de4059f291560166c98ea011fa8fa6df0614d837392323a10635a62298d49a45bc80b3e522ac02cd931d4023f51f4dbe0c29b06e724647420c6b4c4531a9348b790167ca4558059b263a8047ea3e9b7c185360dce48c8e8418d6981675ab15ed5485876150d8032caa9cfb3c16d933f8324ac2b9c9191e0831ad2f2ceb562bdaa90b0ec2a1b006595539f6782db267f06495857392323c10635a5e59d6ac57b552161d8543600cb2aa73ecf05b64cfe0c92b0ae724647820c6b4bc3fbfb15c4106aef2d74ce8115bb30fd48cf9259cc193fa16ce48c8f1418d69770b91bb65586fe09d7b5ff81aadc447a3c634a7368329982e9c9191e3831ad2ed172376cab0dfc13af6bff0355b888f478c694e6d0653305d392323c70635a5da2e46ed9561bf8275ed7fe06ab7111e8f18d29cda0ca660ba7246478e0c6b4bb45c8ddb2ac37f04ebdaffc0d56e223d1e31a539b4194cc174e48c8f1c18d69768452e0f025d608c8f82c5a9a2d2a2a2370f8ccf65329b26eac9191e3931ad2ecf166e76b191239bd6d2517b3d9ba36c68cb5bfac76537f1d692323c73635a5d9d2cdced63224737ada4a2f67b3746d8d196b7f58eca6fe3ad246478e6c6b4bb3a59b9dac6448e6f5b4945ecf66e8db1a32d6feb1d94dfc75a48c8f1cd8d6976743f860e395f7f616e5f5201e4d3798b410722323829c132b59191e39c1ad2ece70b1e751f956145948b6a2bc19d513e7cba86c06d5384096c2323c73935a5d9cd163cea3f2ac28b2916d457833aa27cf9750d80daa70812d846478e726b4bb39a2c79d47e558516522da8af067544f9f2ea1b01b54e1025b08c8f1ce4d697673458f3a8fcab0a2ca45b515e0cea89f3e5d436036a9c204b61191e39c9ad2ece683df9aaa62c76dc008368e411cb720fc654ae62d238423ac3323c73945a5d9ccf0805adf92f503ab8d397f01b8d424787559f21a1708619876478e729b4bb399d100b5bf25ea07571a72fe0371a848f0eab3e4342e10c330ec8f1ce536976733a2016b7e4bd40eae34e5fc06e35091e1d567c8685c218661d91e39ca6d2ece674402d6fc97a81d5c69cbf80dc6a123c3aacf90d0b8430cc3b23c7394da5d9cce80c6d383fcb662e45064529b0ca82a0700634761408633c77478e729c4bb399cf18da707f96cc5c8a0c8a5361950540e00c68ec2810c678ee8f1ce5389767339e31b4e0ff2d98b9141914a6c32a0a81c018d1d850218cf1dd1e39ca712ece673c6369c1fe5b31722832294d865415038031a3b0a04319e3ba3c7394e25d9cce7852e5dca98cc567083118c3049e882efb0f89bd3d86356b7578e729c5bb399cef31de11ffefed50c82ef7ae01336e85f0cb55d6780c6c7aebf1ce538c767339dd63bc23ffdfdaa1905def5c0266dd0be196abacf018d8f5d7e39ca718ece673ba538aa0ac9617c5d888a4dffcc4183fbdd999b5dd31b38fb0c7394e32d9cce77333279a0602920e68de0fe7f17e8ea7765f75c7b76368c3628e729c66b399cee5664f340c05241cd1bc1fcfe2fd1d4eecbeeb8f6ec6d186c51ce538cd67339dca58b0c0c4e0aabc5b4505c7bdf098c5d42a197ada8da4b18b39ca719bce673b933d73da3697b7fb6e56d1b773d78fb3a3007551b21b4b07177394e3389cce772506fa0d1a05d279947a6996dfa57d8f40ad2cff613697b22fe729c672399cee490df41a340ba4f328f4d32dbf4afb1e815a59fec26d2f645fce538ce47339dc921be834681749e651e9a65b7e95f63d02b4b3fd84da5ec8bf9ca719c8e673b92437d068d02e93cca3d34cb6fd2bec7a056967fb09b4bd917f394e3391cce772486fa0d1a05d279947a6996dfa57d8f40ad2cff613697b22fe729c672399cee4906b53fbed90b1b54719f903eca610101051e24823d2f7e9fde538ce48339dc91f62ba5087f7c5ed4600b82fd1427e481b5006ec44a5f177fcca719c91673b923d5186f9bcc5ee5d43ce36879a7b5ab8314c5034864be493fa94e33923ce7724792f204c26623f3d3f6933372ced13985d44e2c50997cacbf629c672489cee48f15e40984cc47e7a7ed2666e59da2730ba89c58a132f9597ec538ce49139dc91e2489389465f5f77b5719304abaaac896fbfcd70235f2cd3d9a719c92373b923c31d396b3995217222afec314f4bb73ada2bdd3c43be5b4bb44e339247e77247853a72d6732a42e4455fd8629e976e75b457ba78877cb697689c67248fcee48f0a00f805932ae84b428c76ed35253b13635bb74d0bf96ed2d238ce49209dc91e1301f00b2655d0968518edda6a4a7626c6b76e9a17f2dda5a4719c92413b923c2603e0164caba12d0a31dbb4d494ec4d8d6edd342fe5bb4b48e33924827724784c07c02c9957425a1463b769a929d89b1addba685fcb769691c6724904ee48f0980f805932ae84b428c76ed35253b13635bb74d0bf96ed2d238ce49209dc91e1301f00b2655d0968518edda6a4a7626c6b76e9a17f2dda5a4719c92413b923c2603e0164caba12d0a31dbb4d494ec4d8d6edd342fe5bb4b48e33924827724784c0081522424a8823fe083cc28a93e7d9a887e8e1f9b76b0d1d6724904fe48f097f102a4484951047fc1079851527cfb3510fd1c3f36ed61a3ace49209fc91e12fe205489092a208ff820f30a2a4f9f66a21fa387e6ddac34759c92413f923c25fc40a9121254411ff041e614549f3ecd443f470fcdbb5868eb3924827f24784bf80d647cd17ee4c298509250a134dbc2832ad07b9876b275d7724904ff48f097ef1ac8f9a2fdc98530a124a14269b7850655a0f730ed64ebaee49209fe91e12fde3591f345fb930a6142494284d36f0a0cab41ee61dac9d75dc92413fd23c25fbc6b23e68bf72614c284928509a6de14195683dcc3b593aebb924827fa4784bf78625a25c4c4aeac3cd5eb320b441a502d594a15846b29017824904ff58f097eef50c6a4365fbfdb31789c8c0e7e92c8555ed68705d653a6f149209fec1e12fddd2d9fa11995e2391abdff4014f383b8a569ef6a08aca8f1e392413fd93c25fbb95b3f42332bc472357bfe8029e707714ad3ded4115951e3c724827fb2784bf7724290dd132deb6722c4c3284bc46d0a905400041fb2a56b8f4904ff65f097eee3113412d3323950fd564c788f7f383d1b5442643c654c7b1f9209fecce12fddc5226825a66472a1faac98f11efe707a36a884c878ca98f63f2413fd99c25fbb8a44d04b4cc8e543f55931e23dfce0f46d510990f19531ec7e4827fb3384bf771415b2ef46682d0aa27f29ec73f02010d54e557de02a657cfd904ff668097eee272b65de8cd05a1544fe53d8e7e04021aa9caafbc054caf9fb209fecd012fddc4e56cbbd19a0b42a89fca7b1cfc08043553955f780a995f3f6413fd9a025fbb89c39a9d2e017cad7cbc6158b97775eaea51eee4afe532d8bed827fb3414bf771377353a5c02f95af978c2b172eeebd5d4a3ddc95fca65b17db04ff668297eee26e72b9a42d358de1e6e51c5655d3d8e28f27fb87f64cb7d3b709fecd062fddc4db7185a107417e468596fed4a39e0fed18fc396be999714b6f13fd9a0d5fbb89b56f1d9abb595f0fc2fac3d13f327e022ca4b533d032e43adf27fb341bbf7713696a4d8e238920a23dc24dca765b5a2c53f5acc39d65ca19bf4ff668387eee26d160ad74f3e8a3c7335161bce4ad1280a2979be337cb95d77f9fecd071fddc4da14d6d4294a7aa111e6f89a1c15083293fdb7a226c972d53003fd9a0e4fbb89b4126ecddd625b6a4f4abd96b7a97647a7a6336a0d62e5c4a017fb341caf77136814dd9bbac4b6d49e957b2d6f52ec8f4f4c66d41ac5cb89402ff668395eee26d0227c5d0056d3d168a7c2bd5e253f011e4391cdf55b972cc06fecd072cddc4da034f8ba00ada7a2d14f857abc4a7e023c87239beab72e5980dfd9a0e59bb89b4062b2998c28b56dce1bd757f81461e6f8b90b5d953e5ccd41cfb341cb47713680b5653318516adb9c37aeaff028c3cdf17216bb2a7cb99a839f6683968ee26d01638b8bbb703bdf63ec29c25fd0ed7e628ef19c14c9734f474ecd072d2dc4da02b7171776e077bec7d85384bfa1dafcc51de3382992e69e8e9d9a0e5a5b89b40566ef54788e55a5bb2d736bfec31bdc09e68a9612f5cd575d4b341cb4c713680ab69fce7bea1173a1d7b33a7d059d9a9377d951e5bb9ac8faa66839699e26d0155600c282a1890f6f2c32d7798aa117a69a76c98b4735ac355cd072d34c4da02a94c2aa9010784709d532117294a811ccdfb1b8d65e6b72aac9a0e5a6a89b405512467aaaee56b63f27308564a8b606196a27976c8cd6ff95a341cb4d613680aa148cf555dcad6c7e4e610ac9516c0c32d44f2ed919adff2b4683969ac26d015421db103686c10128198e7812223dfae553628372035c18969d072d3594da02a833b6206d0d820250331cf024447bf5caa6c506e406b8312d3a0e5a6b29b40550602d6664e86a2ccbe30642c8085dce14f84e3387dd707c9a841cb4d663680aa0b05accc9d0d45997c60c859010bb9c29f09c670fbae0f935083969acc6d0154160b59993a1a8b32f8c190b2021773853e138ce1f75c1f26a1072d3598da02a82c16b33274351665f1832164042ee70a7c2719c3eeb83e4d420e5a6b31b40550582d6664e86a2ccbe30642c8085dce14f84e3387dd707c9a841cb4d663680aa0b05accc9d0d45997c60c859010bb9c29f09c670fbae0f935083969acc6d015416041abec4e7f15b243e5d148196d967bdbe5107b72c1f40e1172d3598ea02a82bf0f6a3149d48de73f9868b82ad18b1fb2766352e283e9c023e5a6b31e4055057d1ed46293a91bce7f30d17055a3163f64ecc6a5c507d38047cb4d663c80aa0afa3da8c52752379cfe61a2e0ab462c7ec9d98d4b8a0fa7008f969acc79015415f40763e2fb7ad1bcb4900be94e82b7258e5f5cf3111f4fa5202d3598f302a82be70ec7c5f6f5a379692017d29d056e4b1cbeb9e6223e9f4a405a6b31e6055057ce1d8f8bedeb46f2d2402fa53a0adc96397d73cc447d3e9480b4d663cc0aa0af9c3b1f17dbd68de5a4805f4a7415b92c72fae79888fa7d290169acc79815415f3802508864837e4e00cd84bce021d080e0a2118d0ef4fbf603d3598f312a82be6f04a110c906fc9c019b0979c043a101c144231a1de9f7ec07a6b31e6255057cde094221920df938033612f380874203828846343bd3efd80f4d663cc4aa0af9bc128443241bf270066c25e7010e840705108c6877a7dfb01e9acc79895415f3782508864837e4e00cd84bce021d080e0a2118d0ef4fbf603d3598f312a82be6f04a110c906fc9c019b0979c043a101c144231a1de9f7ec07a6b31e6255057cde0203471cdb5f602eb2df560006a7e602330a59fba3eff24f5d663cc4ba0af9bbf4068e39b6bec05d65beac000d4fcc046614b3f747dfe49ebacc79897415f377e0ce41fe3ae3a8e64849ba7f9a057a8876ed8dae5fbfe37d8598f312f82be6efb19c83fc75c751cc909374ff340af510eddb1b5cbf7fc6fb0b31e625f057cddf633907f8eb8ea3992126e9fe6815ea21dbb636b97eff8df61663cc4be0af9bbec6720ff1d71d4732424dd3fcd02bd443b76c6d72fdff1bec2cc79897c15f377d85a5456e7ba0b69001680a791fbd8b07199d00a5cbfe5218698f312f92be6efaf40bb067c4a7954b7f9c7771bee0f88dddfe270b67fcbe70e31e625f357cddf5d0d8865a56b552c27c055162fd27d39b66c073d69ff99721d63cc4be7af9bbeb91b10cb4ad6aa584f80aa2c5fa4fa736cd80e7ad3ff32e43ac79897cf5f377d7236219695ad54b09f015458bf49f4e6d9b01cf5a7fe65c8758f312f9ebe6efae46c432d2b5aa9613e02a8b17e93e9cdb36039eb4ffccb90eb1e625f3d7cddf5c86498b3038bb54533d2178af51e31c3616cb6329cf998c5d73cc4be7bf9bbeb8f5543beb3edcd0d1f70f53de232c1aebd85aec136f3332faf79897cf8f377d71d3699d614b1fc9cf6aeb0a3bc5be18575b79fde6ae668035ff312f9f2e6efae396d33ac2963f939ed5d614778b7c30aeb6f3fbcd5ccd006bfe625f3e5cddf5c726679b0ff9e54f6928788b6e965e43dd18ac1d5a899a1b180cc4be7cc9bbeb8e35905baac130c6fdcdbd795cac226a39dc1c6074e334507029897cf9a377d71c53e1dce04fc7b62718475538d7aab6f362fce6a99668bb206312f9f356efae389084df4b6cf59479ad5b0cf12ebb506670bdf312fcd19080d625f3e6bddf5c711109be96d9eb28f35ab619e25d76a0cce17be625f9a32101ac4be7cd7bbeb8e222137d2db3d651e6b56c33c4baed4199c2f7cc4bf34642035897cf9af77d71c44426fa5b67aca3cd6ad8678975da833385ef9897e68c8406b12f9f35eefae388810f1a419cbf6fc6527d31926b1ae8e6b6a356ef9d19224d725f3e6bedf5c710f21e3483397edf8ca4fa6324d635d1cd6d46addf3a32449ae4be7cd7dbeb8e21e43c690672fdbf1949f4c649ac6ba39ada8d5bbe74648935c97cf9afb7d71c43c139f797b361a65e10b5ef12d83d29b55fdedd3cb8c92caba2f9f35f7fae38877273ef2f66c34cbc216bde25b07a536abfbdba797192595745f3e6beff5c710ee4e7de5ecd86997842d7bc4b60f4a6d57f7b74f2e324b2ae8be7cd7dfeb8e21dc290e24868735b1c027bdb16414f302aa9bb0fa596497f9d27cf9afc0d71c43b7521c490d0e6b63804f7b62c829e605553761f4b2c92ff3a4f9f35f81ae38876e304aeac6f33949b86bbced884a2a32a51b06456292618b4af3e6bf045c710edb6095d58de6729370d779db109454654a360c8ac524c31695e7cd7e08b8e21db64d3e03c8a347a9997bb9de191f06f28f185b71874987d12ccf9afc1271c43b6b268e603e1cf1d5eac439e42a346c0d18dcf93f0b9311465a9f35f825e38876d54d1cc07c39e3abd58873c85468d81a31b9f27e1726228cb53e6bf04bc710edaa264bd9a54a29da62ddadb8a0c80e5c5e2027582b4c46bd6b7cd7e0988e21db534c97b34a9453b4c5bb5b7141901cb8bc404eb056988d7ad6f9afc1311c43b6a62541bf41ff09ec43437d0a7b169799732cdfbcaa311c99aef35f826338876d4b4a837e83fe13d88686fa14f62d2f32e659bf79546239335de6bf04c6710eda96211955b4d28a33c4daba51e450bc8dc75fc14ea5c4740abccd7e098de21db52b4232ab69a5146789b574a3c8a1791b8ebf829d4b88e815799afc131bc43b6a561077af80208b51cb37af6f8939505f182b47969411d1cef435f826388876d4ab20ef5f004116a3966f5edf1272a0be30568f2d2823a39de86bf04c7110eda95641debe00822d472cdebdbe24e5417c60ad1e5a5047473bd0d7e098e221db52ac0fcfd4addabd11118a41a441c0e120bc067f109d8e901ba2afc131c543b6a5571f9fa95bb57a22231483488381c241780cfe213b1d2037455f82638a876d4aae3f3f52b76af4444629069107038482f019fc42763a406e8abf04c7150eda955c0a90fe1bac4b0b441ed34a05fd672ddae03ae0e9748281167e098e2b1db52ab71521fc37589616883da6940bface5bb5c075c1d2e905022cfc131c563b6a556e2a43f86eb12c2d107b4d2817f59cb76b80eb83a5d20a0459f82638ac76d4aadc5487f0dd62585a20f69a502feb396ed701d7074ba41408b3f04c7158eda955b835223a679b1336f9b9fac857ccd105a8aff06a944829b568e098e2b2db52ab6f6a4474cf36266df373f590af99a20b515fe0d52890536ad1c131c565b6a556de609b424b42af5e9eb4b1495729a23e9d6c04064e20a879a482638acc6d4aadbb4d48dd435bc13ff53628baa649a2a535844a68994152974a04c71599da955b7526a413338de502a239179d4489a37265b4d72d2f82a6d295098e2b34b52ab6e94d4826671bca0544722f3a891346e4cb69ae5a5f054da52a131c56696a556dd226a2a57b0df68d40b1249d0a1cebf1917f9f10bb0a9cee552638acd3d4aadba34d454af61bed1a8162493a1439d7e322ff3e21761539dcaa4c7159a7a955b746269cee990e3cb7ba91589c206a0dee40aabe9ee92a755d5598e2b35052ab6e8b4d39dd321c796f7522b13840d41bdc81557d3dd254eabaab31c566a0a556dd16268613110f5561a2122898799e95e0fd573cd7a1a9d71957638acd424aadba2b4d0c26221eaac344245130f33d2bc1faae79af4353ae32aec7159a84955b7456262aa4f113b80940156889de70b5abf00935ba83a75e095e8e2b350a2ab6e8ab4c5549e2277012802ad113bce16b57e0126b75074ebc12bd1c566a14556dd15624bcec712542a7b822684f71b934d7bad119460b9d79c97b38acd429aadba2ab4979d8e24a854f7044d09ee37269af75a2328c173af392f67159a85355b745561f060a716b6d2198566765bedb3186e5f0a7742b75e8c9ede2b350a7ab6e8aab3e0c14e2d6da4330accecb7db6630dcbe14ee856ebd193dbc566a14f56dd1556082a8272841709192663bef3632443926ee02caad7a4cbb88acd429fadba2aab105504e5082e12324cc77de6c6488724ddc05955af499771159a853f5b74555620aa09ca105c2464998efbcd8c910e49bb80b2ab5e932ee22b350a7eb6e8aaac4154139420b848c9331df79b19221c9377016556bd265dc4566a14fd6dd155580eba7fd517d3144a3302172e28a261219a4526aa7a4e5f89acd429fbdba2aaaf1d74ffaa2fa6289466042e5c5144c243348a4d54f49cbf1359a853f7b745555e3ae9ff545f4c5128cc085cb8a289848669149aa9e9397e26b350a7ef6e8aaabc01e6575594fb250964d6e1693b7131077e6b9150d274a04e66a14fdfdd15557703ccaeab29f64a12c9adc2d276e2620efcd722a1a4e9409ccd429fbfba2aaaee07995d5653ec9425935b85a4edc4c41df9ae454349d281399a853f7f745555dc0f32baaca7d9284b26b70b49db89883bf35c8a8693a50273350a7efee8aaabb81e6575594fb250964d6e1693b7131077e6b9150d274a04e66a14fdfdd15557703ccaeab29f64a12c9adc2d276e2620efcd722a1a4e9409ccd429fbfba2aaaee005a82e12152bc511027e8246d2aa69da4726b0319d29b79aa853f7f845555dbf0b505c242a578a2204fd048da554d3b48e4d60633a536f3550a7eff08aaabb7e16a0b84854af144409fa091b4aa9a7691c9ac0c674a6de6aa14fdfe1155576fc2d417090a95e288813f4123695534ed23935818ce94dbcd5429fbfc22aaaedf85a82e12152bc511027e8246d2aa69da4726b0319d29b79aa853f7f845555dbf041181aef7bdb24d81c9670d24bab634391186230a53897560a7eff09aaabb7df0e428e8bce18cc6805f3099c8db4ee81ce73205e4a72d2ad14fdfe1455576fbd1c851d179c3198d00be613391b69dd039ce640bc94e5a55a29fbfc28aaaedf7a390a3a2f386331a017cc267236d3ba0739cc817929cb4ab453f7f851555dbef47214745e70c663402f984ce46da7740e739902f253969568a7eff0a2aabb7de8703b4169b7ef49382bf6c1c0d1ad1017937461e1a72eced24fdfe1465576fbcf6c88db804641152824b3ab7999b84829d32b1fc04e5f41a59fbfc28daaedf79d65240fad62e4ad08162d7eeb29ceb84e52989b7d9cc0274c3f7f851c55dbef39565a78079c2bdcc7f92125ce49fb9897517392f83981f2997eff0a39abb7de7138c748bc0eba3c47bf0873948a5559294f2981ed73058933fdfe1474576fbce1718e91781d74788f7e10e72914aab2529e5303dae60b1267fbfc28e8aedf79c26f2f7b9d114b73d6c8e7f64a1fb38c9fe8e863b2cc17c8d0f7f851d25dbef3836a714fe6f8f96a655e96148c35c5413a7e132362983135a2eff0a3a5bb7de70560f4f87ac855578289f2511061e8aa6fa868a2c230640f46dfe1474c76fbce094dfc49a2670d31bce0aaca18ba2f7cd9fd13a18160c9c28ebfc28e99edf79c11280aebf1a47ce6318e1bbc296abd21aea6699effc195291e7f851d34dbef38215015d7e348f9cc631c377852d57a435d4cd33dff832a523cff0a3a69b7de70422c3e087368561b7e0535189da152aeb545e8d7fc0656487afe1474d46fbce083587c10e6d0ac36fc0a6a313b42a55d6a8bd1aff80cac90f5fc28e9a8df79c1063d0a7a7a77baf0afe19a8a6e7ba8e2cfc3e5bbed195ac5ecf851d352bef3820b06274da1c5d864178ffb3cd4edafed9a340dd3d732b72fdaf0a3a6a67de704150c4e9b438bb0c82f1ff679a9db5fdb34681ba7ae656e5fb5e1474d4cfbce082a189d36871761905e3fecf353b6bfb668d0374f5ccadcbf6bc28e9a99f79c1054313a6d0e2ec320bc7fd9e6a76d7f6cd1a06e9eb995b97ed7851d3533ef3820a86274da1c5d864178ffb3cd4edafed9a340dd3d732b72fdaf0a3a6a67de70415050fc0ce5916f05a9cc2dc295ac5bdb412dfcd6e356e79f5f1474d4d0bce0829f2e0a7277f9408e0b6521ad234f15de7d083c09c3add0e2bf28e9a9a279c1053d5c14e4eff2811c16ca435a469e2bbcfa107813875ba1c57e51d35344f3820a7a443c228cbb64bae5614cdc8532b5a1eecd32830bb7452efda3a6a68ae70414f3148a9dc64d2bf8828f5fe1025bc96bd846a762146e8c01fc474d4d16ce0829e529153b8c9a57f1051ebfc204b792d7b08d4ec428dd1803f88e9a9a2d9c1053ca522a771934afe20a3d7f84096f25af611a9d8851ba3007f11d35345b3820a794306746df3fc246cc47c5300ad4a986bce17d6ca07461b3e33a6a68b770414f2760ce8dbe7f848d988f8a6015a9530d79c2fad940e8c367c674d4d16ee0829e4e4daf7429d56b9de8ebdae823490442ee32380e7ed188738de9a9a2dec1053c9b277141008139be89a47bf83e8866add710b278faa3128b1cd35345be820a79354ee2820102737d1348f7f07d10cd5bae2164f1f546251639a6a68b7d0414f26a29d75caedb497cde5eb608f217f8df56ef0c3fe78c4bd0744d4d16fb0829e4d353aeb95db692f9bcbd6c11e42ff1beadde187fcf1897a0e89a9a2df61053c9a6336fcb6843887631479e4bc05641a55668735b9b3130e5d235345bed20a7934b66df96d08710ec628f3c9780ac834aacd0e6b7366261cba46a68b7da414f269659d1864de4845b7ceb3f56f94f64bd544e0fca69c4c53b49d4d16fb5829e4d2b3fb565489f6b39b1a344d5ea9527a2a34861f0d0898c1a94a9a2df6c053c9a550b7d233e1538f61b134fd3cd20ad6d413d063d9e1319d92a5345bed90a7934a916fa467c2a71ec36269fa79a415ada827a0c7b3c2633b254a68b7db214f269522df48cf854e3d86c4d3f4f3482b5b504f418f6784c6764a94d16fb6429e4d2a45be919f0a9c7b0d89a7e9e69056b6a09e831ecf098cec9529a2df6c853c9a54843e48c8e29f1e46901c364ca0134fc0e7ca635de319f36a6345bed91a7934a8f13db71c92a464b89d04cf18bf8c82017a58ec7b96340114d68b7db244f26951d27b6e392548c9713a099e317f190402f4b1d8f72c680229ad16fb6489e4d2a3a4f6dc724a9192e274133c62fe320805e963b1ee58d004535a2df6c913c9a54742aede6f62894df064f2db457bc9f28b7d8b899c81a022e6c45bed9237934a8e755dbcdec5129be0c9e5b68af793e516fb171339034045cd88b7db246f26951ce37c9f48578b5fed1097cf956e8dacada0f24c31d680a5db216fb648ee4d2a39b6f93e90af16bfda212f9f2add1b595b41e49863ad014bb642df6c91dc9a547366b3a2ac2b93a7dfbf2ba0d5399c95362e8d56872a02b1ac95bed923c934a8e6b6286ae3248d77eafb23a429f29f0cec07ded2ce24057d993b7db247a26951cd5511fb51168118017313aad364a3fc57ba81cb5c180b157286fb648f54d2a39a92e51c2cfa68582e62f3b82648addb2f1fc7bc78001645251df6c91eb9a5473515ca3859f4d0b05cc5e7704c915bb65e3f8f78f0002c8a4a3bed923d734a8e6a2455963eb70788e5089b4318a21d4f3c29e3179fd0592ed487db247af6951cd4316c52083b7539f58e02e8b0c3a080f7fe8a54ff70b277e91fb648f5fd2a39a852d8a41076ea73eb1c05d161874101effd14a9fee164efd23f6c91ebfa547350a5b14820edd4e7d6380ba2c30e8203dffa2953fdc2c9dfa47ed923d7f4a8e6a14423b5cca90ff7d7ece3a8059c69ea3f9f16cdbb5593d9890db247aff951cd42710891241f8617db5693b28ab839b6fee8f1c1367b27cd522b648f6002a39a84d21122483f0c2fb6ad27651570736dfdd1e3826cf64f9aa456c91ec005473509a42244907e185f6d5a4eca2ae0e6dbfba3c704d9ec9f3548ad923d800a8e6a134105aeabc996e7063169f6d541339a76f2522f73a93e84d16b247b00251cd426720b5d57932dce0c62d3edaa826734ede4a45ee7527d09a2d648f6004a39a84ce416baaf265b9c18c5a7db5504ce69dbc948bdcea4fa1345ac91ec0094735099c0ee9ae91a1d605d081c19298902b6373d55a15d19f440cb6923d80138e6a13371dd35d2343ac0ba1038325312056c6e7aab42ba33e88196d247b00271cd4266e3ba6ba468758174207064a6240ad8dcf556857467d1032da48f6004e39a84cdc035fcd39e512b13bdad2bcbc77b9439957130a89fa2209b591ec009d735099b706bf9a73ca256277b5a57978ef728732ae261513f444136b23d8013ae6a1336e0d7f34e7944ac4ef6b4af2f1dee50e655c4c2a27e88826d647b00275cd4266dc1afe69cf289589ded695e5e3bdca1ccab898544fd1104dac8f6004eb9a84cdb835fcd39e512b13bdad2bcbc77b9439957130a89fa2209b591ec009d735099b706bf9a73ca256277b5a57978ef728732ae261513f444136b23d8013ae6a1336e06405a7261b0ed1ae81755715e4af0e507104fe7b888411657b00275dd4266dbf541da6f90c802614cfb0d623bfbc449b8e4c58f41109c6cbf6004ebca84cdb7d344da69eef62cee16c27d43f75d6b131c8db0de522153198ec009d7a5099b6f9689b4d3ddec59dc2d84fa87eebad626391b61bca442a6331d8013af4a1336df25d48f32893edbe3d7d6578f5cdb8ecc1cfae939188566a64b00275ea4266dbe346a43efdfe3dff32c79119e391d0017e4b9f832010ae78ca6004ebd584cdb7c5195ad6a8d2de811d5be85bbf19fe2af74381623d215e9595c009d7ac099b6f8932b5ad51a5bd023ab7d0b77e33fc55ee8702c47a42bd2b2b8013af581336df12656b5aa34b7a04756fa16efc67f8abdd0e0588f4857a565700275eb0266dbe2456e90df36d568ba2ac0905f0c64f7fb4c84d6de60af650af004ebd614cdb7c4739e47493b10f99fd24d833d982fd27643cdd37c915ee455f009d7ac399b6f88d73c8e927621f33fa49b067b305fa4ec879ba6f922bdc8abe013af587336df11a73a42afb9aa0eaac6026f75e0252c58b9fb73b2157bab97d0275eb0f66dbe233735aaea40ba458108d1416b3fb03b311ebb0d23faf7716fb04ebd61fcdb7c46572c7b5f4edab32d8e6ee555fec658e1e83a4007c5eefd1f709d7ac409b6f88c971a1c496b1b8e8699aa2d2b7cf294437b38a5cf5bde147ef13af588236df11916f55e1da39d4538b020bcd6794b0b06a135715e87bc433df275eb1056dbe23216abe1c614a0b29cdd0ddc2c71fbf88ced2f087cdf78a0bbf4ebd620bdb7c4641618e916f6a78d6536e81ad8635dd399852236b98ef15bb7f9d7ac418b6f88c814f2f7b8bab542f5ea9c9830462189b2b5089332ede2d1b003af588326df119012a714fc42d0ae17520592e00ba8f5e514d54c25abc5bda0175eb1065dbe2320154e29f885a15c2ea40b25c01751ebca29aa984b578b7b402ebd620cbb7c4640235d797bd8a8e088c4e2adffae09ba13fe1956567f1710c06d7ac41986f88c8036baf2f7b151c11189c55bff5c137427fc32acacfe2e2180daf588330df1190066370b7a3009aa4e90571a7e378ccacfa3297f19cc5c5d41c5eb10662be23200b52f3c7f2d797cc89d7a977bee7f781ef11723f368b8d4c39bd620cc67c46401531f9e89285921bcb7c191775c64d2bd8cf26da6a171c3c747ac4198df88c802963f3d1250b243796f8322eeb8c9a57b19e4db4d42e3878e8f588331bf119005253f9faf6ecaaf1e5bd2a85cf0f92d75de8ddc5a55c7295d2eb106638e23200a334064e9aafb86683471b33961583d6b67dfde747b8e6cfa6d620cc72c4640145680c9d355f70cd068e36672c2b07ad6cfbfbce8f71cd9f4dac4198e588c8028a5c2b931795441cc4e932f6504c6d82d4a439f91be39ce29c588331cc1190051344697edc00eabc419f2c14988f392da3f4b64e34c73b6939b106639923200a2514e55664d837fb3b0b1e512914d0834295aef8668e787674620cc7334640144929caacc9b06ff676163ca25229a106852b5df0cd1cf0ece8c4198e668c8028925395599360dfecec2c7944a453420d0a56bbe19a39e1d9d188331ccd19005124333d0bd398225c9025b8b1409ce2420f59ba1f3173c557a41066399b3200a247667a17a73044b9204b71628139c4841eb3743e62e78aaf4820cc73366401448e590687fb36ebf4f863a8ecfa69e73038132ad8c2cf1702914198e66dc802891b3e1f68a3443a6ca8941801ecca2c886ad2980d829e2fa9238331ccdc90051235085129f35ed75c08f4f62bd18ab738d0517277023c60f648066399ba200a246910a253e6bdaeb811e9ec57a3156e71a0a2e4ee0478c1ec900cc73374401448d22144a7cd7b5d7023d3d8af462adce34145c9dc08f183d920198e66e8802891a442894f9af6bae047a7b15e8c55b9c6828b93b811e307b240331ccdd1005123481124f7e2c3d843471c28e510a1d1b4ffc369cc20c611088166399ba300a2468f2249efc587b0868e3851ca2143a369ff86d398418c221102cc73374601448d1e4493df8b0f610d1c70a394428746d3ff0da730831844220598e66e8c02891a3c153a17c2f5249cf0ae0d507d04ebcff8c790bd033089e80c31ccdd19051234772a742f85ea4939e15c1aa0fa09d79ff18f217a066113d0186399ba320a2468ee54e85f0bd49273c2b83541f413af3fe31e42f40cc227a030c73374641448d1dc35e316c47f876a3d3d30abe01dbca7c0e8c844168450e4628e66e8c92891a3b76bc62d88ff0ed47a7a6157c03b794f81d190882d08a1c8c51ccdd1925123476e639eb3bed4802bacc188d7786d50c6fe4f636c571145358b399ba325a2468edb534fc02a7f62da114fd7d6e8d0ffb5f74b0934ab228c0f177337464c448d1db532b1d901d52836da6c75d5c9985d93e94254c5534519c22fe66e8c99891a3b696563b203aa506db4d8ebab9330bb27d284a98aa68a33845fccdd1933123476d256d9bcb42b035e217e9d7f1e57d4779fb595714a1468acc099ba32672468eda339c5d2152c693efaca012634a607173a176d3e9128d2fd82337464cf48d1db45738ba42a58d27df594024c694c0e2e742eda7d2251a5fb0466e8c99e91a3b68a7329a10188077ea2f4cac0ca8e7a84e309f75641a34d9a09cdd1933e23476d1372659aafe6717ffdb65ba98d135331c0c0310880469cd8149ba3267d468eda2570dd8e0ca34582b3397d7b121d048b7c2ca46cfd8d3b542a37464cfb8d1db4496dcd74c61ced881e3fc11e1c30673ef3058b35f81a784c556e8c99f81a3b689167ad4239103d92f44c486430572ca5e0b758c7ed34f23cabdd1933f13476d1215b6cdd1ef6dda8a06556f058a4b773bc1af3ebd769e61d58ba3267e368eda24142ec12eac41dd3f8977408a93fcd0f72e22a33abd3cddeb27464cfc7d1db448111ea7e825e9e2aa8fbae394a75f846e07096c354a79d6165e8c99f90a3b6890123d4fd04bd3c5551f75c7294ebf08dc0e12d86a94f3ac2cbd1933f21476d120247a9fa097a78aaa3eeb8e529d7e11b81c25b0d529e758597a3267e428eda24041b664cbfcb53d7ffaa37f24ba6205efe30f876a23cecaf30464cfc861db4480736cc997f96a7afff546fe4974c40bdfc61f0ed4479d95e608c99f90c3b68900e6d9932ff2d4f5ffea8dfc92e98817bf8c3e1da88f3b2bcc11933f21876d1201c6744beab310142b51e85ba5527611fec3406110ee7671d833267e431eda240375a9bd6033865082209d19ca2452067d3144e7e1acecfdf0764cfc864db44806d414a04b3472c92fbe069613c809ef7a0d4df58329da1620fc99f90cab68900d90ea6621364bba8af8d98ea70f79c173c56010c623b446820933f21966d1201b11d4cc426c977515f1b31d4e1ef382e78ac0218c47688d041267e432cda2403623a99884d92eea2be3663a9c3de705cf158043188ed11a0824cfc8659b44806c401456947fc3fc834398d7b7fb33ee1dd5c4abf0eda24e50599f90cb468900d87028ad28ff87f9068731af6ff667dc3bab8957e1db449ca0b33f21968d1201b0e0515a51ff0ff20d0e635edfeccfb8775712afc3b6893941667e432d1a240361c0a2b4a3fe1fe41a1cc6bdbfd99f70eeae255f876d127282ccfc865a344806c381456947fc3fc834398d7b7fb33ee1dd5c4abf0eda24e50599f90cb468900d87028ad28ff87f9068731af6ff667dc3bab8957e1db449ca0b33f21968d1201b0e0515a51ff0ff20d0e635edfeccfb8775712afc3b6893941667e432d1a240361c02ec6fcaaf6469cd49383e7d195cf16a8d1a1e36a127426cdfc865a354806c37f5d8df955ec8d39a92707cfa32b9e2d51a343c6d424e84d9bf90cb46a900d86fe472e4b58af7cf60a1ad5c73e4d9a829df2c9e9a549d23f38f21968d6201b0dfb1a6eef5e355c6ecc0271b67491932d3691d62f4793a62272e432d1ad40361bf534dddebc6ab8dd9804e36ce923265a6d23ac5e8f274c44e5c865a35a806c37ea69bbbd78d571bb3009c6d9d2464cb4da4758bd1e4e9889cb90cb46b500d86fd45f89d39e8145f917e053db9c82f791af3af3d6399d32b79821968d6b01b0dfa74b25ffe9d8ee74e78d6ddf30fc4d4b59222a08703a671331432d1ad70361bf4d225e5880883f6c86e7a1e659eef8beacf0966cdd74cfca63865a35af06c37e9944bcb101107ed90dcf43ccb3ddf17d59e12cd9bae99f94c70cb46b5e0d86fd32158bbaaef76034d36b4dc15fb24122ae6e9c0f72d340cd8f1968d6bd1b0dfa632b17755deec069a6d69b82bf6482455cdd381ee5a6819b1e32d1ad7a361bf4c6562eeabbdd80d34dad37057ec9048ab9ba703dcb4d03363c65a35af46c37e98c38702e2491642953273432f588673d6e2122d7939a081079cb46b5e9d86fd31770e05c4922c852a64e6865eb10ce7adc4245af27341020f3968d6bd3b0dfa62e6dd3113f1bf328046996f3ce17fb1db330cdba4b6821e5e82d1ad7a861bf4c5b67b87b2b0e48d2c09ff40f94265463610dddd093d0456fd15a35af51c37e98b55b834f02f2f428390cae47204306eebcc7fdfd24a08c83a3b46b5ea486fd31694318f6b2bc4ad329e622b6387c6c05743c3e5646411aab4868d6bd4a0dfa62d1124446124ef8290b990b9468ef3632e324bf08898236fa91d1ad7a951bf4c5a124888c249df05217321728d1de6c65c6497e1113046df523a35af52a37e98b42491118493be0a42e642e51a3bcd8cb8c92fc222608dbea4746b5ea546fd316841e34893f4e23cb149522cb3f700fbf13d23aa04911b9788f8d6bd4a9dfa62d073c69127e9c4796292a45967ee01f7e27a47540922372f11f1ad7a953bf4c5a0e04e47daa0ef1af0a215154f5b69d2449f52cdd2146e7863f35af52a87e98b41b09c8fb541de35e1442a2a9eb6d3a4893ea59ba428dcf0c7e6b5ea550fd3168361391f6a83bc6bc28854553d6da749127d4b374851b9e18fcd6bd4aa1fa62d06c2723ed50778d78510a8aa7adb4e9224fa966e90a373c31f9ad7a9543f4c5a0d84e47daa0ef1af0a215154f5b69d2449f52cdd2146e7863f35af52a87e98b41b028a20deeb49863fbf6f0c6aeca02b13951de0025dcf26be7b5ea5510d316835f51441bdd6930c7f7ede18d5d94056272a3bc004bb9e4d7cf6bd4aa21a62d06be2e9a9067a8c412a7a88942b31e68ecdff3ba5c9473cb539fd7a954444c5a0d7b5d3520cf5188254f511285663cd1d9bfe774b928e796a73faf52a88898b41af6467c9a4b7972cd566eeb32c47001db7a7b2bce4ecf2ef2805ea55112316835eb190b8d43c9481d64aa9c8d80d661deefa299f89a9e5f8901bd4aa22562d06bd532171a8792903ac955391b01acc3bddf4533f1353cbf12037a95444ac5a0d7aa642e350f25207592aa72360359877bbe8a67e26a797e2406f52a88958b41af54546ec2cb20a36ddd21aa93fea96d1f77c11220d1f2fdec0eea55112c16835ea734efde4317a95e72101b4ff5493866ea2e669da0e5fd7c1ed4aa22592d06bd4d69dfbc862f52bce420369fea9270cdd45ccd3b41cbfaf83da95444b25a0d7a9a5fd1d1b93507fc800d3367cd1b3fc3a365dcd28097f7947c52a88965b41af5334bb5fc1f40727bb7e72cf7922cddaf4177fc00fe2ff0ccf9a55112cc6835ea65237e50eb57477a279b20171c5019867d9c3a5df95fe33df44aa22599d06bd4c946fca1d6ae8ef44f36402e38a0330cfb3874bbf2bfc67be895444b33a0d7a9921a0b9c5a33806b563946846936c441f11d2bd3e27f8e9bd22a88966841af5323341738b46700d6ac728d08d26d8883e23a57a7c4ff1d37a455112cd0835ea646682e7168ce01ad58e51a11a4db1107c474af4f89fe3a6f48aa2259a106bd4c8c5c6f3b7e7265dd6996fa4b41ac80378395a0fb10fc7682925444b3430d7a991744f0cfa9bb2e3d8afababe7b4f5e9701d784521ef8eea925a88966871af5322d15f3f8004cbefdcdc23ba4ee951b55fe5b4b003af1def64c5112cd0f35ea64592be7f000997dfb9b847749dd2a36abfcb6960075e3bdec98a2259a1e6bd4c8b257cfe00132fbf73708ee93ba546d57f96d2c00ebc77bd931444b343cd7a991643bb218af3c5a7125dea34f6c9f38d7ed869a5dd48ef956638896687aaf5322c703768a0b4f1765038a0cc6d134cfd7d5b97717a61df450c8112cd0f65ea6458d06ed14169e2eca0714198da2699fafab72ee2f4c3be8a1902259a1ecbd4c8b1a0dda282d3c5d940e28331b44d33f5f56e5dc5e9877d1432044b343d97a9916341bb4505a78bb281c50663689a67ebeadcbb8bd30efa28640896687b2f5322c683768a0b4f1765038a0cc6d134cfd7d5b97717a61df450c8112cd0f65ea6458d06ed14169e2eca0714198da2699fafab72ee2f4c3be8a1902259a1ecbd4c8b1a069b4db809c3bc39a4ff7dc452a541d690a0845847d15d6054b343d98a991633f5f7c0fae0eda09ec6cb5e0824b0662ccc052e705fa2d500b96687b325322c67d4b0a7808f4169690a631e8fc8c6aed942ce82a08f45c44182cd0f665a6458cf9222748bebe8fafd91929f9f10f3403230612b00ee8ba2c3159a1eccc4c8b19f1444e917d7d1f5fb23253f3e21e6806460c25601dd1745862b343d998991633e214af7ba7d0a1421c316e0fbc332e3486c48d1c38a2ea54c66687b332322c67c3295ef74fa142843862dc1f78665c690d891a387145d4a98ccd0f66646458cf8652bdee9f42850870c5b83ef0ccb8d21b123470e28ba953199a1eccc8c8b19f0c318e35eb5b6c93995836a5d98fcfcc30d0ab3dc217544a34343d999291633e17631c6bd6b6d92732b06d4bb31f9f9861a1567b842ea89468687b332522c67c2e524b305a4414d11d2da0bf5e359d58bdeeef53055d52ccd1d0f6664b458cf85b30a8b9615e8c24f22807a6b46198d9768a210207baa73da4a1eccc978b19f0b5615172c2bd1849e4500f4d68c331b2ed1442040f754e7b4943d9992f1633e16a4eb53e32509316806ce4c2c97cc18dd4d4c6641bea9e9a9387b3325f2c67c2d3297cd5117788afb8a68fad8aefe143a455cf2434d53ed9280f6664bf58cf85a552f9aa22ef115f714d1f5b15dfc28748ab9e4869aa7db2501eccc97eb19f0b4a3205acf2b485419a6704de23b5e3368c037eecd054fd08a13d9992fe633e1693640b59e5690a8334ce09bc476bc66d1806fdd9a0a9fa11427b3325fcc67c2d2654290c77a877892168d9a086cdeb022aba3e0f3e53f5c685f6664bfa8cf85a4b3464719c275194fa9e79690592342c5020be7a79a7ed310ceccc97f619f0b49568c8e3384ea329f53cf2d20b246858a0417cf4f34fda6219d9992fec33e1692a5da41f1d73a8d6a246abcc0e3f2ed93b2f3c45e39fb66834b3325fd967c2d253475a96e7bdb42ffc5a1dc01474bbda710abae7c43f6e746a6664bfb3cf85a4a51ac7867c51cae2b08101a820dfd5dcdcc1b82b857ede8cd5ccc97f689f0b4949358f0cf8a395c56102035041bfabb9b98370570afdbd19ab9992fed13e1692926b1e19f1472b8ac20406a0837f57737306e0ae15fb7a33573325fda27c2d2524624e8c8f64b9983bd4d368fef50d0ee0ba03b828f6f60aaf664bfb45f85a4a4750af71cb9fd5b32f766cf9f5e07845bc2049cc4eededb95fcc97f68cf0b4948d2d713c44160de916b9a01be3b74eb372ecd5f49adbdd16c0992fed1ae16929195ae278882c1bd22d734037c76e9d66e5d9abe935b7ba2d81325fda35c2d2523241d749bd2e9a2712b3469786d398f5c65f9a2e686f75ff0364bfb46c85a4a4630fc0ec273396d0dd335357059d9013876b76b8cddeeda207c97f68da0b4948c51f81d84e672da1ba66a6ae0b3b20270ed6ed719bbddb440f92fed1b41692918a3f03b09cce5b4374cd4d5c1676404e1daddae3377bb6881f25fda3682d2523140a19b9e6731909a16760e024e2dec43607f8226bf76eb43f4bfb46d15a4a4627143373cce6321342cec1c049c5bd886c0ff044d7eedd687e97f68da2b4948c4e2866e799cc6426859d8380938b7b10d81fe089afddbad0fd2fed1b456929189c50cdcf3398c84d0b3b07012716f621b03fc1135fbb75a1fa5fda368ad25231382dadf71407f31cce42d42a46244a6b5b2bc482bc76ece7f5bfb46d16a4a4626f5b5bee280fe6399c85a8548c4894d6b657890578edd9cfeb7f68da2d4948c4de42ca34fcf62ef5f0d816d1108787d5675b5466eedbb543d7fed1b45b929189bb11a6c2a6c2c06e997cf3ca19056dd2c962eb29dab76c2bb0fda368b825231375234d854d8580dd32f9e794320adba592c5d653b56ed85761fb46d1704a4626ea469b0a9b0b01ba65f3cf286415b74b258baca76addb0aec3f68da2e0948c4dd419486de2ec65f783b46478c021ccbe45c39baad2bb630188ed1b45c229189ba73290dbc5d8cbef0768c8f18043997c8b873755a576c60311da368b845231374e6521b78bb197de0ed191e3008732f9170e6eab4aed8c0623b46d1708a4626e9c5655c7c439923ed56fe9edf904c41a28c91fb292db19b04868da2e1248c4dd3738bde83549870062ac9a03e9ffe65c4c3e81c122b6350491d1b45c259189ba6d717bd06a930e00c5593407d3ffccb8987d0382456c6a0923a368b84b231374da6f09f981fc7e84427f2e379ff5f7992ba6496087d8d5b64846d170974626e9b36a264bb0cf5f8b3ccb229737e24d5a51f8d51d0cb1ad10918da2e12f8c4dd365605ef00e75219931630b5667baf8dc9e9dec9616635bc5241b45c260189ba6c94cd038c9c0a5b51a92dcd4c76c4fe137e81b8829c6b92e49368b84c131374d9125b2ca4057adececf27fd186cefdea6a7c796c508d7400936d170983626e9b214b659480af5bd9d9e4ffa30d9dfbd4d4f8f2d8a11ae80126da2e1306c4dd364222dd81ae351a366b96c56e133255d1a49e280d3f35d1a64eb45c260e89ba6c8345bb035c6a346cd72d8adc2664aba3493c501a7e6ba34c9d68b84c1d1374d90617885f65aacb5c6627dbe044bfb56e8d24e290f9d7483d3bd170983b26e9b20b2f10becb5596b8cc4fb7c0897f6add1a49c521f3ae907a77a2e130764dd364165e217d96ab2d71989f6f8112fed5ba34938a43e75d20f4ef45c260ec9ba6c82c485553da2cbd65e90ba52a1df4099c63d356e3cbba438ddf8b84c1da374d90571cbd00612fdd4e89e4107c33de7160c252f023947488bfc0170983b56e9b20ad397a00c25fba9d13c820f867bce2c184a5e04728e9117f802e13076add36415a72f40184bf753a279041f0cf79c583094bc08e51d222ff005c260ed5ba6c82b471fa5bb6554cf706ed4a0996e9e92e0d43c378a0a447a201b84c1dac74d905677007101980fc70c5a75a3b25ca30841533c94d3e4890e80470983b59e9b20acd6c2078dfd85b64431b7a9e438abf302513d4f67991237409e13076b4d364159964534a6c87194b3e03bb647f0bdc8844d3ec48f022488c14c260ed6aa6c82b3154b8ed85e4951933d43cf0f60e173884541aeddd4492bc2a84c1dad64d905661358433b89f8cb51f754009e4128c9903547837b789271c560983b5ad9b20acc16b0867713f196a3eea8013c825193206a8f06f6f124e38ac13076b5b364159826223278f54955735a1c64f8840908c07fe233adb249e1559260ed6b76c82b3035058a7cb7f8d31231052c708777f400aa888d1b3493dceb34c1dad6fd90566052cc3a843d57ce4fded6bb608e55ca80ffd53ff63927d4167983b5ae0b20acc0959875087aaf9c9fbdad76c11cab9501ffaa7fec724fa82cf3076b5c1641598123f20f9bc2c5616af8275001b8bd0c83aa192598b49f6a99f60ed6b83c82b30230a544c252f0eb016d1b0282f0dffb86fef670f1393eef73fc1dad7089056604514a8984a5e1d602da360505e1bff70dfdece1e2727ddee7f83b5ae1120acc08a29513094bc3ac05b46c0a0bc37fee1bfbd9c3c4e4fbbdcff076b5c224159811452a26129787580b68d8141786ffdc37f7b38789c9f77b9fe0ed6b84482b3022831571affc74d8424e7c8aae8d659aef9a2b34d363ef117fd1dad708a0566044f62ae35ff8e9b0849cf9155d1acb35df345669a6c7de22ffa3b5ae1140acc089e516ec4abf398934b6be8d39b4fc4e3e1370f90d5fbc603f576b5c2291598113b2eefe204bd93a94ea497cf2e95e7efbd1a617da8f78dabebed6b84532b3022755ddfc4097b27529d492f9e5d2bcfdf7a34c2fb51ef1b57d7dad708a6566044ea47d1e0bfccb127f25f2564b24dfde6ef15c852a0de3853b0b5ae114dacc089d31bb61a2c6fc4d29c8b10f15c9259f5d8d7d3013ebc724b626b5c229c598113a5376c3458df89a5391621e2b924b3ebb1afa6027d78e496c4d6b84538b302274a6ed868b1bf134a722c43c5724967d7635f4c04faf1c92d89ad708a7166044e9469c32a105489179c254db2dc892dd6c16ada65f2e393ff145ae114e3cc089d275f98accd7f74b1f017618db108b9d57d81f727e2c729a229b5c229c898113a4d4b43b247d54be697fb89435a07d1d2f5b030abc28e54e8546b845392302274992299bd3c80fa4fe7c3d8aeac0601cde60ca3b3821cab74a9d708a7256044e93145337a7901f49fcf87b15d580c039bcc194767043956e953ae114e4ac089d26216794d9eda4bc256dc28e2a80e655f92ded12a0572af76a85c229c968113a4c32cf29b3db49784adb851c5501ccabf25bda2540ae55eed50b845392d0227498659e5367b692f095b70a38aa039957e4b7b44a815cabddaa1708a725a044e930c3fdcc5a3a8c0956eae0d3d3869892491a2cbac28957d5943e114e4b5089d26170bcbe3f427e3ad9528e0a268c970711df1d9b44e2afc5688c229c96b113a4c2d1797c7e84fc75b2a51c144d192e0e23be3b3689c55f8ad11845392d62274985a2f2f8fd09f8eb654a38289a325c1c477c766d138abf15a2308a725ac44e930b45e5f1fa13f1d6ca9470513464b8388ef8ecda27157e2b446114e4b5889d2616848d097ef549d5c0a5ad04e848d6539d9c9dda0dfafc70c8d229c96b213a4c2cf1db3888b7f9d3acc8266c50111289bae3ffd9dbc5f8fbd1b45392d652749859d3b671116ff3a759904cd8a022251375c7ffb3b78bf1f7a368a725aca4e930b3a02e07adad4d76de9d6613bfc3b0096b3ac38d2ee7e40986e14e4b5959d26167305c0f5b5a9aedbd3acc277f876012d675871a5dcfc8130dc29c96b2b3a4c2ce60b81eb6b535db7a75984eff0ec025aceb0e34bb9f90261b85392d656749859cc1703d6d6a6bb6f4eb309dfe1d804b59d61c69773f204c370a725acace930b3982e07adad4d76de9d6613bfc3b0096b3ac38d2ee7e40986e14e4b5959d26167305c0f5b5a9aedbd3acc277f876012d675871a5dcfc8130dc29c96b2b3a4c2ce6044310f620c3dfd2d65152706b683d4e5ba77179c9027bf86392d656849859cbf14747770eede7d1296f076056365d1c621308b362051230d725acad1930b397d28e8eee1ddbcfa252de0ec0ac6cba38c4261166c40a2461ae4b595a3261672fa51d1ddc3bb79f44a5bc1d8158d97471884c22cd881448c35c96b2b464c2ce5f42fb614344d566b4c8449d823118cb62bb5c6b5ae028abc6c92d6568d9859cbe75f6c28689aacd6990893b04623196c576b8d6b5c051578d925acad1b30b397ce4aeaa97e0bbc2fe9dded88843c9100a9835d32b50a2c95b34b595a3761672f9b21e7aba8eddae28b88a139006f80294db2fcc167145acf6796b2b46fc2ce5f3543cf5751dbb5c51711427200df00529b65f982ce28b59ecf2d6568df859cbe6a13b107508dce0ce5ef4b0bf9b45ecd3178356199516ce19f5acad1c00b397cd327620ea11b9c19cbde9617f368bd9a62f06ac332a2d9c33eb595a3801672f9a64ec41d4237383397bd2c2fe6d17b34c5e0d5866545b3867d6b2b47002ce5f34c299a933144d2e9e7471e87c5995491866ded68c78b68b0fbd6568e0159cbe6975335266289a5d3ce8e3d0f8b32a9230cdbdad18f16d161f7acad1c02b397cd2e327ca571e9ae2a54e940470e5bb06e1463f7ff1b2da467f0595a3806672f9a5b64f94ae3d35c54a9d2808e1cb760dc28c7effe365b48cfe0b2b4700cce5f34b65604ee747d1b2c0b71c74431651fe04c3c225869b69343c26568e01a9cbe696b381c3595d098daceb054b05ac09de89324870cd06d282b85cad1c036397cd2d570386b2ba131b59d60a960b5813bd126490e19a0da50570b95a3806c72f9a5aa6c832f0418c5edf28e18e962f8d5ca473e5e8f3eb4a252182b4700d9e5f34b536518b6b507ee5e9ce8f7fabde809bc8928ff7a7a69464831568e01b4cbe696a55643c616e63f3ff19eb61d73c671a10cfe4150f1d28e3463ad1c036a97cd2d493899e4daa2e1029b0a3262df83416a14a8c4fde0a51e0cc85a3806d62f9a5a917133c9b545c205361464c5bf0682d4295189fbc14a3c1990b4700dac5f34b5226e79ec1761e68d23f58fb3760363d04d4f56537f9479d72268e01b59be696a43690630db9a2f9cffb7e58ee3fd25c8954aef02fc28f55245d1c036b47cd2d4855e1eba640ac1bcb73c9145bff0a9b925422061f551ec488ca3806d69f9a5a909484fcd74ebe5fc2645e8b377d7b19a4530831fe7a3da351a4700dad4f34b52111cb1f396ae2e7b0458978ee7a5c15c850d489bcc47b60e358e01b5aae696a4213963e72d5c5cf608b12f1dcf4b82b90a1a9137988f6c1c6b1c036b55cd2d484272c7ce5ab8b9ec11625e3b9e9705721435226f311ed838d63806d6ab9a5a908471a1f56247d65ada91829f3524690c2316873a5f3db215ad700dad5834b521076f564371660f386cefcb66623f304040d950d0bb7b65cf5be01b5ab1696a420d6abedf8fa280f391ac5cf4bc74bea87c5ee3fd73f6cd42b8c036b563d2d48419619017cc1b6469db25801170dfdb78f36a0a56e4ed9c2972806d6ac8a5a908314f3288450d2b566e17c64ad9b61519e1805709c6db39f6e600dad5924b5210612a776936f0b92f93fc52bdab62885bbdacf06f8ab67591cd01b5ab2596a420c154eed26de1725f27f8a57b56c510b77b59e0df156ceb239a036b564b2d48418235effd8899474107be111ea5807f96f160041a27d9d7eb3506d6ac975a9083036bdffb11328e820f7c223d4b00ff2de2c008344fb3afd66a0dad592eb521060663d24ecf3b7f86d6c50aa28df85c83c02c52c49c676150d51b5ab25e6a420c0b53b6f64b4d61906556db6d13e7172f7b04e7e535cec445ab36b564bdd4841815338045437125a3827a7d021fc48c86f0b61226689d8a2f576d6ac97ca908302967008a86e24b4704f4fa043f89190de16c244cd13b145eaedad592f9521060525a136dba9af910c1b6ba3077089043bd848af59f762a615eb5ab25f3a420c0a3403934220c54a43b3a3a88e6077eaf75b558473bec5666be6b564be8484181450c84c0f0ef0bcb2e413b39c4055b86e616f2ea74d8ae717dd6ac97d190830289190981e1de17965c827673880ab70dcc2de5d4e9b15ce2fbad592fa321060512321303c3bc2f2cb904ece710156e1b985bcba9d362b9c5f75ab25f46420c0a2464260787785e597209d9ce202adc3730b79753a6c5738beeb564be8c84181448545e67bbc71f359be079c4384c16965c1b71034a8ae8bbde6ac97d1a0830288f34cf282464a0edef8db9b0688e8b54b2e324629215d31bbdd592fa351060511d699e5048c941dbdf1b7360d11d16a965c648c5242ba6377bab25f46a20c0a23a5f4ef93e68e63a7603ace99a308b7ac638d3e645574e12f8564be8d5418144734ab04b29a82ef7a3d41ffb2c57751d871dea2887ae9dc9f1ac97d1ab830288e52172ef0026c071ff75061e50a5486308e816ad0c5d3d37e4592fa358060511c942e5de004d80e3feea0c3ca14a90c611d02d5a18ba7a6fc8b25f46b00c0a239211de14ad71644ab5a0dea13a8b7fb41e4c9d102e74f6839264be8d611814472323bc295ae2c8956b41bd427516ff683c993a205ce9ed0724c97d1ac230288e46477852b5c5912ad6837a84ea2dfed079327440b9d3da0e4992fa358460511c8c1b02fe186184d864d3bb31cc525bc8ed112add70a7b5c09425f46b09c0a239173605fc30c309b0c9a7766398a4b791da2255bae14f6b81284be8d6138144722e6c0bf861861361934eecc731496f23b444ab75c29ed7025097d1ac270288e45c642a496fe28945de6a9fb65a893c6f63359947823dafa8a22fa3584f0511c8b75466eb8c9b750e74a20594ad08d706c11774eb017b60f5455f46b09f0a23916d34e02fc60d4c9fa110d15152080c357cdb2c31fff6c38e8bbe8d613f144722d969c05f8c1a993f4221a2a2a410186af9b65863ffed871d177d1ac27e288e45b25f9317c50b95013c100b6d40168efdee18f323fcdb0fde2ffa3584fd511c8b634b388836ed8c852fecdd0278237c23d6de28a3f6b6216060f46b09fba23916c52283691ab17b8d17a6802ce83d566fa86893a3ea6c4464c2e8d613f844722d894506d23562f71a2f4d0059d07aacdf50d12747d4d888c985d1ac27f088e45b12161ffd179c50b71666c6db98ebb7e69c4e90eba6b113370ca3584fe211c8b6232c3ffa2f38a16e2ccd8db731d76fcd389d21d74d62266e1946b09fc423916c46587ff45e7142dc599b1b6e63aedf9a713a43ae9ac44cdc328d613f884722d88c3d124169b8e83b6b02fd04bf541d5cdd20c9b932889b5c661ac27f118e45b1170636db804832f98dd2c031769e98e1b4edd5ce6211385ccd3584fe241c8b622d0c6db7009065f31ba58062ed3d31c369dbab9cc42270b99a6b09fc483916c45a18db6e0120cbe6374b00c5da7a6386d3b757398844e17334d613f890722d88b431b6dc024197cc6e96018bb4f4c70da76eae731089c2e669ac27f120e45b1168636db804832f98dd2c031769e98e1b4edd5ce6211385ccd3584fe241c8b622d052edc8b5dcc1b47224cc56cbc97a5e9866fc283f270d3da7b09fc484916c459f31edea188fe5eb9c165ed58f8952e52b7a3aac7b4e1c1f50613f890a22d88b3d63dbd4311fcbd7382cbdab1f12a5ca56f47558f69c383ea0c27f121445b1167a53ca010f15fa312826417e361ba9bca8952d0dea3872214284fe24298b622cf333a65acb0256e508194924642db1a14bd69c77d170e5e68609fc485416c459e5674cb59604adca10329248c85b634297ad38efa2e1cbcd0c13f890a82d88b3ca5aabc3d8dfbe16d831eab988ad24ad2a06b43b42c3993e1927f121515b1167934169e05e95deb068309b9b0950a7824eb9aad282873420334fe242a3b622cf250ee6196a021fe3882dfd5e0a97ad2c981f9801020e69e4679fc485486c459e491dcc32d4043fc7105bfabc152f5a59303f3002041cd3c8cf3f890a90d88b3c923b9865a8087f8e20b7f5782a5eb4b2607e60040839a7919e7f121521b1167924034323fce7619ef93cb1184cb3c78cbba902640d7350c73dfe242a44622cf247068647f9cec33df279623099678f19775204c81ae6a18e7bfc485488c459e48e0d0c8ff39d867be4f2c46132cf1e32eea4099035cd431cf7f890a91188b3c91c1a191fe73b0cf7c9e588c2659e3c65dd4813206b9a8639eff12152231167923834323fce7619ef93cb1184cb3c78cbba902640d7350c73dfe242a44622cf247068647f9cec33df279623099678f19775204c81ae6a18e7bfc485488c459e48e05cdb57e6aeca4106f90c3b24e84156e4ecdb5f59d4337380890a91198b3c91bf45c9087a33f704c5bede9e41c6e0d5c485f91ab0a8688b02121522341679237d17a469a13e508c434a83647b841fd383b834915e50d2ba05242a44692cf246f92f48d3427ca118869506c8f7083fa707706922bca1a5740a485488d259e48df25e91a684f942310d2a0d91ee107f4e0ee0d24579434ae81490a911a4b3c91be44935a5b6c8e6e4d220e14bd4175cc4186de6e6ef8697742a2152234a679237c71e7da41a68304c5c0e88bfa02517b02b881029dc0d308c5542a44695cf246f8d3cfb4834d06098b81d117f404a2f6057102053b81a6118aa85488d2b9e48df1a0608e9167723b42806e926788abce8a8cc83036d34c3d5560a911a583c91be330c11d22cee4768500dd24cf11579d151990606da6987aaac152234b079237c661823a459dc8ed0a01ba499e22af3a2a3320c0db4d30f55582a446960f246f8cc304748b3b91da140374933c455e7454664181b69a61eaab05488d2c1e48df198608e9167723b42806e926788abce8a8cc83036d34c3d5560a911a583c91be3304d2f7b7bbad907b8a9eaf7094dfb3d143ca2c9a3987c4ec252234b089237c65f26714fa44c149229209c160a9254a2232587ef4430fa4185a4469612246f8cbd4ce29f489829245241382c1524a944464b0fde8861f4830b488d2c2448df197a25d7973e06b4cb5c4f3680223fb0b0874262190dc3eaaa17911a584991be32f34baf2e7c0d6996b89e6d00447f61610e84c4321b87d5542f2234b093237c65e62370b5a4f135b02909a02880f520ea17b5cac0340fac4c5f4469612746f8cbcb46e16b49e26b605213405101ea41d42f6b9580681f5898be88d2c24e8df1979619d52f409b39435bf346c9fbcae1d059836d5ccd3eb2d57e11a5849e1be32f2b33aa5e81367286b7e68d93f795c3a0b306dab99a7d65aafc234b093c37c65e566754bd026ce50d6fcd1b27ef2b8741660db57334facb55f8469612786f8cbcac5abbd2b1b02c9d9766fc77d64d6caac6c7ad4266f5984ff18d2c24f1df1979574189fe1036bbbde69abf17a491377d883b9ce0caeb3243e41a5849e4be32f2ad0f2654cd43d9fe850244574118cd230b237c1d92d6662bc934b093ca7c65e5591e4ca99a87b3fd0a0488ae82319a461646f83b25accc579269612794f8cbcab23c9953350f67fa1409115d0463348c2c8df0764b5998af24d2c24f29f19795640544ff16f53276dfdee8e200bcc74053c8234893b333024aa5849e54e32f2ac70a89fe2dea64edbfbdd1c401798e80a790469127666604954b093ca9c65e558e1513fc5bd4c9db7f7ba38802f31d014f208d224ecccc092a961279538cbcab1c2a27f8b7a993b6fef7471005e63a029e411a449d999812552c24f2a719795638544ff16f53276dfdee8e200bcc74053c8234893b333024aa5849e54e32f2ac7034b23b8b7cb15eb3a9e2680f8f463273b0ab6e736661ed55b093ca9d65e558df69647716f962bd6753c4d01f1e8c64e76156dce6ccc3daab6127953acbcab1be5edb46dac927fd86744fc8363376f1c96ef015ca99895957c24f2a769795637b49c8e66268b27dc4b565b8645d4c0b8d8a228792331456b0849e54ee2f2ac6f51fa42571a7c77e41379198c0b0f63f15c0876b21662a5162093ca9dd5e558de93f484ae34f8efc826f23318161ec7e2b810ed642cc54a2c4127953babcab1bd20aa2ee7375807bbcab0c8afaba372451ae60088298aae98924f2a776795637a31545dce6eb00f779561915f5746e48a35cc011053155d31249e54eecf2ac6f462a8bb9cdd601eef2ac322beae8dc9146b980220a62aba62493ca9dd9e558de8c5517739bac03dde5586457d5d1b9228d73004414c5574c4927953bb3cab1bd1836413fe42e6a3e827d8ed7a399d06d159242e4268ab03c934f2a776895637a2f6c827fc85cd47d04fb1daf4733a0da2b2485c84d156079269e54eed12ac6f45e6517583d900b7cc1c30186865d9fdc50f54dec972ac2964e3ca9dda3558de8bb56410927f6797c3b52c93504b19de09c96de352b5586d09d7953bb47ab1bd17538946afcc3557b2e725892015999e933d9fec653ab0f453bf2a776905637a2e97128d5f986aaf65ce4b12402b333d267b3fd8ca7561e8a77e54eed20ac6f45d26e64049fe3b86f7196286ffd5cc5ccca143d754bac3eb8f0ca9dda4258de8ba368da61ec9dd3619af91707f2afe9c18ed4bd4694587f15e2953bb485b1bd17455dc71c86120945edbef437dd5631ab1855bce925b0ffcfc62a77690c637a2e8947a091b8fa750e934aae97b2a2c17e2b57bc2e486201438d54eed219c6f45d111b537c1ecb4c9fde6223575d3be124515bbab88dc4042b1ba9dda4348de8ba2136a6f83d96993fbcc446aeba77c248a2b775711b8808563753bb48691bd174426d4df07b2d327f79888d5d74ef8491456eeae2371010ac6ea77690d237a2e88466ae39a330c781aadde0e2e1d5674a858a18206b2022fcde4eed21a56f45d107596ecbf337f1860d8887edbba12cbd05c0729cd340479dbd9dda434bde8ba20d3eeff09346458ed2ddd6036f38b7a2062d2795a38090df7c3bb48698bd17441909f239d362eda05d88722ed667cd6c0706918744012362f977690d327a2e883113e473a6c5db40bb10e45daccf9ad80e0d230e880246c5f2eed21a64f45d106227c8e74d8bb6817621c8bb599f35b01c1a461d10048d8be5dda434c9e8ba20c44f91ce9b176d02ec439176b33e6b6038348c3a20091b17cbbb486993d17441882b35f5e3053c889053e9155e7334e86b155ad03d1237d3987690d328a2e8830f566bebc60a791120a7d22abce669d0d62ab5a07a246fa730ed21a65145d1061e38ea3038eb54a4f91c6a7d71c331c9a701ad9cf148e0f262da434ca38ba20c3b71d46071d6a949f238d4fae38663934e035b39e291c1e4c5b4869947174418766fbb199083b5169c3e701dbf03254e96b2f8cfc223856d8c690d328f2e8830eb6b888bcdddccaff049a66375fca8c5281233fb81470c7f19d21a651f5d1061d56323704891fbe2986012eee3efafb24ad0aa52ff8e1aa234a434ca3fba20c3a95259393dfa5a47e88cec05bfd5bd8c904d9701fc1c36e86a486994807441875130c4cb28cb171288e69e3377a1d9411b47705ff5386f74d590d32901e8830ea161899651962e2511cd3c66ef43b282368ee0bfea70dee9ab21a65203d1061d424f25855002beccdb673ef5d67dc32c67ca03dbd1e1bf7757434ca408a20c3a832a5d634cdbe01c6e9b4413a4f1e480ca404a13a0c38092af869948124418750554bac699b7c038dd36882749e3c90194809427418701255f0d3290248830ea0a3587e5e045e2f47239d6768bbdf02b23ad6aaa800e03eebf1a65204a1061d4136b0fcbc08bc5e8e473aced177be056475ad555001c07dd7e34ca409420c3a8266231f02dedee5480b4200226ee1ed48961ed05fd38115efd699481294187504b50763908b23f2bb935062c45d29bd10d701c67f7702461fbd3290253830ea0952cfecabe3ae0da2a36d280839b95ca158c7b2bebe04a67f8a65204a8061d412959fd957c75c1b4546da50107372b942b18f657d7c094cff14ca409500c3a8252400d83a5c1e5eb60a8102a0664b55050de2f0bac812b43e3994812a1187504a30c2d5ff85a2e59791ce67c04bfc8c89c68a0735602582bc83290254330ea0945185abff0b45cb2f239ccf8097f919138d140e6ac04b0579065204a8661d4128a30b57fe168b965e47399f012ff232271a281cd580960af20ca40950cc3a82514616affc2d172cbc8e733e025fe4644e345039ab012c15e4194812a1987504a284ee8583279481a499b2de843f2eab1c13649915d25846084290254340ea0944f29e30911c8f2b74b0321f87fdc338b7d18d57eb74b0a65095204a8691d41289d53c6122391e56e960643f0ffb86716fa31aafd6e9614ca12a40950d23a82513a339e7cf3fa2d5fe3d94e09f7672c55ef0f9856da2c2b38264812a1a57504a273673cf9e7f45abfc7b29c13eece58abde1f30adb45856704c9025434aea0944e65a8c4c7cbf18024731fe4fd5930f7fb6eaa3b765b0ae849a204a8696d41289cb412af1a65492874630c2c7a31c7d27688189cac8615ead3540950d2ea82513950e683bf97f8791442e4bb73e2f5876cbaf55f18dc2befe6b812a1a5e504a27291cd077f2ff0f22885c976e7c5eb0ed975eabe31b857dfcd7025434bca0944e5239a0efe5fe1e4510b92edcf8bd61db2ebd57c6370afbf9ae04a8697941289ca47341dfcbfc3c8a21725db9f17ac3b65d7aaf8c6e15f7f35c0950d2f28251394872961844cedb96fab1819bdaebe594b5a1a174d92bf18ab912a1a5e604a2728f713e89367419b0ad2fc95fadce295165ef8545af57e4b97325434bcd0944e51d6e8f6b19be95e4122c58e75392b0cac68b4ce75bafcb16e74a86979b1289ca3969312ee0538e4adc2577f69f1bbfbd87c2dc2ab45f97d1cf950d2f37251394715e74b66d7d7f187017b615362ddda30a31fab165bf3147a02a1a5e6f4a2728e148fbc587d160b397fc32526452196e0f1037bec87e6433415434bcdf944e51c11e09e3bc7923e9e7c52accc09a910418ccb1d98dfcca0a83a86979c0289ca3813c13c778f247d3cf8a559981352208319963b31bf994150750d2f380513947020439e79ebaf22a56e1715afa60a2385ddf09c234f329ce0fa1a5e701a2728e030873cf3d75e454adc2e2b5f4c14470bbbe138469e6539c1f434bce0344e51c0610e79e7aebc8a95b85c56be98288e1777c2708d3cca7383e86979c0689ca380c21cf3cf5d79152b70b8ad7d30511c2eef84e11a7994e707d0d2f380d13947018439e79ebaf22a56e1715afa60a2385ddf09c234f329ce0fa1a5e701a2728e030134f4c8434a7cd93faf187440aa533b68d7aa29b653b65f534bce0354e51c05f269e9908694f9b27f5e30e88154a676d1af54536ca76cbea6979c06a9ca380be4d3d3210d29f364febc61d102a94ceda35ea8a6d94ed97d4d2f380d53947017c268cbcce7ba0ef57a45262184b87c5af181770d829dcd3aaa5e701ab728e02f74d19799cf741deaf48a4c430970f8b5e302ee1b053b9a7554bce0356e51c05ee26454be6c4e640165e0fb059247d3eb70ca01f5da774f2ab979c06aeca380bdb4c8a97cd89cc802cbc1f60b248fa7d6e19403ebb4ee9e5572f380d5d947017b625278847e9fb83114504e95c885322d6dec2d9739dd56eaf5e701abc28e02f6b4a4f108fd3f706228a09d2b910a645adbd85b2e73baadd5ebce0357851c05ed620b079cc7e508efce0d9cd6a17aab356274dc1cb77575ebe79c06af1a380bdab4160f398fca11df9c1b39ad42f5566ac4e9b8396eeaebd7cf380d5e347017b560ed43fdecfa4beab502d5da05508f5534979632add5f1efae701abc78e02f6ab1da87fbd9f497d56a05abb40aa11eaa692f2c655babe3df5ce03578f1c05ed563b50ff7b3e92faad40b576815423d54d25e58cab757c7beb9c06af1e380bdaac02b457a3538878124e3114fa9ea5d294f80d7553eafa9bd8380d5e3d7017b5570568af46a710f0249c6229f53d4ba529f01aeaa7d5f537b0701abc7ae02f6aae0ad15e8d4e21e04938c453ea7a974a53e035d54fabea6f60e03578f5c05ed55c15a2bd1a9c43c0927188a7d4f52e94a7c06baa9f57d4dec1c06af1eb80bdaab82b457a3538878124e3114fa9ea5d294f80d7553eafa9bd8380d5e3d7017b5570568af46a710f0249c6229f53d4ba529f01aeaa7d5f537b0701abc7ae02f6aae039284181b880874b590b669f9fd2cd38af9fb0f7bea89a0f03578f5d05ed55bf7250830371010e96b216cd3f3fa59a715f3f61ef7d51341e06af1eba0bdaab7e70b35eb3b8649fe530f3c27675a95cdd6ac11fdbfaa40c3d0d5e3d7517b556fb6d791614472bc2822eadace4e1b0e1b581c49bb4f549bc7b1abc7aeb2f6aadf5670484d564ba07bc2a2181c1b9bfeb65afcb9366ea951cf73578f5d75ed55be95a1b62579fd6923021092b7b69ddfec60bd982cad52bddef6af1ebafbdaab7d140491d5c160fa7180ed87eeeca1a2586c3f56192aa595fdfd5e3d7607b556fa10ca493650281d0e7ea7725d58a927308342d1f2254b463c0abc7aec1f6aadf41194926ca0503a1cfd4ee4bab1524e610685a3e44a968c781578f5d83ed55be8232924d940a07439fa9dc97562a49cc20d0b47c8952d18f02af1ebb07daab7d0465249b28140e873f53b92eac54939841a168f912a5a31e055e3d760fb556fa08565b8efcfe7f9136743885509f85587def144e224b47e00bbc7aec206aadf40f38c976a6d361a524b53732993568d8f68a6af8419691641878f5d841d55be81d7192ed4da6c34a496a6e65326ad1b1ed14d5f0832d22c830f1ebb083aab7d03a6f38334823e9174aa1a2f25ccc018bd4d5ee3d035a473462e3d76108556fa0736a82bf3d1e34b14d100c0cb18e613fa4581ed603b4900cc6c7aec211aadf40e56117d72712cbe551ecde415b1320a7435c8008046921bd8e8f5d842455be81c94e4206fafbfa4d5ba682aaae1c9f768165426c05d2451f1e1ebb0849ab7d0391289666a2ce571d6f19cb7d542f9d14fd76c73408a48be23d3d76109456fa0721512ccd459cae3ade3396faa85f3a29faed8e68114917c47a7aec2128adf40e422e6bf3380fbef87433f41d48b4d27bf0875f2c1f92312cf5f5d842525be81c835cd7e6701f7df0e867e83a9169a4f7e10ebe583f246259ebebb084a4b7d0390645c2258d155e64889c969d1ac9a817bcc9bf0c7b48c657d8d761094a6fa0720b1796a3c7011f4bc905f3622d89ae57743fc074f3918e53b2aec21295df40e4152f2d478e023e97920be6c45b135caee87f80e9e7231ca7655d84252bbe81c82a5e5a8f1c047d2f2417cd88b626b95dd0ff01d3ce46394ecabb084a577d03905448c776e4df5ce0fffc61396443d0e39caa4603998c744196761094affa0720a71da14676951c44b7c5889ac07dffef3400ce633018ea272dec212960f40e414d3b428ced2a38896f8b113580fbffde68019cc66031d44e5bd84252c1e81c829a029772872ad39596e2e892f9ee5de4caaf7be8bd63aa40b8b084a584d0390533052ee50e55a72b2dc5d125f3dcbbc9955ef7d17ac754817161094b09a0720a660a5dca1cab4e565b8ba24be7b977932abdefa2f58ea902e2c212961340e414cc14bb9439569cacb7174497cf72ef26557bdf45eb1d5205c584252c2681c8299829772872ad39596e2e892f9ee5de4caaf7be8bd63aa40b8b084a584d0390533052ee50e55a72b2dc5d125f3dcbbc9955ef7d17ac754817161094b09a0720a66031eefa778b47e87086eae6738dd75aa68b3c8b55ea91d22d212961350e414cbf63ddf4ef168fd0e10dd5cce71baeb54d167916abd523a45a4252c26a1c82997e53ce428b03822479e871c1c62dbb9294d9348954aa48ecb584a584d5390532fb33aeddc2dd66cbab9da9ab8451d54d245eab6ea654937d6c094b09ab720a65f5675dbb85bacd97573b535708a3aa9a48bd56dd4ca926fad812961356e414cbea5acdcfb84bfdb166436cd6093db35c8c26f01696524f99b1252c26aec82997d341adf81d6e5de584539fd40a71c4e112fa228929a4a0d7634a584d5e90532fa50f6e48e7b31e4dc07405d00cd9e7ea20a0876e50494352c794b09abe20a65f491edc91cf663c9b80e80ba019b3cfd441410edca09286a58f2961357c414cbe923db9239ecc793701d0174033679fa882821db941250d4b1e52c26af882997d2407849fea6f54f0bb6cf4a85ec59d78ffb07dce7f4a1c3a3da584d5f20532fa470f093fd4dea9e176d9e950bd8b3af1ff60fb9cfe9438747b4b09abe40a65f48e1e127fa9bd53c2edb3d2a17b1675e3fec1f739fd2870e8f6961357c814cbe91c3c24ff537aa785db67a542f62cebc7fd83ee73fa50e1d1ed2c26af902997d238045c5753cbb18e6e9c10ade45035b7f5b41f43f1a1c547db584d5f21532fa46f08b8aea797631cdd38215bc8a06b6feb683e87e3438a8fb6b09abe42a65f48de11715d4f2ec639ba7042b79140d6dfd6d07d0fc687151f6d61357c854cbe91bc22e2ba9e5d8c7374e0856f2281adbfada0fa1f8d0e2a3edac26af90a997d237845c5753cbb18e6e9c10ade45035b7f5b41f43f1a1c547db584d5f21532fa46f0179d43264c94508b4edbe481fd1526b1302ada3138aa9f6c09abe42b65f48ddf2f3a864c9928a1169db7c903fa2a4d626055b46271553ed81357c856cbe91bbe5e750c993251422d3b6f9207f4549ac4c0ab68c4e2aa7db026af90ad97d2377c48fc71df3b05071243a54c07df075d842d992d86c5569f614d5f215c2fa46ef71e0b3c6b4c6c90dc5410c007b46ce3030774b70a8aaee2c39abe42b95f48dded3c1678d698d921b8a821800f68d9c6060ee96e15155dc587357c8572be91bbda043f4a5a0814c6291d092816c811b406ca1538272abd2f0f6af90ae67d2377b3087e94b410298c523a12502d9023680d942a704e557a5e1ed5f215ccfa46ef6610fd2968205318a47424a05b2046d01b2854e09caaf4bc3dabe42b99f48ddecc21fa52d040a63148e84940b6408da03650a9c13955e9787b57c85733e91bbd9843f4a5a0814c6291d092816c811b406ca1538272abd2f0f6af90ae67d2377b3013fba3edd8fb47db6deb2ad0f894a8d3eee960e257a785ee5f215cd0a46ef65f27f747dbb1f68fb6dbd655a1f12951a7ddd2c1c4af4f0bdcbe42b9a148ddecbe4fee8fb763ed1f6db7acab43e252a34fbba583895e9e17b97c85734291bbd97c2bef781b9e3cc1933c1f7e7fbb036e9a238d630fbd3dd373f90ae6862377b2f757def0373c798326783efcff7606dd34471ac61f7a7ba6e7f215cd0c46ef65ee3bd0391b4f558904bd4421f6e26be2633a77e83bf4f8f1d0e42b9a198ddecbdb03b2cae3750d94c1474e6be5bb35ecc121322c74e9f387a2c85734341bbd97b5076595c6ea1b29828e9cd7cb766bd982426458e9d3e70f4590ae6868377b2f6a0ecb2b8dd43653051d39af96ecd7b30484c8b1d3a7ce1e8b215cd0d06ef65ed41d96571ba86ca60a3a735f2dd9af6609099163a74f9c3d1642b9a1a0ddecbda83b2cae3750d94c1474e6be5bb35ecc121322c74e9f387a2c85734341bbd97b50026bb51b78151ae0b693a4af5d1bc01ed287ea9a3e72985a0ae6868477b2f69f04d76a36f02a35c16d27495eba37803da50fd5347ce530b415cd0d08ef65ed3e09aed46de0546b82da4e92bd746f007b4a1faa68f9ca61682b9a1a11decbda7c135da8dbc0a8d705b49d257ae8de00f6943f54d1f394c2d057343423bd97b4f826bb51b78151ae0b693a4af5d1bc01ed287ea9a3e72985a0ae6868477b2f69f04d76a36f02a35c16d27495eba37803da50fd5347ce530b415cd0d08ef65ed3e026ff9f8adba93ae571af53cf3d4e2faf4e3d028c9ca7ba83b9a1a11eecbda7bf4dff3f15b75275cae35ea79e7a9c5f5e9c7a0519394f75077343423dd97b4f7e2810d6d845076e4d93837734eb96e6b7e536662f72a08e0fe686847cb2f69efb5021adb08a0edc9b2706ee69d72dcd6fca6ccc5ee5411c1fcd0d08f965ed3df62c55b40dea803bee1ad404cba4b9c2da411bf4baca83dc409a1a11f3cbda7beb58ab681bd50077dc35a80997497385b48237e9759507b881343423e797b4f7d63d6928e48063727038163b2689453363b0b22ee82a111503686847d02f69efab06e4aa75d72967983cf29e4508e88ec20da6b9cd5423ce07d0d08fa15ed3df550dc954ebae52cf3079e53c8a11d11d841b4d739aa8479c0fa1a11f42bda7beaa1b92a9d75ca59e60f3ca791423a23b08369ae735508f381f43423e857b4f7d54372553aeb94b3cc1e794f228474476106d35ce6aa11e703e86847d0af69efaa86e4aa75d72967983cf29e4508e88ec20da6b9cd5423ce07d0d08fa15ed3df55068a7a767bb8f75bf6b19f0991370003c611995a7847b64fb1a11f42cda7bea9f5d61a77c4d816e36a2fa092a1d3e28736e75874c08f86df73423e85ab4f7d53d46d5a7a571655f2512ba3a4c30da78e1892d6a9511f27fef6847d0b669efaa7919bda7f7b92d4101f23a9c90581319bdbe9d312723e6a3dfd08fa16dd3df54f1337b4fef725a8203e4753920b026337b7d3a624e47cd47bfa11f42dba7bea9e266f69fdee4b50407c8ea7241604c66f6fa74c49c8f9a8f7f423e85b74f7d53c459ff986a9fcc8ac75e9b0c7ab6f6f5e8a12be5361f36c2ff847d0b6f9efaa7874011898215fb984689fc40ed644c13cbee9a26693e6f2a0008fa16e03df54f0d0c356bb10259b344e0bea9d2bef64f928976a8cf7cdff80111f42dc17bea9e19186ad76204b36689c17d53a57dec9f2512ed519ef9bff00223e85b82f7d53c3230d5aec40966cd1382faa74afbd93e4a25daa33df37fe00447d0b705efaa786461ab5d8812cd9a2705f54e95f7b27c944bb5467be6ffc0088fa16e0bdf54f0c84f6913bcfbfdb705d8b0c523e5c3212343ace8f4ce0124121f42dc18bea9e18f2ae48026ce5df0c37e27b23fc1e46a41339c2de69c03ec253e85b8327d53c31d55c9004d9cbbe186fc4f647f83c8d48267385bcd3807d84a7d0b7064faa7863a37a459480fda45c5c564f0f6fdefd0ff7ab3139770115495fa16e0caf54f0c736f48b2901fb48b8b8ac9e1edfbdfa1fef566272ee022a92bf42dc195ea9e18e66aa3bdcd15cb99cee259ebd3ee1d6bf8970eaa5ac046f658e85b832cd53c31cb6159d44701f9b6559179ff9fd298ffebda5fb0b2808f90b2d0b7065aaa7863954ec6013ada55ef62efba27379b9027d26101bd620120c566a16e0cb654f0c729299e5b228b0e617dac3a76672d7e779f6e45d6c102432ece42dc196da9e18e51533cb645161cc2fb5874ecce5afcef3edc8bad8204865d9c85b832db53c31ca2328bc537029c08ae7db00194ac5806786559b701090e5f3a0b7065b7a786394365178a6e0538115cfb60032958b00cf0cab36e02121cbe7416e0cb6f4f0c728656416d88e0d2a571c3862e4aa7be41dc41a93801243b20e92dc196df9e18e50b389533be9807cd9b53d2848d45daabb32f94cbff4877e5d35b832dc03c31ca15712a677d300f9b36a7a5091a8bb557665f2997fe90efcba6b7065b807863942a6e6727a73681b9251c103a2d0dc8d6c76a958bfa21e13b4e6e0cb701f0c7285368e0a7fb4365f50204e69c5211efd589816d73f143c41a9ddc196e04e18e50a55dd3a8a35d2e6cbbd693609c1a3dd30daf1d43df8789d93cb832dc0ac31ca14947b9a9f390bf5c2f79ece9302ad9ce160a7ce3bc0f15567a7065b816863942911b85ac93f7e13b16c09ffa584c11c426c13c23751e2c50f5e0cb702e0c728521370b5927efc2762d813ff4b09823884d827846ea3c58a1ebc196e05c18e50a426e16b24fdf84ec5b027fe9613047109b04f08dd478b143d7832dc0b831ca1484683fbd4c956c5b6dd1c5faba56ec4930b62377a5f1642bb0065b8171639429075c91d346013b399370521d6ca436ba5c18894b48e2c9fb610cb702e3c728520d4535ff38d8d8f5dead6a62d13ecb9cb2dd54f28ec5959ac3196e05c88e50a419167e571e88146e75279aed9a73f5616066ec411a8b2cd98732dc0b921ca148312cfcae3d1028dcea4f35db34e7eac2c0cdd882351659b30e65b817243942906259f95c7a2051b9d49e6bb669cfd585819bb1046a2cb3661ccb702e48728520c4400511a11705f661099d94cb960932fde3a464d15968703a96e05c91e50a41870c1c7bef046e6f79e001518f22708df6738b259fb2d284762dc0b924ca14830d1838f7de08dcdef3c002a31e44e11bece7164b3f65a508ec5b8172499429061a3071efbc11b9bde78005463c89c237d9ce2c967ecb4a11d8b702e49328520c3460e3df7823737bcf000a8c7913846fb39c592cfd969423b16e05c92650a418684dda179d1d497a55ccdb40ea1d670761e4f4b5f82d29eb63dc0b924da14830cf27c687e710f57763667ca9cc312c36be762bc7ed5a557ac8b817249c4290619d4f8d0fce21eaeec6ccf9539862586d7cec578fdab4aaf591702e49388520c33a2b2c78491a38604566b8cf28bb0f02f484f17bb269578f23e05c92720a4186735658f0923470c08acd719e51761e05e909e2f764d2af1e47c0b924e414830ce638c439d13f4403cd67a9649ae29a33ccc0084ac6a55fe090817249c9290619cb718873a27e88079acf52c935c53467998010958d4abfc12102e49392520c33966f233ff1d37291ed6b6bba6380c6f72dac6387179581264305c92725a418672b6a58d8907d47a692a39d9cbef7ec165605096a2c2b03f0870b924e4c4830ce5560c409cdd0f1cfdd14016175e63654a6b65530555609850f17249c9990619ca94d9a6c4878462271f4c8eae3c2cad14818ecbca7ac14ae1f2e49393420c339512747313dc6eec79bb657fdbf7bf3ca8ade1bd54c582b003f5c927269418672a14e8e627b8ddd8f376caffb7ef7e79515bc37aa98b056007eb924e4d2830ce542292f1da3f21da126a6261ef5e62d522624b1b12e60ada4fe7249c9a60619ca83525e3b47e43b424d4c4c3debcc5aa44c4963625cc15b49fce493934c0c33950630cecf3c9ed90752655ea3cf8f1370933f0920b682b837fac927269918672a0b619d9e793db20ea4cabd479f1e26e1267e12416d05706ff5924e4d3230ce54164f4d959f51c6a0016240b73632abea47a866ded70ae283ec249c9a65619ca82b2aad83eb79efc2ba914796645bb5fc89fd1019ab15c6abd9493934cbc3395055555b07d6f3df8575228f2cc8b76bf913fa2033562b8d57b2927269978672a0aa36c8685abe218da211e4818965361a22a082c2a9571c536624e4d3300ce541536d90d0b57c431b4423c90312ca6c344541058552ae38a6cc49c9a66019ca82a66733fa17cee8b94014582e1d8b3690852e4d66a25c72f19993934cc13395054b5a7a4cdc7433f537f57684330ccb490508dd2941b8e7873427269983672a0a954106f265beca6d27b7b3305e0ff4ba04bdfcae8071d0b2694e4d3307ce5415290e203d7853f75d073c2c88b416479c04283bb8fde3a308d39c9a66109ca82a511c407af0a7eeba0e785911682c8f3808507771fbc74611a73934cc21395054a23880f5e14fdd741cf0b222d0591e7010a0eee3f78e8c234e7269984272a0a9447101ebc29fbae839e16445a0b23ce02141ddc7ef1d18469ce4d33084e54152886e16303215d8532b8f8eb3395ad7e83d2ffdebdb3a32313ac9a6610aca82a50f683eb9110213290eebe38e6aac0df8750c3e33b374660676934cc21695054a1d5c8fcaceda88d4d5a48d44cd4e7a18e4c4bec363e8cdb0ee2699842e2a0a94394531ee4a8b742c6315e0b192935259c435bfe2c4d19d05dd4d33085d5415287116763541ed4adb7df8878b1d1d02db8317c22186a33bafbb9a6610bba82a50e12cec6a83da95b6fbf10f163a3a05b7062f84430d46775f7734cc21775054a1c259d8d507b52b6df7e21e2c74740b6e0c5f08861a8ceebeee699842eea0a943843fc402bc40b95ea7910280e0de7504136a53683219df21ddd33085de415287070b9a5e2557d54006eecb29b9b348302180e92c6133bfe7bca6610bbd82a50e0d1734bc4aafaa800ddd9653736690604301d258c2677fcf794cc2177b054a1c1a2e6978955f55001bbb2ca6e6cd20c08603a4b184ceff9ef299842ef60a9438345cd2f12abeaa003776594dcd9a41810c074963099dff3de533085dec1528706845b83b0253b68326b978c3932ae12a12bad522103c001fcb6610bbd92a50e0cf1782ceb17dcf89053fb7af1e4c207c2021eca01d7801e397cc2177b354a1c19d2f059d62fb9f120a7f6f5e3c9840f84043d9403af003c72f9842ef66a943833a5e0b3ac5f73e2414fedebc793081f08087b28075e0078e5f3085decd528706744828ce38c4decae1ca83a0ea576208fbbba75ce8c010c0bf610bbd9ba50e0ce71c63f51e6020187b61cd69cca52239f2239115ce8023257fc2177b384a1c19cd38c7ea3cc04030f6c39ad3994a4473e447222b9d00464aff842ef6709438339a718fd479808061ed8735a7329488e7c88e44573a008c95ff085dece1287067346f32019fd7634692db31765d1f6ff78bc8cb0a71011acfff10bbd9c350e0ce676a765bec85290fdd832914b2353e17123dd870df023743ff2177b387a1c19ccd60ff1085e0b4a272d318515c60da561f27f33dbb04702bff42ef6710438339994e1079b897cbc79d72f6cab0b812d438fc28d77308e1fbff85dece218706733128334c1e05fa11f2b2b3bd596683d06ca4940ae311c59c000bbd9c440e0ce6615066983c0bf423e565677ab2cd07a0d9492815c6238b3800177b38881c19ccc22cdf8924ee4aca8297951d5d906d69ad3e928789471814012ef671113833998359bf1249dc9595052f2a3abb20dad35a7d250f128e3028025dece222706733063f907d408f8dacc22b1a9d6e3813ceafa68c7a221c61f405bbd9c445e0ce660b0b33532df57ddc3c22fb62d46685c559f95b504138c58c0c77b3888cc19ccc151666a65beafbb87845f6c5a8cd0b8ab3f2b6a082718b1818ef6711198339982a2ccd4cb7d5f770f08bed8b519a171567e56d4104e3163031dece223306733054599a996fabeee1e117db16a3342e2acfcada8209c62c6063bd9c44660ce660a83f478b8c2e404679fc7c553e5eba7d9a41f760108c5a64c87b3888cd19ccc14f0aa16fc532e30fabc5bed274b3d3232f30311c1e18b66d91f671119b3399829d1542df8a65c61f578b7da4e967a6465e6062383c316cdb23ece223366733053a2a85bf14cb8c3eaf16fb49d2cf4c8cbcc0c4707862d9b647d9c4466cce660a74550b7e2997187d5e2df693a59e9919798188e0f0c5b36c8fb3888cd99ccc14e83629550004937d7428b34f4333905aedaf541dde8b687d20671119b4399829cf6c52aa000926fae851669e866720b5db5ea83bbd16d0fa40ce2233687330539e64b7acace8b078886f936504c49f93b16992d3772da398829c4466d1e660a73b5581b206a7c373c8abecf2017f9d4f5d7f6802eb5b48d5063888cda4ccc14e753715bcba25e96a4924a00bfaf598c6b5ab1261d3b6934e0d71119b4a99829ce96e2b79744bd2d492494017f5eb318d6b5624c3a76d269c1ae2233695330539d268694b956e082bdc5f4657e3ccc142d1588be34bda4edc36c4466d2b660a73a35ce4efd7b272da708b52d7bf8fe0ad9d5d5a2294b49f5c6e888cda57cc14e74545dc385c3b483798e36bd777161f833566f6a12669405cde1119b4b09829ce8917cac9654cf2f1e9939dd6e6229d2e657a2f9e49d2825dbd2233696230539d112f9592ca99e5e3d3273badcc453a5ccaf45f3c93a504bb7a4466d2c460a73a225f2b259533cbc7a64e775b988a74b995e8be79274a0976f488cda588c14e74444a68a3d73dfa120469b4df290b479b267dbf4e4b941491ea119b4b12829ce88720e3a05b5256a6c0a02fe64a0ced5e47a7c0f894282ac7d5233696260539d10d41c740b6a4ad4d81405fcc9419dabc8f4f81f12850558faa466d2c4c0a73a21a0fa0da1a1fbd1dba4d85c1202a13a1194b463e4da0acc3558cda589914e744331f41b4343f7a3b749b0b824054274232968c7c9b415986ab19b4b13229ce88663e8368687ef476e936170480a84e84652d18f93682b30d5633696264539d10cc0919297dd44b708a38f430f946fb30c506744e6a0567bead66d2c4c9a73a2197123252fba896e11471e861f28df6618a0ce89cd40acf7d5acda589934e74432e2464a5f7512dc228e3d0c3e51becc31419d139a8159efab59b4b13269ce8865c48c94beea25b8451c7a187ca37d9862833a273502b3df56b3696264d39d10cb81da4f08a1b198b5b5c09378c6611344b1387429d567d8ed76d2c4c9b73a2196f3b49e114363316b6b8126f18cc226896270e853aacfb1daeda589936e74432de02a61ad542c8b0253ceb06298ea2f926fa5f667259f7df5eb4b1326ece8865bb054c35aa8591604a79d60c531d45f24df4becce4b3efbebd696264dd9d10cb760a986b550b22c094f3ac18a63a8be49be97d99c967df7d7ad2c4c9bb3a2196ec1530d6aa16458129e758314c7517c937d2fb3392cfbefaf5a589937674432dd82a61ad542c8b0253ceb06298ea2f926fa5f667259f7df5eb4b1326ece8865bb054c35aa8591604a79d60c531d45f24df4becce4b3efbebd696264dd9d10cb76035990dfd888e8c070787b25b9f1c71b9441bf8937df97bae2c4c9bb4a2196ebf6b321bfb111d180e0f0f64b73e38e3728837f126fbf2f75c589937694432dd7e627690a2f89cb2d3eae4f16672cfeedfbcb23e4af7e792b9b1326ed38865bafb50ff79f2c79be85fa2900ac4dbfe05ba25a6d892efd0c9746264dda810cb75f52e114c92659a537711e63d81ae5a336ef7900d22dfa336e9c4c9bb512196ebe95c229924cb34a6ee23cc7b035cb466ddef201a45bf466dd3899376a2432dd7d244578af66ccbd094145f1dfeafc6f5b68a8290887e8e7fa81326ed45865bafa314c16e99affa23dff58463f555ec1367c1477d0dfd1ea351264dda8c0cb75f452982dd335ff447bfeb08c7eaabd826cf828efa1bfa3d46a24c9bb518196ebe8a5305ba66bfe88f7fd6118fd557b04d9f051df437f47a8d4499376a3032dd7d14321dcd7a5633a1b778e947a2a5bec338b67e446ce8f6be8a326ed46165bafa27643b9af4ac67436ef1d28f454b7d86716cfc88d9d1ed7d1464dda8c2cb75f44e54898e962f310995b06b46828d5934dd863b6db0a3dc9e29c9bb518696ebe89b352575d934c495e32d9cb4fd111091b5b8b9375e47bae0549376a30e2dd7d1356a4aebb269892bc65b3969fa2221236b71726ebc8f75c0a926ed461c5bafa26a60a83011a974da448338fbec3aa06ed18f2739761eed25534dda8c39b75f44d34d62b8d0294c3740d3381fd06b9f059dca90cee93ddbeea79bb518746ebe89a526d7ca4d28faf13973366798cd9c33364163f9cf7bb98150376a30e9dd7d13494daf949a51f5e272e66ccf319b38666c82c7f39ef77302a06ed461d3bafa2692277181e17a4e479d999fc65b2ccef4d3b1d2433aeee7a941dda8c3a875f44d234ee303c2f49c8f3b333f8cb6599de9a763a48675ddcf5283bb518750ebe89a4629d86032bf9ba12e33454164a999fb49738b68e8bba0490876a30ea2d7d1348b53b0c0657f37425c668a82c95333f692e716d1d177409210ed461d45afa269163373d977d4d1077099db2d8a9cc615207a6fff9fee82c822da8c3a8c5f44d22b66e7b2efa9a20ee133b65b15398c2a40f4dfff3fdd059045b5187518be89a45659e1be8c29a6a07a3432de2269767c7c96025a7cba0cc48c6a30ea327d1348ab3fd5d5c529afc3ac352be43cc94b20f3d84710f6741b2d19d461d465fa2691550bbe043729c20a10371df07188f469e25cd07de9e837fe34a8c3a8ccf44d22a9177c086e538414206e3be0e311e8d3c4b9a0fbd3d06ffc6951875199e89a45522ef810dca7082840dc77c1c623d1a7897341f7a7a0dff8d2a30ea333d1348aa45df021b94e105081b8ef838c47a34f12e683ef4f41bff1a5461d4667a269154847f29c1f728323bb3ea52f1085a4c620794a3a9b8381874b8c3a8cd044d22a8f1bf790ebbb68ca2e4a10861901a7b43b9ed6d1340704b298187519a189a4551d37ef21d776d1945c94210c32034f68773dada2680e09653030ea33431348aa3a6fde43aeeda328b928421864069ed0ee7b5b44d01c12ca6061d46686269154746bcee00ab1a8d42a1d4a58c0039bc9d7a2f8e59d382738c1c3a8cd0d4d22a8e763b018c239b42b0c075ad977fd95bba9f23427377050158487519a1b9a4551cd53728a3149cad8cfdb7bdae7f1899f4e90aaaa6be0a1cf0a0ea33438348aa39932f76d0f69f8345783bdddc7d9716697cd97b0d4c14542151d4668716915473165eeda1ed3f068af077bbb8fb2e2cd2f9b2f61a9828a842a3a8cd0e2d22a8e6257f00cea7e435415dbbd9f175c23c259e2a11f500516ac557519a1c6a4551cc33bf27281d2e92ae384416626aea5acae71849a9d0a2efcabea33438e48aa398503f73db07c34d87ed548f44553a981578f4b9137145f9d58d466871d9154730907ee7b60f869b0fdaa91e88aa75302af1e97226e28bf3ab1a8cd0e3b22a8e6120fdcf6c1f0d361fb5523d1154ea6055e3d2e44dc517e7563519a1c764551cc241fb9ed83e1a6c3f6aa47a22a9d4c0abc7a5c89b8a2fceac6a33438ec8aa398483f73db07c34d87ed548f44553a981578f4b9137145f9d58d466871d9154730900afa0ebc5cfd929275e4b0a26b8e52ec95b482df8bf54f1b8cd0e3b32a8e611f15f41d78b9fb2524ebc96144d71ca5d92b6905bf17ea9e3719a1c766551cc23e2be83af173f64a49d792c289ae394bb256d20b7e2fd53c6e33438eccaa39847c57d075e2e7ec9493af2585135c729764ada416fc5faa78dc66871d99547308f83bb34472a63babdf2b11321eaf4356c4078a89f5bf5695b9cd0e3b33a8e611ef0378e19222d9da7622e88c3554e4d582bb576fe87eaecf749a1c766851cc23dd06f1c32445b3b4ec45d1186aa9c9ab0576aedfd0fd5d9ee93438ecd0a39847ba0de386488b6769d88ba230d55393560aed5dbfa1fabb3dd26871d9a147308f741bc70c9116ced3b1174461aaa726ac15dabb7f43f5767ba4d0e3b3428e611ee8378e19222d9da7622e88c3554e4d582bb576fe87eaecf749a1c766851cc23dd06f1c32445b3b4ec45d1186aa9c9ab0576aedfd0fd5d9ee93438ecd0a39847ba06a4abd358cd9204086e9354d2f9388a9821e561cabb58127871d9a157308f73f60a7d317f014c338da9892925585394db07f0836576ca6500e3b342be611ee7d4d61fedcb68c092981f74d1ca1689a960d406c69aedaf0a11c766858cc23dcf926d65666437a950ad0b4c231392f5d26c6c334d05db7854338ecd0b29847b9f14dacaccc86f52a15a1698462725eba4d8d8669a0bb6f0a8671d9a165308f73e2276bb245e44cd6e30f9930bcdb1b9c95c74f2f3e76dfb90de3b342cb611ee7c34ed7648bc899adc61f326179b637392b8e9e5e7cedbf721bc7668596c23dcf8629c121c46795de440b2aeaeb62cc9a51c97f18f6db8088388ecd0b2e847b9f0b53824388cf2bbc881655d5d6c59934a392fe31edb70110711d9a165d08f73e163316dfbe74b9fbc7f971d3a581909141d23ebfd86e03c4e33b342cbb11ee7c2b662dbf7ce973f78ff2e3a74b03212283a47d7fb0dc0789c67668597623dcf856586dd7a6a94a71d7b28d768dfca06d01f53d5b5eb810b78decd0b2ed47b9f0ab3cee07fa28f7666731e11513ef9f01fe96bd12ba7023131cd9a165db8f73e15505ee68a128514f863088521fd59c2bf7d9bc8171e047ca3ab342cbb81ee7c2a90bdcd14250a29f0c6110a43fab3857efb37902e3c08f9475668597703dcf855217b9a284a1453e18c221487f5670afdf66f205c7811f28eacd0b2ee07b9f0aa42f734509428a7c31844290feace15fbecde40b8f023e51d59a165dc0f73e15485ee68a128514f863088521fd59c2bf7d9bc8171e047ca3ab342cbb81ee7c2a9049df6cd1e08c737dddd06bf2a9e3a6f5e3d28a3908faeb5768597704dcf8551f1fd13250977b69b38866ffdd4a2575e673e7706f11f77aafd0b2ee0ab9f0aa3d3fa264a12ef6d36710cdffba944aebcce7cee0de23eef55fa165dc1573e1547a0b5721ef34502985ee62276d1ef3ff947be01db947df8ec042cbb82be7c2a8f316ae43de68a0530bdcc44eda3de7ff28f7c03b728fbf1d8085977057cf8551e62d5c87bcd140a617b9889db47bcffe51ef8076e51f7e3b010b2ee0af9f0aa3cc5ab90f79a2814c2f73113b68f79ffca3df00edca3efc7602165dc15f3e154798418477a01b651b16b2e89ec9e59e21426a4437917dfa90052cbb82bf7c2a8f2f0f1b47ed0d2cb8e53297658bc19a6a7f80cacb1ffbf6c40b5977057ff8551e5d1e368fda1a5971ca652ecb178334d4ff0195963ff7ed8816b2ee0afff0aa3cba3c6d1fb434b2e394ca5d962f0669a9fe032b2c7fefdb102d65dc15ffe154797404ec98153fc849e16181545603317bf6b298b4fcdfb7c45bcbb82c00c2a8f2e709d9302a7f9093c2c302a8ac0662f7ed653169f9bf6f88b7977058018551e5ce13b26054ff212785860551580cc5efdaca62d3f37edf116f2ee0b0030aa3cb9c2764c0a9fe424f0b0c0aa2b0198bdfb594c5a7e6fdbe22de5dc16006154797384ec98153fc849e16181545603317bf6b298b4fcdfb7c45bcbb82c00c2a8f2e7029a55b54cf6bbee3fcf0b2b85c8da6d0ff58fb98f6fa2f7a77058019551e5cdf534ab6a99ed77dc7f9e16570b91b4da1feb1f731edf45ef4ee0b0032aa3cb9be32a7c60014117e47c088f2d96894c33ea9a64a60dbea61eadc1600665479737b654f8c002822fc8f8111e5b2d129867d534c94c1b7d4c3d5b82c00cca8f2e6f656b170ad26a87bd6cee9f35d98b134f552db85806fab2bac7058019a51e5cdeb39753a0723b37a656a9a0eb327c091e551f966fddf57fb59e0b00335a3cb9bd572ea740e4766f4cad5341d664f8123caa3f2cdfbbeaff6b3c160066b479737aa71e740c965306c4d772e62c495606f8ff427f7f47d61916882c00cd78f2e6f536fe0da3fa0c35b52bb22ed81211f071a94924be5fac4c6d2058019b01e5cdea56bd40d2c17e9395d430c02fa389c362fd566f3c8f58b31a50b0033613cb9bd4963ba73050634f57252de2dec6796945a5710438eeb18074b160066c379737a9153873eb6e2cc6d9c728283d0c58b50af5a62e31ad631b2972c00cd87f2e6f5213320d61a9bfb5df0b1cb2f998174c95961082232ac65092f58019b10e5cdea416641ac3537f6bbe163965f3302e992b2c210446558ca125eb0033621cb9bd4825895b117464ffa7a93f2e65dfc314d603062e4c7b195c8be60066c449737a9033d3dbadb630277acf4abf4b3eec0c2bb0d08258c632d357dc00cd88a2e6f5205068dce639c677211b61e115fd3dfad70c652a715c65c0efc8019b1155cdea4090d1b9cc738cee4236c3c22bfa7bf5ae18ca54e2b8cb81df90033622ab9bd48121a37398e719dc846d878457f4f7eb5c3194a9c5719703bf20066c455737a9024346e731ce33b908db0f08afe9efd6b86329538ae32e077e400cd88aae6f5204868dce639c677211b61e115fd3dfad70c652a715c65c0efc8019b1155cdea40905dcc25206350c4ee908853f27253d61376973eb5cb838391033622ac9bd4811f47aaa2ed9d040c94edd6cfdcdb05d4219970d9689708ab23066c455a37a9023d1b679e88106a9be1a873c7b1ac69d03ddf240ece2e12fa470cd88ab56f52047936cf3d1020d537c350e78f6358d3a07bbe481d9c5c25f48e19b1156adea408f26d9e7a2041aa6f86a1cf1ec6b1a740f77c903b38b84be91c33622ad5bd4811e4674f4ced59b761c51064658559aca9e9a562d26e7099763966c455ac7a9023c75ab0f28789d14641ed8ef302a9b77bcdf70800d9e1349073cd88ab59f520478d41743dbbea050f3ba7e40dfd49cd1f969a525db0c26ac4e89b1156b4ea408f190efad424aa6ca12f1c8e43f289f86727e0e7175e84d72dd23622ad6ad4811e311df5a84954d9425e391c87e513f0ce4fc1ce2ebd09ae5ba46c455ad5a9023c623beb5092a9b284bc72390fca27e19c9f839c5d7a135cb748d88ab5ab520478c403e8f9d229c78c30b138478c46216139b37b16f126bb1292b1156b57a408f18707d1f3a4538f186162708f188c42c27366f62de24d762525622ad6af4811e30e0fa3e748a71e30c2c4e11e31188584e6cdec5bc49aec4a4ac455ad5e9023c61c1f47ce914e3c618589c23c62310b09cd9bd8b78935d8949588ab5abd20478c383e8f9d229c78c30b138478c46216139b37b16f126bb1292b1156b57a408f1870093192f20f5408cdf3cf1980ba8a4f311ba53a21d763f65722ad6af5811e30df126325e41ea8119be79e330175149e62374a7443aec7ecae455ad5eb023c61be24c64bc83d502337cf3c6602ea293cc46e94e8875d8fd95c8ab5abd60478c37c498c97907aa0466f9e78cc05d4527988dd29d10ebb1fb2b9156b57ac08f186f81f2b87cdcba30f9709b7c0039f031b0c6695fe1a764109732ad6af5911e30def3e570f9b97461f2e136f80073e063618cd2bfc34ec8212e655ad5eb223c61bde08c077e404eec113f3a52806726a942c469a5466d905c9cdab5abd65478c37bb1180efc809dd8227e74a500ce4d528588d34a8cdb20b939b56b57aca8f186f762301df9013bb044fce94a019c9aa50b11a69519b64172736ad6af5951e30deec4603bf202776089f9d2940339354a16234d2a336c82e4e6d5ad5eb2a3c61bdd81819d6ed254e93f70718a85f1d076abf15e7a26a905e40dbb5abd65578c37baf3033adda4a9d27ee0e3150be3a0ed57e2bcf44d520bc81b76b57acaaf186f75e60675bb4953a4fdc1c62a17c741daafc579e89aa4179036ed6af5955e30deebc4ce1101600d72270058b6af0de997df35b7f6f5182f3aadead5eb2acc61bdd7725d478d8d810c797d7dcfdd9b39123e163413aa005e8f9be5abd655a8c37baed4ba8f1b1b0218f2fafb9fbb3672247c2c68275400bd1f37cb57acab5186f75da23643c1036a5a1172c3a1f5ec4a2b7803947467d17a58afa6af5956b30deebb346c878206d4b422e58743ebd89456f00728e8cfa2f4b15f4d5eb2ad661bdd76619a348edb0f907147daea57308e905fb915f75f15e97cfeaabd655adc37baecb334691db61f20e28fb5d4ae611d20bf722beebe2bd2f9fd557acab5b86f75d96668d23b6c3e41c51f6ba95cc23a417ee457dd7c57a5f3faaaf5956b70deebb2c592ca01a5e2abb5bba3b53903da657d7373e0b87f4c023565eb2ad6f1bdd76573e6b98e192b7f96f413ccf1871aad7a91abe730ce981eaadbd655adf37baecad08e98a6ffbd275964f3fc628d9b3d74ce1bf4216d305795c7acab5bf6f75d95911d314dff7a4eb2c9e7f8c51b367ae99c37e842da60af2b8f5956b7edeebb2b223a629bfef49d6593cff18a366cf5d3386fd085b4c15e571eb2ad6fdbdd76564474c537fde93acb279fe3146cd9eba670dfa10b6982bcae3d655adfb7baecac81aaaffac9389dc1cc0c28a85919b9cc8c8367d6a305939c8acab5bf7f75d958f3555ff592713b8398185150b23373991906cfad460b273915956b7efeebb2b1e6aabfeb24e277073030a2a16466e732320d9f5a8c164e722b2ad6fdfdd76563c616a561172b1639dd2da7c24833b0e40edf6474e82cb7246655adfc0baecac774ee704cfbbc549f3727b2040fcd4447c882eea9a0598888dcab5bf8275d958ed29e0624c4ded169eb1bc6879f006b0f3bca031310b32b51c956b7f05ebb2b1d953c0c4989bda2d3d6378d0f3e00d61e77940626216656a392ad6fe0bd76563b23393e1de0e16dd3293b7c9dfb678ebc99ec320c12ccc787355adfc18aecac7636727c3bc1c2dba65276f93bf6cf1d7933d8641825998f0e6ab5bf8315d958ec65a61e0250ebdf7821ba54f76d041d721274edf01b33385ce56b7f063bb2b1d8b40d618f6f3de71bc0410c6e596e1d63cfae01a006668af9dad6fe0c876563b150dbe8a9abe1f662fd4e7b5c32421d474a2028ffdccd3033c5adfc191ecac76291b7d15357c3ecc5fa9cf6b864843a8e944051ffb99a60678b5bf8323d958ec5236fa2a6af87d98bf539ed70c908751d2880a3ff7334c0cf16b7f0647b2b1d8a46df454d5f0fb317ea73dae19210ea3a510147fee669819e2d6fe0c8f6563b14867fb0258b858e5b51b41842a387b6f44cc6b5bd9cd31d7c6adfc191fcac7628f5c085d5e47144e220349304c67550684451913b09a65538e5bf83240958ec51d44231369648b1efbd3588890c50835033674835e34cc4b1db7f064822b1d8a3914587f7f9f78c0af73773919806e9201192b62b9699a3a3c6fe0c905563b147128b0feff3ef1815ee6ee723300dd24023256c572d3347478dfc1920aac7628e25161fdfe7de302bdcddce46601ba480464ad8ae5a668e8f1bf83241558ec51c42ed654a9d2288833687ff0c3f9d2b803759d71c84cd375e47f06482bb1d8a3875daca953a4511066d0ffe187f3a57006eb3ae39099a6ebc8fe0c905763b1470e476bab541f04a3856ec5eb07dda9080882b8231e334f7b92fc1920afc7628e1b1ae9af55146bc9c2aa51fe07b1b0380bb1b2a23966a09b26f83241608ec51c3535d35eaa28d7938554a3fc0f6360701763654472cd41364df06482c11d8a386a6ba6bd5451af270aa947f81ec6c0e02ec6ca88e59a826c9be0c905823b1470d4635fd35579c0d0cd1f56183583dfe85839d76dc835067d38c1920b057628e1a752d1ff57c9e424520b725862fe1df8ab1ff1378d6a0e9e728324160bec51c34d31b6575c6a2acb5be3aad8bdf29a1950ec24cb17d41ee0e606482c18d8a38699636caeb8d45596b7c755b17be53432a1d849962fa83dc1cc0c905831b1470d3252ebb61e7f0db0275b718aefc0c68d3e5cd5885c507d27991920b064628e1a6331e9c4e9d47de30683a93dd777eb427765ed6cb5a0fbf333324160c9c51c34c563d389d3a8fbc60d07527baeefd684eecbdad96b41f7e6666482c1938a38698a53b96c54285a0ed1db6b1f55d60b31d843f80ed383f170cdc90583281470d313338531552716a05b839c66a3a2748bab343279a407e4859c920b065128e1a625670a62aa4e2d40b70738cd4744e917566864f3480fc90b3924160ca251c34c4a5a271e0172bd0425db37c286803056a77d0c428d1f93ba73482c1945a3869893406094afbbdc8b038335ad04f6bed549a65ae1173f2918e79058328c470d31250cd3820c4e1b98bed3318201e3dbd28df8f81e2b7e53d5d020b065198e1a624919a704189c37317da6630403c7b7a51bf1f03c56fca7aba04160ca331c34c492334e0831386e62fb4cc608078f6f4a37e3e078adf94f574082c1946638698924669c106270dcc5f6998c100f1ede946fc7c0f15bf29eae81058328cc70d31248594a7971b81c0ea4ffde4816341b50da3bc43eb4e53f01030b065199e1a6248f3ea74b90469aa001cc82b8245e94c9af23cad966ca7fa607160ca334c34c491d0960efcd6397c2bb65cb9840b387bb58f3d80eca9500f00f2c19466a8698923912c1df9ac72f8576cb973081670f76b1e7b01d952a01e01e58328cd50d3124722583bf358e5f0aed972e6102ce1eed63cf603b2a5403c03cb06519aa1a6248e44b077e6b1cbe15db2e5cc2059c3ddac79ec07654a807807960ca335434c491c8222155830fdeae6e297fac032ed9dd89e9c348a65010a4f3c19466a96989238f4442ab061fbd5cdc52ff58065db3bb13d386914ca02149e78328cd52d312471e1497aeb915dd3c7072c4d804b1c59e22534f7e96404437d006519aa6a6248e3b292f5d722bba78e0e589b009638b3c44a69efd2c80886fa00ca3354d4c491c76525ebae45774f1c1cb136012c71678894d3dfa590110df4019466a9a989238ec30cfce75854c663b62ece81d848b190d46be50af02236281328cd536312471d7619f9ceb0a98cc76c5d9d03b0916321a8d7ca15e0446c5026519aa6c6248e3ae4f519282eb941ba55879c86e088a8c2fc73b9eb9088f2e05ca3354d9c491c75b2ab57db2ad8aba027db9b8d40773405a3ab9996f1120000c9466a9b489238eb5556afb655b157404fb7371a80ee680b4757332de2240001928cd536912471d6a36e84f778c8d6ac1c3ad0b48142b29639728c1b94481a433519aa6d3248e3ad36dd09eef191ad583875a1690285652c72e51837289034866a3354da6491c75a667b3968b08982dbedb7a5518470acd8908e562e2120834ce466a9b4d9238eb4b5b7985c2e792de3583bad2288473c30cbe0d21c124120d9d8cd5369c2471d69543056432a5883f22d43bcc48ff45ae14285c9f7f4825bf3c19aa6d3948e3ad29121d2112217300fd753dc089f4e98422fcfb9afb904d22793354da7391c75a51243a422442e601faea7b8113e9d30845f9f735f7209a44f266a9b4e7238eb4a24874844885cc03f5d4f70227d3a6108bf3ee6bee413489e4cd5369ce471d69441cfb613de1fa8aa376b42c479daa4912941f33d9826ab7ca9aa6d39d8e3ad28739f6c27bc3f51546ed68588f3b549225283e67b304d56f95354da73b1c75a50e73ed84f787ea2a8ddad0b11e76a9244a507ccf6609aadf2a6a9b4e7638eb4a1c73ed629be636d7d382678a34e3b0708f4d3bfac913576255d5369ced71d6943773ed1de4a2d0325ed1953c61bdbf091946ba518f26b068acaa6d39dbe3ad286d73ec94761c02e7756ff0a0bb71dc3a2d39b6ff1b4d62755a54da73b8c75a50d973eb81990e6851a2aca7696eda169c551fb05a339ac68eb5a9b4e7728eb4a1b173e95bdef33325fd2614fad5aa8b60a4eba31064358ec16c5369cee61d69436173e5106abcc8ceb218f01da34b74e94483887cc56b1f26d9a6d39dcd3ad286c173dc79824ff4201bfea6633e8d47fa83b3535587d63ff1b44da73b9b75a50d8173cb4bb1764ac2efca12ee7510ee1d0212e9070cac8187699b4e7737eb4a1b0173a8f00fc2f8089760ec04e2183a61fed2146a165904b2d4369cee70d6943601736438cc5c5293e68e9e31bc26d2ebf8506b3029b20b09a96d39dce2ad286c0172daca458f07aa84ea028b704403ffeb4d18bc506417b753da73b9c65a50d80171c7ed37f471d7c1a0cb3ed87e6627d14673d49dc83112a8b4e7738db4a1b0016fa2331cbf46323b0e5ca5a8f32a779d392a05389063c95269cee71c694360016b56bee654eee72de97f7349dcb317351e96666e20c936a5d39dce39d286c00162bfd679804051139fc50e8bafc45664e96f28d94194114ca73b9c74a50d80015192059fd6e324df0c50450f55e6d4c47f20adaf8329c69a4e7738ea4a1b00012f3663ec8428cc75e566b216a22bd183aa83b75c065531359cee71d5943600015e6cc7d9085198ebcacd642d4457a30755076eb80caa626b39dce3ab286c000248ebe85ee705b48f6260f0527f0d6e095651396d195668d773b9c75750d800031dea296aa46debd69188089cf479040d58e4ced732ae75afe7738eafa1b000053bd452d548dbd7ad23101139e8f2081ab1c99dae655ceb5fcee71d5f4360000a03bafe57681a321212e64a6bc84238300fd59759cabb7ac09dce3abf86c000130775fcaed034642425cc94d7908470601fab2eb39576f5813b9c757f0d8000260eebf95da068c8484b9929af2108e0c03f565d672aedeb027738eafe1b00004c1dd7f2bb40d190909732535e4211c1807eacbace55dbd604ee71d5fc360000983bafe57681a321212e64a6bc84238300fd59759cabb7ac09dce3abf86c00013003722399d9a8c4fa298f7570fea52dfca6f547365770fc14b9c757f1d800025f06e44733b35189f4531eeae1fd4a5bf94dea8e6caee1f829738eafe3b00004be0dc88e6766a313e8a63dd5c3fa94b7f29bd51cd95dc3f052e71d5fc76000097c1b911ccecd4627d14c7bab87f5296fe537aa39b2bb87e0a5ce3abf8ec00012f83722399d9a8c4fa298f7570fea52dfca6f547365770fc14b9c757f1d800025f06e44733b35189f4531eeae1fd4a5bf94dea8e6caee1f829738eafe3b00004be0689b3f234093c14230a384379fa9a72469942992dc40a92f71d5fc77000097bf5d48d6f3578a053c2e0d306735b176437f6aaf22b882f65fe3abf8ef00012f7d46a4069385768d3028e088c661c11481ab17ba42710790c0c757f1df00025ef9195a65d3e14f9d181e873984b9e050fe0271d081e210c5828eafe3bf0004bdf132b4cba7c29f3a303d0e730973c0a1fc04e3a103c4218b051d5fc77e00097be26569974f853e74607a1ce612e78143f809c742078843160a3abf8efc0012f7c456e5874be0df6b78c0fff41dc560afeabfd0e00c1087d015757f1df90025ef8739dd6744982159a94ec61033811f87d02be41c152111442beafe3bf3004bdf0d73bace893042b3529d8c2067023f0fa057c8382a42228857d5fc77e60097be1a7387f5bf36e7e95d07de68c5fadc473b5bd2cc518446b4b0abf8efcd012f7c337322442b44325571dc82f983ec16b67163e7f4a0088f0d6257f1df9b025ef8657256e1035ec72d9b85cc1affce8b94dd7412453d111fbec5afe3bf3704bdf0c970c01ab393f0ddeed85e5df7937551b59466e6772241218c5fc77e6f097be1916d928e13fe443e957d82e3e71d48cb65d51028eb4483e719bf8efcdf12f7c321673774d4d2eaffe2c7cbefc630efbec65662add3890972347f1df9bf25ef86415a8142567c38827d5c5e0784583da5875907b7a412148869fe3bf37f4bdf0c814114dd59ced387b285823700a6d973095e51cb45242ab4d4fc77e6ff97be19010e3c13607409921cd7ca95f944110e0d68e5f28748570daaf8efce002f7c32011c7826c0e8132439af952bf288221c1ad1cbe50e90ae1b55f1df9c005ef8640238f04d81d02648735f2a57e510443835a397ca1d215c36abe3bf3800bdf0c80471e09b03a04c90e6be54afca2088706b472f943a42b86d57c77e70017be190086fd38eb416fba485496f878c376f08d13aa1847185727eb08efce003f7c3200f6bb976150459cbc25fa53710653c399d218564e00ae6a1621df9c008ef86401d638544d6df161a3c8c109618c0d69b34ef4d25bd15cee6c53bf38012df0c8039531ce25a948eb730e4e75429780b5e648adca7772b9f718b77e70026be190071324c1d61ff7ff1199694d04ae674e4c3c1fbaaeb57408717efce004e7c3200e164983ac3feffe2332d29a095cce9c98783f755d6ae810e2fdf9c009cf86401c25542ce34d462471e271969239031bb09b43107aa5d03c060bf38013af0c803833697f5167f2710f41af8fa3f16c19e0e14a46b51ba0924c27e700276e19007056d2fea2cfe4e21e835f1f47e2d833c1c2948d6a374124984fce004edc3200e0a66722d06d2fec68838aa10f45164a032fed40943e826370af9c009dc86401c1358f6b2ba7c600fc83e1a49e099276860a9ea6e84d04e1216f38013ba0c8038253dffbe21cf22a24848fabbb928acf8bc00173906a09dc82ee7002775190070490811d4f074a7c7485ebb9f6a47b81972ac70ce0a413d345ece004eeb3200e0911023a9e0e94f8e90bd773ed48f7032e558e19c14827a68bd9c009dd66401c122204753c1d29f1d217aee7da91ee065cab1c3382904f4d17b38013bacc8038244408ea783a53e3a42f5dcfb523dc0cb956386705209e9a2f670027759900704880d2fa7b420def73db8801e9c71dfbf25734f3ca113d4e9ede004eeb4200e090f1a5f4f6841bdee7b71003d38e3bf7e4ae69e794227a9d3dbc009dd68401c121e34be9ed0837bdcf6e2007a71c77efc95cd3cf2844f53a7b78013bad08038243c697d3da106f7b9edc400f4e38efdf92b9a79e5089ea74f6f002775a1007048785f0cd3eee451f69354c811bf145a1a51e136260e3d5042df004eeb4300e090ef4a2c008a9f066fde76564b761f125c9e6eaea8197aa229bf009dd68701c121dd206a59c2146f6274b972bee43482e137899fac2ff545f77f013bad0f038243b940d4b38428dec4e972e57dc86905c26f133f585fea8beefe02775a1e070487720dbbbfb528200c8ab2912388c869acd8d2c10cbcd51981fd04eeb43d0e090ee31b777f6a504019156522471190d359b1a5821979aa3303fa09dd687a1c121dc636eefed4a080322aca448e2321a6b3634b0432f3546607f413bad0f438243b8c6dddfda94100645594891c46434d66c6960865e6a8cc0fe82775a1e87048771867ce53ff58634b62f5d860847cf8f587d85327ca5199c3d14eeb43d1e090ee2f5baf00ab8729197db876e900f050130a5ce8ab91a3352ba39dd687a4c121dc5d43705a03e4b4b5b33db3f9f9d6fe4e0f6613b320466bfb483bad0f4a8243b8b912f30cb49fcbee1e482e1beba45ac4197869c23d8cd99a91775a1e960487717125e619693f97dc3c905c37d748b58832f0d3847b19b33522eeb43d2c090ee2e24bcc32d27f2fb87920b86fae916b1065e1a708f633666a45dd687a58121dc5c423aabe51d4c1f3aa0e370755193448c66f906de966ce788cbad0f4b1243b8b8747557ca3a983e7541c6e0eaa3268918cdf20dbd2cd9cf11975a1e9624877170e1abd51f4296a516005a2454c5b2f4b146a8413a29b3b8633eb43d2c590ee2e1b357aa3e852d4a2c00b448a98b65e9628d508274536770c67d687a58b21dc5c366af547d0a5a94580168915316cbd2c51aa104e8a6cee18cfad0f4b1643b8b86c61fce84e21b50db7f9d8525acfd8809e0062f911d9ddd5a05a1e962d877170d7500c294919cc9e27c076ccad960f2936ad084e20b3bd4f41b43d2c5c0ee2e1ad2c2aab3f09fbbf074db3c153227c7a680652f83e677c4284687a58b91dc5c3595855567e13f77e0e9b6782a644f8f4d00ca5f07ccef88508d0f4b1723b8b86b23cbd05a8fe517ed503952d448050119ac58e3cf69df2ae12a1e962e577170d63058c63fed3058061d3f08280f6fe4b30375ed5ea3be7002643d2c5cbee2e1ac50b18c7fda60b00c3a7e10501edfc96606ebdabd477ce004c87a58b97dc5c358a16318ffb4c1601874fc20a03dbf92cc0dd7b57a8ef9c00990f4b172fb8b86b142c631ff6982c030e9f841407b7f25981baf6af51df3801321e962e5f7170d62858c63fed3058061d3f08280f6fe4b30375ed5ea3be7002643d2c5cbee2e1ac503d9ed88737128ef24ad67816d6278e01981d19447ce1a8c97a58b97ec5c3589f075009bb4487a09c62731825a2ad43fddc7c8e85f9c4f593f4b172fe8b86b13d0ea01376890f4138c4e6304b455a87fbb8f91d0bf389eb27e962e5fd170d627a1d4026ed121e827189cc60968ab50ff771f23a17e713d64fd2c5cbfa2e1ac4f43a804dda243d04e31398c12d156a1feee3e4742fce27ac9fa58b97f45c3589e80112f4611edc8c7df3f7aa52213267d8740b445c9c50fd404b172fe9b86b13cf0225e8c23db918fbe7ef54a44264cfb0e81688b938a1fa80962e5fd370d6279e044bd1847b7231f7cfdea94884c99f61d02d11727143f5012c5cbfa6e1ac4f3c0897a308f6e463ef9fbd529109933ec3a05a22e4e287ea0258b97f4dc3589e78112f4611edc8c7df3f7aa52213267d8740b445c9c50fd404b172fe9b86b13cf0225e8c23db918fbe7ef54a44264cfb0e81688b938a1fa80962e5fd370d6279e044bd1847b7231f7cfdea94884c99f61d02d11727143f5012c5cbfa6e1ac4f3c0158c893c44a8c1b1c89b51088f921434b1e48a4b288044268b97f4dd3589e77f2b191278895183639136a2111f24286963c914965100884d172fe9ba6b13cefe563224f112a306c7226d44223e4850d2c792292ca201109a2e5fd374d6279dfc3876a28efba8904611a0b03c72eec9a03b66ae564403c5355cbfa6eaac4f3bf770ed451df751208c23416078e5dd934076cd5cac88078a6ab97f4dd5589e77ee6dece2e8c504c3d01348e8e9c2194e7b99dd15561010b8d672fe9babb13cefdb67ec1e7e606c0a57f357f9cb7a90c4f1dffc86a9202315ade5fd37586279dfb55bea95a9973a9767b3761b8eeb7fb1de6c3b694f4047cf5ccbfa6eb1c4f3bf6943e7840004d7b18733b25f15cd5d8bb784b92e9b809142ba97f4dd6489e77ed113e160ace011e5c6342ae62391193f69b5b4b934012429762fe9baca13cefda127c2c159c023cb8c6855cc4722327ed36b697268024852ec5fd37594279dfb424f8582b380479718d0ab988e4464fda6d6d2e4d00490a5d8bfa6eb284f3bf6842b1d5e13d6f1b0e96e1d59147f28234859e8259d0922efb27f4dd6519e77ed07563abc27ade361d2dc3ab228fe504690b3d04b3a1245df64fe9baca33cefda0e3887d0fc3229465d853b8c49f2feb51c13e2f271248d62cafd37594779dfb41b710fa1f864528cbb0a771893e5fd6a3827c5e4e2491ac595fa6eb28ef3bf68366e319c9d9f079c2de1b4591fc258fc6afbce25c192372f2cf4dd651ee77ed06b687591e81471bb13902eda377b1020d0a3dea7802470025ae9baca3ecefda0d55cfd7c7cff45f8deed23dc66ec7e699bf3ffaafd48e1a8b6d375947e9dfb41a9460d51a6d4ee7475a70de0c5cf5afb329441b1f791c4f56ea6eb28fe3bf68351182cfbfa803f6ba31ae1e98395141e5fd4c5bfec238b8ede4dd651fd77ed06a13059f7f5007ed74635c3d3072a283cbfa98b7fd847171dbc9baca3faefda0d4260b3efea00fdae8c6b87a60e5450797f5316ffb08e2e3b79375947f5dfb41a844d7a3880d85ddfd0a3d574149eff1af952705b5e1c5e1af36eb28fecbf6835072706c9ae871e425914711021345c5ded512312b938bdd9e7dd651fda7ed06a0d4e0d935d0e3c84b228e2204268b8bbdaa2462572717bb3cfbaca3fb4fda0d41a282d7f66f2db8c1c1e8a687cc7cf9faff0cea6e1e2f90ba075947f6afb41a833505afecde5b718383d14d0f98f9f3f5fe19d4dc3c5f21740eb28fed5f68350662cc85648a1d0b32846efc9eb159ca6ba6f7cf7848be5d282d651fdaced06a0cb5990ac9143a166508ddf93d62b394d74def9ef0917cba505aca3fb59da0d41963f33b1cf5da54f58e8854fa44cd0c2e46a363a0f2f98ee0c5947f6b4b41a832b0a79bc4b91ad21699dd0c7408fffadc380aed01b5f338019b28fed6a6835065514f37897235a42d33ba18e811fff5b87015da036be670033651fdad4d06a0caa29e6f12e46b485a677431d023ffeb70e02bb406d7cce0066ca3fb5a9a0d4195453cde25c8d690b4cee863a047ffd6e1c057680daf99c00cd947f6b5341a832a833ae1d65f1349951a9d29c00f6590432b72f5db2f339a59c28fed6a78350654f675c3acbe26932a353a53801ecb208656e5ebb65e6734b3851fdad4f06a0ca9e5acace449b34e7fe741097fbcfc238c588ffd2c8cce83a71a3fb5a9f0d41953b41a7f5360ccc52b4b4e757ef95e29985be42018e99d218e447f6b53f1a832a750f624318effb28213694d7d722235b0628c65f1a33a5d5c98fed6a7f350654e91ec48631dff650426d29afae4446b60c518cbe34674bab931fdad4fe6a0ca9d23d890c63bfeca084da535f5c888d6c18a3197c68ce9757263fb5a9fcd41953a407247174563bc3c1816ce6b10779002bf27554ce9d30524d7f6b53faa832a7470e48e2e8ac77878302d9cd620ef20057e4eaa99d3a60a49afed6a7f550654e8e1c91c5d158ef0f0605b39ac41de400afc9d5533a74c14935fdad4feaa0ca9d1c39238ba2b1de1e0c0b6735883bc8015f93aaa674e982926bfb5a9fd541953a387247174563bc3c1816ce6b10779002bf27554ce9d30524d7f6b53faa832a747070a087379ddafae7fa62fe18e57e2d78faecf5d0a60bedb0ed6a7f560654e8df6d53671c12187887c18c2429c15a82eca21c479e4c197f62dad4fead0ca9d1bd66b926e4fa9373c74fde704b79132dd3f07aeb399834a2c6b5a9fd5b1953a3795984a676cb896a466c83088ee88483a28d383270306ae98e6b53fab732a746f13f1ba59a6d755744a5cc3915c7672f3fc6b2c0dd60d7771dd6a7f56f654e8de10a49a3e1b14d3141185e9a23852c867a39a7ddb7c1b0923cad4feadfca9d1bc1149347c3629a628230bd34470a590cf4734fbb6f836124795a9fd5bf953a378229268f86c534c504617a688e14b219e8e69f76df06c248f2b53fab7f2a746f04524d1f0d8a698a08c2f4d11c296433d1cd3eedbe0d8491e56a7f56fe54e8de0830ac96c7eb3596c952afca3049268f9e46c037791b0ac7cbd4feadfda9d1bc0f61592d8fd66b2d92a55f9460924d1f3c8d806ef236158f97a9fd5bfb53a3781e4ec4b3cc8338dddd178550b91af86673c74339e16c2cc33053fab7f7a746f03b299bc045dcd43e71fbd0c96a2c4ef4e23ac8cfbfd85b2a61a7f56ff04e8de0755337808bb9a87ce3f7a192d4589de9c475919f7fb0b654c34feadfe09d1bc0ea328159c449b37c7fbc094da0a799fb8397659afc616e4d879fd5bfc23a3781d36502b3889366f8ff78129b414f33f7072ecb35f8c2dc9b0f3fab7f84746f03a65617bfbdfd3074b6bceb5e7a94c6160909d8c7ee85bada1f7f56ff09e8de074b3841d828d0c36c25469ce4ed1fea540cbff3ebda0b77583ffeadfe14d1bc0e957083b051a186d84a8d39c9da3fd4a8197fe7d7b416eeb07ffd5bfc29a3781d2a6d19b9501970334ce739bbac7607782dac120b652ddf0500fab7f85446f03a536645cb4d0942e9519b399f50e26d1856046672c75bbfae02f56ff0a98de074a5589def46e8e8555b03396699bb3858a6b50f418bb7810006eadfe1541bc0e9493d4e373aa8332d6dd338f52b6cced9481660df146f03a40ed5bfc2a93781d29106aec72226c8dd937338124ecffbda8ad9041a25de08ec1eab7f85536f03a5210d5d8e444d91bb26e670249d9ff7b515b208344bbc11d83d56ff0aa6de074a421abb1c889b23764dcce0493b3fef6a2b641068977823b07aadfe154dbc0e9484357639113646ec9b99c092767fded456c820d12ef04760f55bfc2a9b781d29086aec72226c8dd937338124ecffbda8ad9041a25de08ec1eab7f85536f03a521061eb3cf1af7e352633c871d1f5d97955ccc5a0b8c11f27d66ff0aa6ee074a41f4fe8d290355eed0434570b9be2111aa645cd9d6e823ff3addfe154dec0e9483d2be3fdcd41205cc035743f2fba805d4737dd96da04818b5cbfc2a9be81d2907957c7fb9a8240b9806ae87e5f7500ba8e6fbb2db4090316b97f85537d03a520f23ba24fe1dae3f5b8a29724b6e05f9d178bb8b7651207d173ff0aa6fb074a41e30356f8708c2a6e2911f47165b71d6229c3b3cac7241146e8fe154df70e9483c506adf0e11854dc5223e8e2cb6e3ac4538767958e48228dd1fc2a9bee1d29078a0d5be1c230a9b8a447d1c596dc7588a70ecf2b1c90451ba3f85537dc3a520f141ab7c384615371488fa38b2db8eb114e1d9e5639208a3747f0aa6fb874a41e28356f8708c2a6e2911f47165b71d6229c3b3cac7241146e8fe154df70e9483c506adf0e11854dc5223e8e2cb6e3ac4538767958e48228dd1fc2a9bee1d29078a061d074cfe0fe0cfc49e28165bdb6b26b99350dc604535e4085537dc4a520f13f4fb3424c985e9cb0608b2ac371cb8cd1deac778908a860820aa6fb8a4a41e27d2b78dd46071fbc188ddc7d7ed9f5419e699b4b0f11526505154df7159483c4f956f1ba8c0e3f78311bb8fafdb3ea833cd336961e22a4ca0a2a9bee2b290789f239f5cdc4f2e1731a04381df35e332e7452af8839454b38155537dc57520f13e373eb9b89e5c2e63408703be6bc665ce8a55f10728a96702aaa6fb8aea41e27c673e98fc0a1e84f1fdda69fc56f2ae1cbf7007ce2152e845654df715e483c4f8b73e5782e1a3320f788136782d4b3eb929a4355c12a5eacada9bee2bd90789f1573dd49090ac8c4a6dcecf6fd9fc5ff1fe0c9077f54befd5c537dc57c20f13e2973cceabeebf40c0586a015f335ea263a6dd46afba97f9eb9a6fb8af941e27c5173ac2e2aae4a9ac2da0653de6232746f87eb31f45300e1744df715f383c4f8a1736ab50232f7b83d80d2cfb4bac310d9bc18bfe5a60366e99bee2be80789f14172e7c2b13c51f332ce6bc7616be449ae2473dbc84c0871d437dc57d10f13e28171e1de0f4f06691d699db6bace26bb56f52a138d981287a96fb8afa31e27c5016fd614cb746f54f2a001956d92ab9ea8969683183026b353df715f473c4f8a016bbe8243bf412c9d0cc952d31bb5654bd96f622d604f0aa8bee2be8f789f1401638f5d3454e4dbf1e658cd9e2dc8f2925f212057c09fb9527dc57d1ff13e280153311315802c3a9b9977c33451f00d1f6a849cac814116a5fb8afa40e27c500132747ed7d6baf7eeffb5ae609a3e4239814b95560283d14cf715f482c4f8a00164e8fdafad75efddff6b5cc1347c847302972aac0507a299ee2be90589f1400255e4540c314e6273cb9ce17a5f5730e0b170b1550a10e934dc57d20c13e2800337db00c538ff479f63ffeaecb50c89bc0f23bea71423766ab8afa41927c500056fb6018a71fe8f3ec7ffd5d96a1913781e477d4e2846ecd5715f48324f8a000a6b7e5bc1ba5fa1355cc5d3aaca904eeae8d15699508f7dabe2be90659f140013630f10304b21c5228651cf4d8b7ec5d07de5092fa1209f58c57d20cc3e2800255230790d6ca60cfcd969c6930d5bb39ba80c6e5c4242e2b28afa41997c50004930734ac7afae9cb17f99b51e11158f31fc5b38b58487696615f48333f8a0009160e6958f5f5d3962ff336a3c222b1e63f8b6716b090ed2cc2be90667f14001224ddf83cb951cf57dcb2cfc703ab464c29daf3ed3121f499957d20cd0e280024327d16044009c6db3632020d86bc6f17fe7a0d9a324403733afa419a2c50004854fa2c0880138db66c64041b0d78de2ffcf41b34648806e675f4833458a00090a2b57d9bcd8d439855946ab59a579edfa4ac5c289910280cfbe90668c1400121356afb379b1a8730ab28d56b34af3dbf4958b85132205019f7d20cd18280024263971bfa039b368cd31e0d55e8c45dfe3d7596623440ba73ffa419a315000484b72e37f407366d19a63c1aabd188bbfc7aeb2cc4688174e7ff4833462a000909671d9572dbd3025ec94497d722775a78a09a7f48a10304100e90668c64001212b6fc5070850c2ce90f55922dc4549770ebf92451120622602d20cd18d800242556b9c66bd77e81fd9b7786db080f116182b66e61f40c5f006a419a31c000484a9634b2627c632c26b3bb70358f840542b0310283b818d840e483346390009095152a8a4fc62c8078e44342ea9e6ded050b262ac74031cac1d90668c73001212a13163a2a59bf291d4552e854bc41bc89c1107b4e5063afc3c20cd18e70024254162c7454b37e523a8aa5d0a9788379138220f69ca0c75f878419a31ce00484a8251a0e343462cca0921803d2706cd4a6af0612f9118ed94f18334639d009095032f541f3362bc16ca0fc6a24603f8bcd08d04bb1f31dccde40668c73b01212a055ea83e66c5782d941f8d448c07f179a11a09763e63b99bc80cd18e760242540a4962d57a6152dde00be0b11006411b3ce0554879c774db9119a31ced0484a8131ed803a199083e77e4878a1802e05e746cececf08eeb5b23334639db090950253db0074332107cefc90f143005c0bce8d9d9d9e11dd6b646668c73b61212a04a077267333a837c975ee4505801dfa1cc5ff60fbf3baf108dcd18e76d242540930ee4ce667506f92ebdc8a0b003bf4398bfec1f7e775e211b9a31ceda484a81261dc99cccea0df25d7b914160077e87317fd83efceebc423734639db49095024c3b933999d41be4baf72282c00efd0e62ffb07df9dd78846e68c73b69212a04980338cbe07e9a4c2dbb0b2d78145844c0aba357f0baf2acddd18e76d34254092f067197c0fd34985b76165af028b089815746afe175e559bba31ceda684a8125e0ce32f81fa6930b6ec2cb5e051611302ae8d5fc2ebcab3774639db4d095024bc19c65f03f4d2616dd8596bc0a2c226055d1abf85d79566ee8c73b69a12a04978338cbe07e9a4c2dbb0b2d78145844c0aba357f0baf2acddd18e76d34254092f067197c0fd34985b76165af028b089815746afe175e559bba31ceda684a8125e05a4550cc7cf58e268f9185fd0c6f58259518582bbcacdb75639db4d195024bbf409cfa45d04d9f04ebe933f20f3cd845d6730c54795b5aebc73b69a42a04977d0d4c4d3876fdc0c1a4988fdc14d7d886592874a5f2b859d88e76d34954092ef91a989a70edfb818349311fb829afb10cb250e94be570b3b11ceda692a8125df2353134e1dbf7030692623f70535f621964a1d297cae1676239db4d255024bbe46a6269c3b7ee060d24c47ee0a6bec432c943a52f95c2cec473b69a4aa04977c860d72c34463e8ed2164f25b943dbb0603ec9a65c2b874189e76d34964092ef8f4dc0b11562dfa05bf964736a7e1588bb29d5a8b557102714ceda692d8125df1d2793bad79c21c36fbf8f0eccf2893970ffedad67ae21f22a9db4d25c024bbe394f2775af384386df7f1e1d99e51272e1ffdb5acf5c43e4553b69a4b804977c722a61440b46e99076cb02632bc0830dbeabf9119bb8896cab76d34971092ef8e354c288168dd320ed9604c65781061b7d57f223377112d956eda692e2125df1c6359768d9f208c492f8cfb4a6f86a5ef55c26a26be22756aedb4d25c524bbe38b6b2ed1b3e4118925f19f694df0d4bdeab84d44d7c44ead5db69a4b8a4977c716626ffc149e859503b004fa93d807a3d01cdce5ac889efebc6d34971592ef8e2b50f250d6136dacbf2cd01d1fa66d6f9ae5fc2756113fa179da692e2c25df1c552df6fa58fd3ddc362666623743390730783aaaa92280e6f4b4d25c594bbe38a95bedf4b1fa7bb86c4cccc46e86720e60f07555524501cde969a4b8b2977c715243ee4210cb59f390665fb0d5034244bc8d2d06a18a053fd3d34971662ef8e2a313eedcce6d1669d8998589a1fce2b173c69c6940140c23a8a692e2cd5df1c54527ddb99cda2cd3b1330b1343f9c562e78d38d280281847514d25c59abbe38a8a4fbb7339b459a76266162687f38ac5cf1a71a50050308ea29a4b8b3577c715142b893f203f15d17c98f27507dd73b398e125a5fda062c1463497166bef8e2a2757127e407e2ba2f931e4ea0fbae76731c24b4bfb40c5828c692e2cd7df1c544e3a37552dd2b9c8aa308ffc176c2cf65e30d8f3f3818ca919d25c59b0be38a89b008103087bd6140c2de62026ceb814b70df443e4031af634a4b8b3627c71513501020610f7ac28185bcc404d9d70296e1be887c80635ec69497166c4f8e2a26a02040c21ef585030b798809b3ae052dc37d10f900c6bd8d292e2cd89f1c544d404081843deb0a0616f31013675c0a5b86fa21f2018d7b1a525c59b13e38a89a808103087bd6140c2de62026ceb814b70df443e4031af634a4b8b3627c71513501020610f7ac28185bcc404d9d70296e1be887c80635ec69497166c4f8e2a26a02040c21ef585030b798809b3ae052dc37d10f900c6bd8d292e2cd89f1c544d404081843deb0a0616f31013675c0a5b86fa21f2018d7b1a525c59b13e38a89a800d156128ac768ee5b2e64ec6ae72df08a08640001af7d8a5b8b3627d715134ff1a2ac25158ed1dcb65cc9d8d5ce5be11410c800035efb14b7166c4fae2a269fe345584a2b1da3b96cb993b1ab9cb7c22821900006bdf6296e2cd89f5c544d3fc68ab094563b4772d973276357396f84504320000d7bec52dc59b13eb8a89a7f85d686b379dcb7112fb2b1462dd8c1884b4a65bfeaf7f2e5c8b3627d815134fef46e32f1c11f964ddc31c50bdb1765904158f13fa5f0000ba166c4fb12a269fdd19d8b6e4fa554c7352fec973594ada02d76083f1be01a5752cd89f63544d3fb933b16dc9f4aa98e6a5fd92e6b295b405aec107e37c034aea59b13ec6a89a7f726762db93e95531cd4bfb25cd652b680b5d820fc6f80695d4b3627d8d5134fee45ad80fd4a90ce65264bc7392c0b4f81167467b8af00ecfaa66c4fb1ba269fdc741c27856287c4f5c963f0f1d77c8181d7acf5312e01f4355cd89f63844d3fb8d0f974959275b2170f9444632e5ee5835a1e10222c0402aac9b13ec7189a7f7191f2e92b24eb642e1f2888c65cbdcb06b43c20445808055593627d8e3134fee323e5d25649d6c85c3e51118cb97b960d68784088b0100aab26c4fb1c6269fdc6408cca376113b8e3f96e8598f25d0e9a7bb4a6d130202f965d89f638d4d3fb8c7119946ec22771c7f2dd0b31e4ba1d34f7694da260405f2cbb13ec71a9a7f718e23328dd844ee38fe5ba1663c9743a69eed29b44c080be597627d8e3534fee31c46651bb089dc71fcb742cc792e874d3dda5368981017cb2ec4fb1c6a69fdc63818dc900dea1b66b13b4bc0ea536cc27660e92d2d20313a5e89f638d5d3fb8c6f31b9201bd436cd62769781d4a6d984ecc1d25a5a406274bd13ec71aba7f718de63724037a86d9ac4ed2f03a94db309d983a4b4b480c4e97a27d8e3574fee31bc52f6d91c273db841a7242f4a91c43badb38bc566018b76f54fb1c6af9fdc637732000ae524ddf33b1b0e868d19e69f561359e6c9031891eb9f638d603fb8c6ed640015ca49bbe676361d0d1a33cd3eac26b3cd92063123d73ec71ac07f718dda5412844169da4fa43900422c5df8a552f9a9f7210c63ebaf7d8e3581fee31bb33437612faa1722003ec6ac50b24f72a09f964a3f18c97b5ffb1c6b04fdc63765686ec25f542e44007d8d58a1649ee5413f2c947e3192f6bff638d609fb8c6eca5cefdd6b7ebf0ab8c7e0d93abf9bf27d2a9b84f963279180ec71ac14f718dd9345f21383d3e098295c87da6d75960cf5017965efc650c702d8e3582aee31bb2517f67fb47e23b30a85d5dcd2e18a41e4af3527dc8ca33206b1c6b056dc6376492fecff68fc4766150babb9a5c31483c95e6a4fb91946640d638d60adb8c6ec925fd9fed1f88ecc2a1757734b86290792bcd49f72328cc81ac71ac15b718dd9244bc65650c7801b0bfb750e8f02b0372025eb9ae1651b34368e3582b7e31bb247239f054e6562b8cfc3b04515fbbe963af81991bfca380c6e1c6b0570c637648d473e0a9ccac5719f87608a2bf77d2c75f033237f947018dc38d60ae18c6ec91a1a8e6de66bed65f6db873c4fe55880e68ca8a2fc28e1d5b971ac15c418dd9233351cdbccd7dacbedb70e789fcab101cd195145f851c3ab72e3582b8831bb24666a39b799afb597db6e1cf13f9562039a32a28bf0a38756e5c6b05710637648cc6085c7e035cdb26ea9000a7721222f2f118773de471051cc8d60ae21c6ec91974d1de86d41fde7951ec63ce638a28658cf5143b98e22479a1ac15c448dd9232d264e29875a5e51e20a52a1c467a334ac4ae4e3701c4633353582b88a1bb246594c9c530eb4bca3c414a54388cf46695895c9c6e0388c666a6b05711437648cb2254afeca3fdbca3ff610af0994eafaabd7d5e9bd711a70d5d60ae2296ec919634a95fd947fb7947fec215e1329d5f557afabd37ae234e1abac15c452dd9232c6213e53d5d5d1abb7a508e41e4a0a12aa0b9a02f2c46b6758582b88a6bb24658b427ca7ababa3576f4a11c83c94142554173405e588d6ceb0b057114d7648cb16110ba8042da9319660e9b8711e8672a2daaa67c811af416260ae229bec91962b221750085b52632cc1d370e23d0ce545b554cf90235e82c4c15c4537d9232c56442ea010b6a4c65983a6e1c47a19ca8b6aa99f2046bd058982b88a6fb24658ac146f98ce43ac0f6ad413eb80ea91bd1181959a3d8d7baf14057114e0648cb15728df319c87581ed5a827d701d5237a23032b347b1af75e280ae229c0c91962ae51be63390eb03dab504fae03aa46f446065668f635eebc5015c453819232c55c2f8f1f1ef3c2fe0e6d6583ff4aec1086b8ef2de96bdf1ca12b88a70424658ab75f1e3e3de785fc1cdacb07fe95d8210d71de5bd2d7be394257114e0848cb156e4a4ed528a56e7af1825c37f5220e6a158fff13a2af7e1685ae229c1191962adb20b002fe213f789ad17e97e23a7afc25cc4083425efdd10c5c453824232c55b5416005fc427ef135a2fd2fc474f5f84b98810684bdfba218b88a70484658ab6a0ed264a55b60652312c08780e04a1891dd4469067bf8e8327114e0918cb156d31da4c94ab6c0ca4625810f01c0943123ba88d20cf7f1d064e229c1231962ada63b4992956d81948c4b021e03812862477511a419efe3a0c9c453824632c55b4c02a57dd7b165abd062ca63fef8aeec899665a430dfc8e59488a7048d658ab697054afbaf62cb57a0c594c7fdf15dd9132ccb4861bf91cb29114e091acb156d2e0a95f75ec596af418b298ffbe2bbb226599690c37f239652229c1235962ada5c152beebd8b2d5e8316531ff7c577644cb32d2186fe472ca44538246b2c55b4b82a57dd7b165abd062ca63fef8aeec899665a430dfc8e59488a7048d658ab697054afbaf62cb57a0c594c7fdf15dd9132ccb4861bf91cb29114e091acb156d2e03571ce992fcd76d07f5f27b622194a6045ab6834f23b092329c1235a62ada5bf6ae39d325f9aeda0febe4f6c443294c08b56d069e4761246538246b4c55b4b7e61d9931195985df9ca42c6d07ec3517bc2effcd0c8edc88da7048d6a8ab696fb4fc57ed001933eab614bb598f3e4caf23222559e91dd351c4e091ad6156d2df52b9d564cd989000e8f5d9329de27bddf1087073a23bc0e399c1235ad2ada5be9573aac99b312001d1ebb2653bc4f7bbe210e0e7447781c7338246b5a55b4b7d23a87b1e03c8682f20a3c749f6efd1f76ee5e78e58ef1dce77048d6b5ab696fa30121bc6d4f6f889be13f1136d45866e888ff4dc81de55dcfe091ad6c56d2df45024378da9edf1137c27e226da8b0cdd111fe9b903bcabb9fc1235ad8ada5be8a0486f1b53dbe226f84fc44db51619ba223fd37207795773f8246b5b15b4b7d14090de36a7b7c44df09f889b6a2c3374447fa6e40ef2aee7f048d6b62b696fa28121bc6d4f6f889be13f1136d45866e888ff4dc81de55dcfe091ad6c56d2df45024378da9edf1137c27e226da8b0cdd111fe9b903bcabb9fc1235ad8ada5be8a0486f1b53dbe226f84fc44db51619ba223fd37207795773f8246b5b15b4b7d1401cf08f548e26d0a86c4ec36222919c3f2be9400bf2b08bf148d6b62c696fa27f39e11ea91c4da150d89d86c44523387e57d28017e56117e291ad6c58d2df44fe73c23d52389b42a1b13b0d888a4670fcafa5002fcac22fc5235ad8b1a5be89fc7396d351479907fb2f3c43090aeb09f40b8c5c5c9586038b46b5b1644b7d13f7733fff4f659492ae2b3eae0a0c343be2c35b14b62b0dab178d6b62c996fa27ed7292574ba18ba8142343840c0ec69fc032f88569561cfa301ad6c5942df44fd9713707441979d2e0134d301013eb677b123366cfac3b986135ad8b295be89fb16e80673509562877f36088181e34f6f0d0a9299c5878d4c36b5b1653b7d13f6169132716e90ed3a7b387382832c815dc4d94af35b0f34d87d6b62ca86fa27ec15e38a6daa8802a0733d498485bee53b3476bba6861e83f10ad6c5951df44fd814883a6622762d6c6346f5888ae3acf613b19d0cdc3d222225ad8b2a4be89fb011d19a5712528304435a4d90952d3c6bd2275fd9887a5e845b5b1654a7d13f6013a334ae24a5060886b49b212a5a78d7a44ebfb310f4bd08b6b62ca94fa27ec020078ee716b0343c8a3598c1d41ad42ef361a525f1e994517d6c5952af44fd80300f1dce2d606879146b3183a835a85de6c34a4be3d328a2fad8b2a55e89fb00601e3b9c5ac0d0f228d66307506b50bbcd869497c7a65145f5b1654abd13f600c03c7738b581a1e451acc60ea0d6a1779b0d292f8f4ca28beb62ca957a27ec018078ee716b0343c8a3598c1d41ad42ef361a525f1e994517d6c5952af44fd80300f1dce2d606879146b3183a835a85de6c34a4be3d328a2fad8b2a55e89fb00601e3b9c5ac0d0f228d66307506b50bbcd869497c7a65145f5b1654abd13f600c03c7738b581a1e451acc60ea0d6a1779b0d292f8f4ca28beb62ca957a27ec01800500ca17d9a64b5b26524539a3a11730c694bb1b9946bbd7c5952af54fd802ff0a01942fb34c96b64ca48a7347422e618d297637328d77af8b2a55ea9fb005fe1403285f66992d6c994914e68e845cc31a52ec6e651aef5f1654abd53f600bfc280650becd325ad9329229cd1d08b98634a5d8dcca35debe2ca957aa7ec017f8500ca17d9a64b5b26524539a3a11730c694bb1b9946bbd7c5952af54fd802ff02c2b9ba80b2bee1c970ecf2c6a810e137ed9bf7028d91ef9b2a55eaafb005fdf585737501657dc392e1d9e58d5021c26fdb37ee051b23df3654abd55f600bfbe3cc0c74d03123b2a290164a9a0626048a7a959bda3661fe7ca957aacec017f7b0593e746dc86f90c1ec8f14b3722e88bfb950f7846cde3d0952af55ad802fef50b27ce8db90df2183d91e2966e45d117f72a1ef08d9bc7a12a55eab5b005fdea164f9d1b721be4307b23c52cdc8ba22fee543de11b378f4254abd56b600bfbd42c9f3a36e437c860f6478a59b917445fdca87bc2366f1e84a957aad6c017f7a8593e746dc86f90c1ec8f14b3722e88bfb950f7846cde3d0952af55ad802fef503e8f41886741a43ba5e4515edabb397a1ee44b05d9be1e13a55eab5c005fde9f0930dbbda4e5cb2f188ecab5abd49aeeea0af208b37de0284abd56b900bfbd3d1261b77b49cb965e311d956b57a935ddd415e41166fbc050957aad72017f7a7a24c36ef693972cbc623b2ad6af526bbba82bc822cdf780a12af55ae402fef4f44986dded272e5978c47655ad5ea4d777505790459bef014255eab5c805fde9e81f20148724bf35a955b2d352b3a7d6e94cf17c8837dfa685abd56b910bfbd3cf3e40290e497e6b52ab65a6a5674fadd299e2f9106fbf4d0b57aad72217f7a79e0892aac9695f595d23917542c4fd839fe0084e1ddf803e17af55ae452fef4f3b11255592d2beb2ba4722ea8589fb073fc0109c3bbf007c2f5eab5c8a5fde9e76224aab25a57d65748e45d50b13f60e7f802138777e00f85ebd56b914bfbd3cec4495564b4afacae91c8baa1627ec1cff004270eefc01f0bd7aad72297f7a79d8153d05436c58188a05dd7c24463661f8acc73ddaf805857bf55ae453fef4f3af2a7a0a86d8b031140bbaf8488c6cc3f1598e7bb5f00b0af7eab5c8a7fde9e75e54f4150db16062281775f09118d987e2b31cf76be01615efd56b914ffbd3cebc35fa82c839234707fbb2091a281137c0127c4ad4c02dcfe0aad722a0f7a79d776bf5059072468e0ff764123450226f8024f895a9805b9fc155ae4541ef4f3aee63fc63cdbaef9ed7bb8e4c6096a306faf633875000b8e383ab5c8a84de9e75db540b20484c41c06743e2c0b923a435f098a96a9d01736b0856b9150abd3cebb53428993d6ee60386548ba96a3da693dbdd95313702e87a11ad722a167a79d7696851327addcc070ca91752d47b4d27b7bb2a626e05d0f4235ae4542cf4f3aed25cb4bda291fa90d11ef4cda0ecf8776a229720d90ba38c47b5c8a85ae9e75da3457bd3f1fa57a45a0aafc339d04f16cef1709daf1748bc906b9150b6d3cebb45170a0090cb11cb6be225ae6b96fc55988f23975b2e931d21d722a16ea79d76892e140121962396d7c44b5cd72df8ab311e472eb65d263a43ae4542dd4f3aed125c2802432c472daf8896b9ae5bf156623c8e5d6cba4c74875c8a85ba9e75da2444625d332ef0de16ddf39b54ae40d4bf255f16d6749a8d0fb9150b763cebb44714d7131334443ee588ad5ea152dfd178f70089a9e936be20722a16ed79d7688d29ae262668887dcb115abd42a5bfa2f1ee011353d26d7c40e4542ddaf3aed11a535c4c4cd110fb9622b57a854b7f45e3dc0226a7a4daf881c8a85bb5e75da23432caf146788479e412311d028d5cb3c26446a94c49b795049150b76ccebb44676595e28cf108f3c824623a051ab96784c88d5298936f2a0922a16ed99d7688ce573e1dc6b8746a48158a9c022bd0f7043d5d012e26dff8134542ddb43aed119b3a8e943a474b5747f7db5ffc4e00160326fc5e594dc194278a85bb6975da2335012f812164f93147bc7ce7f0925e5400fa3b18af9b84cc50150b76d3ebb44669025f0242c9f2628f78f9cfe124bca801f476315f370998a02a16eda7d7688cd204be048593e4c51ef1f39fc249795003e8ec62be6e133140542ddb4faed119a4097c090b27c98a3de3e73f8492f2a007d1d8c57cdc266280a85bb69f5da2334812f812164f93147bc7ce7f0925e5400fa3b18af9b84cc50150b76d3ebb44669025f0242c9f2628f78f9cfe124bca801f476315f370998a02a16eda7d7688cd204be048593e4c51ef1f39fc249795003e8ec62be6e133140542ddb4faed119a4023d2e95f52fb26960b3a204125882877c9ceb3cac267cc0b85bb69f6da23347f47a5d2bea5f64d2c167440824b1050ef939d679584cf98170b76d3edb44668fe1b5dfe2a224f1d0ff9aea8fc8c7ec9d9d37d2b2809a0d42f16eda7dc688cd1fb36bbfc54449e3a1ff35d51f918fd93b3a6fa56501341a85e2ddb4fb8d119a3f66d77f8a8893c743fe6baa3f231fb27674df4aca0268350bc5bb69f71a23347ec670249fde8db6b379a3b6fdc5a5476c9482bb53d4d084579b76d3ee444668fd75a16eca8a8195927013d07b0ab07158d3c99c6779a122ef46eda7dc988cd1fad404031fe26953505cf4037594c6c53152575e8ec342601e9ddb4fb94119a3f590c92bca9238cecc36b4696aa8f36ce24f72e2dd5684da7d4bb69f72923347eb1192579524719d986d68d2d551e6d9c49ee5c5baad09b4fa976d3ee524668fd62324af2a48e33b30dad1a5aaa3cdb3893dcb8b755a1369f52eda7dca48cd1fac46495e5491c67661b5a34b55479b67127b9716eab426d3ea5db4fb94919a3f588553e233f0f314eee812f92a0e9cb0a4a1f25395384dc214cb69f72933347eb0f368e9f2af4c52094cf254d39c9f43c8eea8ccea409b9e69a6d3ee527668fd61d6d1d3e55e98a41299e4a9a7393e8791dd5199d481373cd34da7dca4ecd1fac3a664cd558a977050b095b5cdf1e2f1a365675968d26e93e6ab4fb949e9a3f587358ac035e29508ccddf7ce1b632bc5c67592d89174dd420d669f7293e347eb0e53d6a5f6929039c538bbfeb645bd6e0c95e9d6e2b9ba9e5add3ee527d68fd61c906e7177f2869bb5ee445fec0ae0be98d697d385437556f5ca7dca4fbd1fac3910dce2efe50d376bdc88bfd815c17d31ad2fa70a86eaadeb94fb949f7a3f587221b9c5dfca1a6ed7b9117fb02b82fa635a5f4e150dd55bd729f7293ef47eb0e443738bbf9434ddaf7222ff605705f4c6b4be9c2a1baab7ae53ee527de8fd61c886e7177f2869bb5ee445fec0ae0be98d697d385437556f5ca7dca4fbd1fac391068f54891e399ee945586000db7db59a7dbe96683eaaf8f95fb949f7b3f58721f5dfce9d09d965fe077d228136614db4a64152904d560c32cf7293ef77eb0e43d480c2c4e118f4278bc6a781ec287de8f746cae06aac32a5aee527deffd61c8791c2ab148f98107a9459b18357b6de519951bb80a5587f8b6dca4fbe0fac390f138556291f3020f528b36306af6dbca332a377014ab0ff16db949f7c1f58721e270aac523e6041ea5166c60d5edb79466546ee029561fe2db7293ef83eb0e43c46d67e2f4a26ac001f99ee9a3d1cd50c755201c4fac4169b7e527df08d61c878766e21e961b3802bbc003fb3f99f8c9895682949c58847770ca4fbe12ac390f0d59d695d90cd2882f4cce1e772a4fbb0d59478535b10a92e2949f7c2658721e193fbf845ef0079316666264e64afd9e155ed166686216c9c6293ef84db0e43c310b91616ab671a8e4998af1c48c59642569e528cdc42f378d527df09c61c878611722c2d56ce351c93315e38918b2c84ad3ca519b885e6f1aa4fbe138c390f0c22e4585aad9c6a392662bc71231659095a794a33710bcde3549f7c2718721e1845c8b0b55b38d4724cc578e2462cb212b4f29466e2179bc6a93ef84e30e43c30845286f583d7d110165754440bbf46a514a94e8d942f51cd627df09c71c87860f1663375d515ca4ba97b0b0796e46fc9d416c2daf85ebddad4fbe138f390f0c1d2cc66ebaa2b949752f6160f2dc8df93a82d85b5f0bd7bb5a9f7c271e721e183a598cdd75457292ea5ec2c1e5b91bf27505b0b6be17af76b53ef84e3ce43c30743f2c13976147a88c8a4babc368960ce4b7a3c9792f60916b7df09c7ac87860e70a6a7fdb98f1d3d0e15d7f7ec78a41c41b89eeef5ec2c6d7fbe138f690f0c1cd14d4ffb731e3a7a1c2bafefd8f1483883713dddebd858daff7c271ed21e1839a29a9ff6e63c74f438575fdfb1e2907106e27bbbd7b0b1b5fef84e3da43c307345353fedcc78e9e870aebfbf63c520e20dc4f777af61636bfdf09c7b487860e6832ba5666657fbfc5e29e1fe46f02443c64e14af2ec2e1180be138f6a0f0c1ccf6574accccaff7f8bc53c3fc8de048878c9c295e5d85c23017c271ed41e18399e56fbb2466c6181cf573ea789b26738ec3fc787c8b0b9ea03f84e3da93c30733b3a09bd39af2586567b43770b5b2c99d32bd16b8e61757808f09c7b537860e6750025d32034ad8f64c34d160eacb75ba103e53319c2ec9412e138f6a7f0c1cce9004ba640695b1ec9869a2c1d596eb74207ca663385d92825c271ed4fe18399d200974c80d2b63d930d34583ab2dd6e840f94cc670bb2504b84e3da9fc30733a4012e9901a56c7b261a68b07565badd081f2998ce1764a09709c7b53f860e6748025d32034ad8f64c34d160eacb75ba103e53319c2ec9412e138f6a7f0c1cce9004ba640695b1ec9869a2c1d596eb74207ca663385d92825c271ed4fe18399d200974c80d2b63d930d34583ab2dd6e840f94cc670bb2504b84e3da9fc30733a4012e9901a56c7b261a68b07565badd081f2998ce1764a09709c7b53f860e6748025d32034ad8f64c34d160eacb75ba103e53319c2ec9412e138f6a7f0c1cce9004ba640695b1ec9869a2c1d596eb74207ca663385d92825c271ed4fe18399d200235ed97f8ca015c5011e62aad3ccac0a410ec308b251ef85e3da9fc40733a3ff46bdb2ff19402b8a023cc555a7995814821d861164a3df0bc7b53f880e6747fe198dbeab08e2d9cbd13fb2a34590d823b07d681fc94962188f6a7f111cce8ffb331b7d5611c5b397a27f65468b21b04760fad03f9292c4311ed4fe22399d1ff66636faac238b672f44feca8d1643608ec1f5a07f252588623da9fc44733a3fec58804e051d79511656c3bd1222e4e918302d9cfb4a4cb4c57b53f889e6747fd73d12f4b7115524e47a4da21c3c27fa2b0c9d95f3949b0d8bf6a7f114cce8ffad0638421af90ccc80c1616c306eae1c50c57d87e42937bf18ed4fe22a99d1ff590c708435f219990182c2d860dd5c38a18afb0fc8526f7e31da9fc45533a3feb218e1086be43332030585b0c1bab8714315f61f90a4defc63b53f88aa6747fd6431c210d7c86664060b0b61837570e2862bec3f2149bdf8c76a7f1154ce8ffac8638421af90ccc80c1616c306eae1c50c57d87e42937bf18ed4fe22a99d1ff590531a9c0bf7fc12cff8f3ae05cc21b2135bf3588226f9871ea9fc45543a3feb1f324790c4c65aa857bead84038ea18c2164290d014df4b23e53f88aa9747fd63d648f21898cb550af7d5b08071d431842c8521a029be9647ca7f11552e8ffac7a55309bbfefcd2416c77c380630e458803ce6900237d46cfa4fe22aa6d1ff58f33673902cb5fccae55bbe98045826d8fb260f7c016faa7df59fc4554ea3feb1e56ce720596bf995cab77d3008b04db1f64c1ef802df54fbeb3f88aa9d47fd63ca65e0995fae55ae4d3bc0880956f98be744804c02beab9bd77f11553b8ffac79357d38b6c330ddf524447380aa4513fc93542f4027d58dbaffe22aa781ff58f253bb96f853c7e415c5554980d3f00a78d16c84401fab35b60fc4554f13feb1e49038537b74f5f0570776f5812745f7714d9d2e400f5685ac2f88aa9e37fd63c91070a6f6e9ebe0ae0eedeb024e8beee29b3a5c801ead0b585f11553c6ffac79220e14dedd3d7c15c1ddbd6049d17ddc53674b9003d5a16b0be22aa78dff58f2441c29bdba7af82b83bb7ac093a2fbb8a6ce972007ab42d617c4554f1bfeb1e48838537b74f5f0570776f5812745f7714d9d2e400f5685ac2f88aa9e37fd63c91070a6f6e9ebe0ae0eedeb024e8beee29b3a5c801ead0b585f11553c6ffac792206d604680ae23ded5a89c2c950e3bed3120fb5c3a5a1854bf22aa78e0f58f243f66d2e5ae32aa40631dfe812212d6025cee391471b4324d7f4554f1c2eb1e487d59b824093bb7037e08c32a3c1c0a2cb488b484e068663eff8aa9e386d63c90f93f82a0bf4dd089b3de4c7c702e728163bdab65bdd0ce22001553c70eac7921f10b179a2b7203961f895f20d853432ac227992778a19de8012aa78e1e58f243e1162f3456e4072c3f12be41b0a68655844f324ef1433bd002554f1c3cb1e487c22c5e68adc80e587e257c83614d0cab089e649de28677a004aa9e387963c90f8458bcd15b901cb0fc4af906c29a1956113cc93bc50cef4009553c70f2c7921f083d8bfb63f69be4b062b8357d2a90d41d25d4d38719e02413aa78e1e68f243e0f072a4f74c39a4c18923692f24b7fd034f7ec030b33c1ec2854f1c3ce1e487c1d0e549ee987349831246d25e496ffa069efd806166783d850a9e3879c3c90f83a1ca93dd30e69306248da4bc92dff40d3dfb00c2ccf07b0a153c70f387921f07439527ba61cd260c491b497925bfe81a7bf6018599e0f6142a78e1e70f243e0e872a4f74c39a4c18923692f24b7fd034f7ec030b33c1ec2854f1c3ce1e487c1d0715c474549ac05ca1398864166582e99a9c2bd63783f290b9e3879c4c90f839f6ecae73769ba8e4bf3f7347ac30e852dffc7d6c3f07ff6183c70f38a921f073d69a8271ba9d79f4fb4b490ed7c7b3256abd20984e101903178e1e716243e0e795f62a6e42a11c157362f49d2ef548ca803e66f06c204c463f1c3ce2d487c1cf14ad7a6752a8605663924bb9dd507414ab40f3a0a840b2cc8e3879c5b90f839e121c1a5972b6e8d843f0f9f33a06caa901460d0120817fd92c70f38b821f073c143834b2e56dd1b087e1f3e6740d9552028c1a024102ffb258e1e717043e0e7821318ef09841cb8c8c904a4c67810d23afdc59c4520619a4c1c3ce2e187c1cf032631de13083971919209498cf021a475fb8b388a40c334983879c5c30f839e064c63bc261072e32324129319e04348ebf71671148186693070f38b861f073c0c24d9d0f8f74848fe14eb4e2bb6e4b9d29a6f3e26030e7661e1e7170d3e0e781749b3a1f1ee9091fc29d69c576dc973a534de7c4c061cecc3c3ce2e1a7c1cf02e1f799c90b383a6b0207360a6d1f10f4515ff54950c3b7d88879c5c35f839e05b3ef3392167074d6040e6c14da3e21e8a2bfea92a1876fb110f38b86bf073c0b609f8caefa4711d784e93aa933e22650f043fae5130ef9a231e7170d8e0e7816b13f195df48e23af09d2755267c44ca1e087f5ca261df34463ce2e1b1c1cf02d627e32bbe91c475e13a4eaa4cf889943c10feb944c3be688c79c5c363839e05ac4fc6577d2388ebc2749d5499f113287821fd7289877cd118f38b86c7073c0b582b9f07a71d745a3cb600d12bd88478eaf03d41100efb4632e7170d8f0e7816af573e0f4e3ae8b4796c01a257b108f1d5e07a82201df68c65ce2e1b1e1cf02d5e3a8e77494c33ebaaa4c96ca758700ba66d37603d3beebccc9c5c363d39e05abb012f473f6eca5a0d16590146a73e3f4786b11c7777df1d9a38b86c7b73c0b575025e8e7edd94b41a2cb2028d4e7c7e8f0d6238eeefbe3b347170d8f6e7816aea04bd1cfdbb2968345964051a9cf8fd1e1ac471dddf7c7668e2e1b1edcf02d5d4097a39fb7652d068b2c80a3539f1fa3c3588e3bbbef8ecd1c5c363db9e05aba812f473f6eca5a0d16590146a73e3f4786b11c7777df1d9a38b86c7b73c0b575025e8e7edd94b41a2cb2028d4e7c7e8f0d6238eeefbe3b347170d8f6e7816aea04bd1cfdbb2968345964051a9cf8fd1e1ac471dddf7c7668e2e1b1edcf02d5d4023b5f8643b8f8942f946cb4b957dcbbe04d097b8ef90711d5c363dbae05aba7f476bf0c8771f1285f28d96972afb977c09a12f71df20e23ab86c7b75c0b574fe1aea3a3dc4a0a7c3b1e155264c5556f2bf84bae0be43687670d8f6ec816ae9fb35d4747b89414f8763c2aa4c98aaade57f0975c17c86d0ece1b1edd902d5d3f66ba8e8f712829f0ec785549931555bcafe12eb82f90da1d9c363dbb205aba7ec63642a9afb67c0d55bd0d12a5908df90a8683302f21ce7b486c7b7650b574fd752daade2cd3204628467ca4ca86fe71bfd12c202e43b736a0d8f6ecb16ae9fad31c7b47270c68b7cd595bc91473df632a667e002c8788ad51b1edd972d5d3f59638f68e4e18d16f9ab2b79228e7bec654ccfc00590f115aa363dbb2e5aba7eb253312a76997cb0ab231d1a3d135600c545e1dc0821e3cf556c7b765db574fd633274ad9a095be40e13005c721d0a29853806140d43c942abd8f6ecbc6ae9fac564e95b3412b7c81c2600b8e43a14530a700c281a87928557b1edd978d5d3f58a55e50f14fbd212f018c799c06a86ce0f8c5aac320f26aeb063dbb2f2aba7eb1337dc76d6ce06a897fe555b78cb6bc419c4f7b4611e4f0161c7b765e6574fd6256fb8edad9c0d512ffcaab6f196d7883389ef68c23c9e02c38f6ecbccae9fac4a6b8434080e7d2517c61b95db240d3861c0212d81793da9881edd979a5d3f5893631ac0bcf35ccce758fd53ae3e7898be2c84b6fff27cf7113dbb2f35ba7eb1255247da26bd1c1c867ec0cf54734f5977054bc9fce4fb92237b765e6c74fd624930a20cfa509abbc4ca47c6a0dcfcdae8b6d9eff6c9f8c847f6ecbcd9e9fac491614419f4a1357789948f8d41b9f9b5d16db3dfed93f1908fedd979b3d3f589224e9a8c9618cd71caf5e5427b6a51939d87aa1bd827e4c520dbb2f368a7eb1243294771d907fd664db890aceecb014f35bb9693ad4fcb2e42b765e6d24fd62485528ee3b20ffacc9b712159dd96029e6b772d275a9f965c856ecbcda49fac490a31302010f6581beeaf08dbb3226364d19a9caab23f2e5d0bdd979b4a3f58921362604021ecb037dd5e11b76644c6c9a3353955647e5cba17bb2f36947eb1242650d2d8f0afc2f27288e996c47febbb4116b506c5fcbb1830765e6d29fd62484b2db80a8e35e8679cde995580f6359e7cd9ac6988f977d461ecbcda54fac490955b70151c6bd0cf39bd32ab01ec6b3cf9b358d311f2efa8c3d979b4a9f589212a42f282e5ae04212b472b7dfbcf34a1ee12f40220e5e0f588b2f36954eb12425311f75e78326ac50e5b1d23ef94c76bd6d22a603ecbc38f1265e6d2aad62484a523eebcf064d58a1cb63a47df298ed7ada454c07d97871e24cbcda555ac49094a47dd79e0c9ab14396c748fbe531daf5b48a980fb2f0e3c49979b4aab589212941bcd4c6e69b8ab2aa5af47749c9986b13d955df35e1e1c942f369557b1242527379a98dcd37156554b5e8ee939330d627b2abbe6bc3c39285e6d2aaf62484a4e6f3531b9a6e2acaa96bd1dd272661ac4f65577cd78787250bcda555ec490949c6a7cbc202427dc0cfa40639cdb2a5d8498ed4b97f0f288a279b4aabe89212937610bd0ed1eb23ad1c146ef31acb2e303de1cf32ce1e6b545f369557e1242526d4e29fa8713c6f85b4f54065b4fc3ee02687c4256c3cf0e8ce6d2aafd2484a4d928664dbafdf0736e6b6e34ae95e603ff7d3ae0aa879fc11acda555fb490949b150cc9b75fbe0e6dcd6dc695d2bcc07fefa75c1550f3f82359b4aabf6921293622dab8f98ce2450717a7efab24df637f8a12ddea71e80a86c369557ee242526c35b571f319c48a0e2f4fdf5649bec6ff1425bbd4e3d0150d86d2aafdc484a4d8642c097100ef3c47db6c212c12e3707dd30f9d6997a0445b1da555fb990949b0b119386ccf44a0bb33a4a4d7a52cc37b50e36092ff40a2f64b4aabf742129361523270d99e894176674949af4a5986f6a1c6c125fe8145ec969557ee842526c2a464e1b33d1282ecce92935e94b30ded438d824bfd028bd92d2aafdd084a4d85418ae8f1478b2e0519f1893ca8cbfe5a31df2a57ca0531f26a555fba20949b0a7315d1e28f165c0a33e312795197fcb463be54af940a63e4d4aabf7441293614e62ba3c51e2cb81467c624f2a32ff968c77ca95f2814c7c9a9557ee882526c29c5186d1509bf98544c58ac64c5c5d55139bd787e2029a9d362aafdd114a4d85372f1ffb4e0e558d4157dbb490af18d221e3f16bc10536de6d555fba23949b0a6d5e3ff69c1cab1a82afb769215e31a443c7e2d7820a6dbcdaaabf7447293614da489245e50fb8b7bd2c34fa3ab2c170823c080b0114dd1db6557ee88f526c29b31d36e476f5d3f23225301c6d5be108ff245271ff29bbdf6daafdd11fa4d853653a6dc8edeba7e4644a6038dab7c211fe48a4e3fe5377bedb55fba23f49b0a6ca00edea88adb24b80618699ad65e24bf73d8c23f9a6f121b7abf7447f93614d9301dbd5115b649700c30d335acbc497ee7b1847f34de2436f57ee88ff26c29b2603b7aa22b6c92e01861a66b597892fdcf6308fe69bc486deafdd11fe4d85364c076f54456d925c030c34cd6b2f125fb9ec611fcd37890dbd5fba23fc9b0a6c980edea88adb24b80618699ad65e24bf73d8c23f9a6f121b7abf7447f93614d9301dbd5115b649700c30d335acbc497ee7b1847f34de2436f57ee88ff26c29b2603b7aa22b6c92e01861a66b597892fdcf6308fe69bc486deafdd11fe4d85364c003079d03af8842e89012feaae7842399725458d078927fd6fba23fcab0a6c97f060f3a075f1085d12025fd55cf084732e4a8b1a0f124ffadf7447f95614d92fe0c1e740ebe210ba2404bfaab9e108e65c9516341e249ff5bee88ff2ac29b25fc183ce81d7c4217448097f5573c211ccb92a2c683c493feb7dd11fe5585364bf83079d03af8842e89012feaae7842399725458d078927fd6fba23fcab0a6c97f060f3a075f1085d12025fd55cf084732e4a8b1a0f124ffadf7447f95614d92fe04df99998b8733cdbd185d2b1d7670e574158901b24a199bfe88ff2ad29b25fbf28058bde4748fc6f6fd1cd5ba52c44a92ef37c334944d780d11fe55b5364bf7d500b17bc8e91f8dedfa39ab74a5889525de6f8669289af01a23fcab6a6c97efa2c288825f38674758c0d5d668b0f3a9f68104cca25150204447f956e4d92fdf35851104be70ce8eb181abacd161e753ed02099944a2a040888ff2adc9b25fbe63cb47944a47c548dfcfb9d92229b12784c838f259455ac1211fe55ba364bf7cb057b4b361f5b2bd3c6bd631c3b944ceb45497a4828acfc2523fcab756c97ef950af6966c3eb657a78d7ac638772899d68a92f4905159f84a47f956ead92fdf2a15ed2cd87d6caf4f1af58c70ee5133ad1525e920a2b3f0948ff2add5b25fbe542bda59b0fad95e9e35eb18e1dca2675a2a4bd2414567e1291fe55bab64bf7ca857b4b361f5b2bd3c6bd631c3b944ceb45497a4828acfc2523fcab756c97ef9503b7bbf70c1c7fd30a4728b7f68e7c5635571a50215a128a57f956eae92fdf29f0309d78e59f27d1915ab3ef6c82db2c15725a6012b43f54bff2add5e25fbe53d0613af1cb3e4fa322b567ded905b6582ae4b4c025687ea97fe55babc4bf7ca7a0c275e3967c9f46456acfbdb20b6cb055c969804ad0fd52ffcab757897ef94f4184ebc72cf93e8c8ad59f7b6416d960ab92d30095a1faa5ff956eaf12fdf29e8309d78e59f27d1915ab3ef6c82db2c15725a6012b43f54bff2add5e25fbe53d0613af1cb3e4fa322b567ded905b6582ae4b4c025687ea97fe55babc4bf7ca7a04e883c435301c8fd3795e5aa01cad85075abdc47d0fef700cab7578a7ef94f3f2922d1337c6614b23bf1f34bf9f3d89b979a148ca1ff9202956eaf15fdf29e7d5245a266f8cc296477e3e697f3e7b1372f34291943ff24052add5e2bfbe53cfa309d9d7ac7fad580bc8df527de2d8a690aaaae2f87ffec0b55babc58f7ca79f3613b3af58ff5ab01791bea4fbc5b14d215555c5f0fffd816ab7578b1ef94f3e64e88ce97f64dd8babefdfc976f14519ed6ed14bb2001542e56eaf164df29e7cb2923f5dcc2fe342d4ac22126d486cb385a1c857340044c5dadd5e2cabe53cf955247ebb985fc685a9584424da90d9670b4390ae6800898bb5babc5957ca79f2a30a2301fe25b536cf7ceac93487954dc14b471ca0012d577b7578b2bf94f3e536144603fc4b6a6d9ef9d592690f2a9b82968e3940025aaef6eaf1657f29e7ca64e9b192c5fcfd06bac00da4518437b6aff142325004cf9dfdd5e2cb0e53cf94b29488b059602238f24c7dc8226e51ed0aa6aa247009b97c0babc5962ca79f2955291160b2c04471e498fb9044dca3da154d5448e01372f817578b2c594f3e52a313484c32e6b10f45fe59a0091f2a33d55ece51902700303eaf1658c29e7ca53626909865cd621e8bfcb340123e5467aabd9ca3204e00607d5e2cb1853cf94a650e46bb9900ec6894c5c8ffa3e28b4f003f5f06109c1b010abc59631a79f294b2ddb301ff6800fca657f47ec72af91dab42e3cbf13850422578b2c644f3e52955bb6603fed001f94cafe8fd8e55f23b5685c797e270a0844af1658c89e7ca52a437f192cb062c1e162c347a9c11c6f657cfb4ef94e15b48a5e2cb1923cf94a5313108b063728067a924cb74b789706c5a638f9ef9c2d0d15bc59632579f294a52621160c6e500cf524996e96f12e0d8b4c71f3df385a1a2b78b2c64af3e5294a4c422c18dca019ea4932dd2de25c1b1698e3e7be70b43456f1658c95e7ca52942496b0de8fa2b68c5f2be253bb165e27de0a2b79e16a0caee2cb192ccf94a527492d61bd1f456d18be57c4a7762cbc4fbc1456f3c2d4195dc59632599f294a4e1e6d1c2714ed5ce94975b146e2b7a09a246b09e485a9d6bc8b2c64b43e52949b3cda384e29dab9d292eb628dc56f413448d613c90b53ad791658c9687ca5293605c6c9492a17f65cf29ced13813caa633dee838f16a8fef32cb192d1f94a526b0b8d9292542fecb9e539da27027954c67bdd071e2d51fde6596325a3f294a4d6171b2524a85fd973ca73b44e04f2a98cf7ba0e3c5aa3fbccb2c64b47e52949ac2e364a4950bfb2e794e7689c09e55319ef741c78b547f799658c968fca5293585c6c9492a17f65cf29ced13813caa633dee838f16a8fef32cb192d1f94a526b044eb81d219614e562063ca681df374626a12cddfd521826696325a40294a4d5f15e95c5109251f640d8dbcc8324510bf8067f7bcaa44a8ce2c64b48152949abd2bd2b8a2124a3ec81b1b7990648a217f00cfef795489519c58c96902a529357a57a5714424947d903636f320c91442fe019fdef2a912a338b192d2054a526af43b5d3b351f8b7dd839340e398886adf6af8219e25226ea726325a40b94a4d5e702cccf1715797e683f2e446b076b83e80b468fc1a44f78e5c64b48182949abcd05999e2e2af2fcd07e5c88d60ed707d0168d1f83489ef1cb8c9690305293579a0b333c5c55e5f9a0fcb911ac1dae0fa02d1a3f06913de397192d2060a526af34166678b8abcbf341f97223583b5c1f405a347e0d227bc72e325a40c14a4d5e682cccf1715797e683f2e446b076b83e80b468fc1a44f78e5c64b48182949abcd05999e2e2af2fcd07e5c88d60ed707d0168d1f83489ef1cb8c9690305293579a03f461e7234c21cc7985742b9d13f21fd7de64c6613dfdd7292d2060b526af33f0a9e95913fe6bc46fd74ad6b98dc6bf5a80ef4c927c15ee625a40c17a4d5e67d153d2b227fcd788dfae95ad731b8d7eb501de9924f82bdcc4b48182f49abccfa2a7a5644ff9af11bf5d2b5ae6371afd6a03bd3249f057b989690305e935799f454f4ac89ff35e237eba56b5cc6e35fad4077a6493e0af7312d2060bd26af33e835fbb1c0d4ce4727a410feb18424e7552d31a88f7c1792635a40c17b4d5e67cf6bf76381a99c8e4f4821fd630849ceaa5a63511ef82f24c6b48182f69abccf9e64011fb0299b9f565d0a22be06f1c54f6108fe3af05fed8e690305ee35799f3b5414980d2999c16486da6d740441b2996e545872e0c17f1dd2060bdd6af33e75343b88c729960580da7b02dffee18d2d88eb0ce2c184a23ca40c17bbd5e67ce96877118e532c0b01b4f605bffdc31a5b11d619c58309447948182f77abccf9d25d007bc97cba98bb36b23377f1e45cb0cfee8f8806142cf390305ef05799f3a34613503fcfd7b42e3a2a8ee7da26e15c4c1f7b0d0c29fde82060bde1af33e7451838f92c7611eb14411b45c7aaabeab34481521718559fd140c17bc45e67ce893071f258ec23d62882368b8f5557d5668902a42e30ab3fa28182f788bccf9d1260e3e4b1d847ac51046d171eaaafaacd1205485c61567f450305ef11799f3a244dda221086f1db59d5a056354bbd7d94d04cecb5c2aea28b060bde23f33e744727c69ccde446396b7806d4628dd923244cdc3568855ee9170c17bc48e67ce88d4f8d399bc88c72d6f00da8c51bb2464899b86ad10abdd22e182f7891ccf9d11a2b2ccbe4677b6865ace179822dc2b48bdfb3319f157d485d305ef12499f3a233565997c8cef6d0cb59c2f3045b856917bf66633e2afa90ba60bde24933e7446638c5883e7450244e804c0e00ad68fa2a2b0f227955f6c575c17bc49367ce88cb718b107ce8a0489d00981c015ad1f454561e44f2abed8aeb82f78926cf9d11966f2879a6a7a313f1cdf65ffaac0210a3587ee5e257dcb9d805ef124e9f3a232b6a634bfa25a8aa9b68b2e7ed4e6249415d4027c1afbb17b10bde249e3e74465560d8f0a121b3d7ee9e2bf7d29322ba7d66c2ab805f77d36317bc493d7ce88ca94dc439ef19ca3295091e179d1ca39cf579c7b2fdbef14ac72f78927bf9d11951279acc8b09f6e7e1df0257322fa561e59fd1c1f87de4398f5ef124f8f3a232a14f35991613edcfc3be04ae645f4ac3cb3fa383f0fbc8731ebde249f1e74465422a7d8ad8fe3e223f48cf84c0b4f3af912b8963def7928a3e7bc493e4ce88ca8354fb15b1fc7c447e919f098169e75f225712c7bdef25147cf78927c99d11950636088410cf5b0bb4f0043afaca2ce63f5a67eb78de4bccfaef124f943a232a0b6c1108219eb61769e00875f59459cc7eb4cfd6f1bc9799f5de249f2874465416643468f013ceb18b8cd713e31f11c0f815e209e07930d7ecbc493e51e88ca82b547b2a8cfdffe5cee6744fbe3481a9ead8066fbdf26353da78927ca4d11950553508adc6d2624e5599aec7745f617bd05c4f3b78e4c84bb5f124f94aa232a0a96a115b8da4c49cab335d8ee8bec2f7a0b89e76f1c990976be249f2954465415260350fc81febbc0e338145c973e4173c1d7f49e09322d2d8c493e52b88ca82a34c7c783d1639fad433c8b38ade265672e740efbe264749b28927ca5811950545250b492702d6786034578f0db2aad4e07ac43b794c903766124f94b1232a0a894a16924e05acf0c068af1e1b6555a9c0f58876f299206ecc249f296246541512203f7d48e1bc64389e24642ec1097b7c975349e232428199493e52c58ca82a23407efa91c378c8713c48c85d8212f6f92ea693c464850332927ca58b195054460d104dd05d54139a4557b8b2fa8415ed098f8385c90baa6624f94b1732a0a88b1a209ba0baa827348aaf7165f5082bda131f070b921754cc49f2962e654151163441374175504e69155ee2cbea1057b4263e0e17242ea99893e52c5cca82a22c68826e82eaa09cd22abdc597d420af684c7c1c2e485d533127ca58b9950544585d1735b2aba3bc5c2241b3279e9f86cb453a945990bc4a634f94b1742a0a88af4640c4122da9fb7011498e47339d359136b784b0217a38c79f2962e95415115d1893e0d131b67997ef5944865d98931d19b1655d42f615903e52c5d3a82a22b93127c1a2636cf32fdeb2890cbb31263a3362caba85ec2b207ca58ba750544572624f8344c6d9e65fbd65121976624c7466c595750bd85640f94b174ea0a88ae450b15f3664164f7747904c2ae322c0e379cd86e717b25082f2962e9e415115c72d7517199e8f21a65be6c04dbca3a9c19fdd69cb2f664506e52c5d3d82a22b8d5aea2e333d1e434cb7cd809b794753833fbad3965ecc8a0dca58ba7b0544571a41e6b513509f09513c61292ee8eccf012bb80329bd9ab81c94b174f70a88ae330fdfc2d377a0955a45887a55c837c5fd03b262507b37143a2962e9ef15115c651fbf85a6ef412ab48b10f4ab906f8bfa0764c4a0f66e287452c5d3de2a22b8ca3f7f0b4dde8255691621e95720df17f40ec98941ecdc50e8a58ba7bc544571940b106f4893672d89f909faa6381c57e2c9d56e80d9ba45d24b174f79a88ae3271620de9126ce5b13f213f54c7038afc593aadd01b3748ba4962e9ef35115c64e2c41bd224d9cb627e427ea98e0715f8b2755ba0366e917492c5d3de6a22b8c9c58837a449b396c4fc84fd531c0e2bf164eab7406cdd22e9258ba7bcd445719383d194d360cd55b575d65d25b7823a6274999440a9ba60125b174f79b88ae326f0644f318f00d39668791ccaee6a574493f74e412374da64c62e9ef38115c64dd0c89e631e01a72cd0f23995dcd4ae8927ee9c8246e9b4c98c5d3de7022b8c9ba1913cc63c034e59a1e4732bb9a95d124fdd39048dd3699318ba7bce045719374322798c78069cb343c8e6577352ba249fba72091ba6d3263174f79c08ae326e8644f318f00d39668791ccaee6a574493f74e412374da64c62e9ef38115c64dd054b0bbcad809af88beffbdd4cb0cb1229adede43e9b66d8d5d3de7032b8c9b9f3573d0428675e1c94ac5a3a18c778a3fe2001884d36e7f1bba7bce075719373d6ae7a0850cebc392958b474318ef147fc4003109a6dcfe3774f79c0eae326e7a61e199b6f03a09dcf7dcb67e283c50fa3442be104dbba06fe9ef381e5c64dcf34fd58c1ab6d69671bc7f94f446d6c9ef14c7d81d9b78e4e0d3de703db8c9b9e52bbd70e2440faf9b45c551e0840bbbd8d5d20c3836f36dc2a7bce07c719373c9577ae1c4881f5f368b8aa3c1081777b1aba418706de6db854f79c0f8e326e7923b081c35e6a14124e3db6f7a068d175e038a8cdddbcf5b0b9ef381f2c64dcf2302229118a3a50501947d06ec037856b6b35775b8b7a05a183de703e68c9b9e4504452231474a0a0328fa0dd806f0ad6d66aeeb716f40b4307bce07cd19373c8a088a44628e94140651f41bb00de15adacd5dd6e2de816860f79c0f9a326e7914111488c51d28280ca3e837601bc2b5b59abbadc5bd02d0c1ef381f3464dcf2282229118a3a50501947d06ec037856b6b35775b8b7a05a183de703e68c9b9e4504452231474a0a0328fa0dd806f0ad6d66aeeb716f40b4307bce07cd19373c8a014b69ed5bfa3c31cec07e2f8d473d5a7821fca2ae8182a1079c0f9a426e7913f296d3dab7f478639d80fc5f1a8e7ab4f043f9455d0305420f381f3484dcf227e52da7b56fe8f0c73b01f8be351cf569e087f28aba060a841e703e6909b9e44fc31c74f5ad3809b9f2d053fbe99fcd536bd40ad5440c2f484ce07cd22373c89f7638e9eb5a701373e5a0a7f7d33f9aa6d7a815aa88185e9099c0f9a446e7913ee532f96182464f13480db26f25e517cd5a145114e030d7614381f3489dcf227db327184dd1f2c6520ce7c75dcb30121a5eecc7e99061c9029703e6914b9e44fb564e309ba3e58ca419cf8ebb96602434bdd98fd320c392052e07cd22973c89f6a55d86c215314173b06b7ff6ac262ae92677456611873e4a6c0f9a453e7913ed337c330ef7c8ab12dda3626cd7b23851f7b2b08bf30e96d4e81f348a8cf227da56f8661def915625bb46c4d9af6470a3ef656117e61d2da9d03e691519e44fb4a6b1f1c6ac88d476f359ec32de2ec3c7898ee7ef9c3a7593b07cd22a43c89f69362509182677d11963803ae53bc36a0ebde1f59f0875056770f9a45497913ed2550b37bb1a55ca5e43ccd849f6ecb69d268810fde0ea250ef1f348a93f227da492d795010211bce8046613136d3f4fb9f7d447bb91d4645df3e691528e44fb4915af2a02042379d008cc2626da7e9f73efa88f7723a8c8bbe7cd22a51c89f692241f798ed5ad1bcb8e64aecd346321678a1544ae1751abb7df9a454a4913ed24310018a878c05fc29995c019e82c254ebeeeaf1bfea371afcf348a94a227da4852003150f180bf85332b8033d0584a9d7ddd5e37fd46e35f9e691529444fb490a40062a1e3017f0a66570067a0b0953afbbabc6ffa8dc6bf3cd22a52889f692140c1eace93692640497a634ec0c70cf5a2399e9fc51ba7be89a454a5213ed2427183d59d26d24c8092f4c69d818e19eb44733d3f8a374f7d1348a94a427da484e307ab3a4da4990125e98d3b031c33d688e67a7f146e9efa2691529484fb4909c60f56749b4932024bd31a76063867ad11ccf4fe28dd3df44d22a52909f6921384dfd27403f88c301472976b8bd6b1d9ce5e0fbc21ba9628aa454a5223ed2426f280ca72d557408ba5b19156971346334780453813754691648a94a457da484dd50194e5aaae81174b6322ad2e268c668f008a7026ea8d22c9152948afb4909ba2c44f5622c32a5a1392a7d9dbb2fb4cc8c53aa01dd53485a22a52916f69213735889eac458654b427254fb3b765f699918a75403baa690b4454a522ded2426e63d262e35872d193cb1701e6ee31cfb2cdd910404754ec5698a94a45cda484dcb065eb517e4bcb5312fa664d5bc981e5467646405ea9f2ed4152948bab4909b950cbd6a2fc9796a625f4cc9ab79303ca8cec8c80bd53e5da82a5291756921372a197ad45f92f2d4c4be999356f26079519d919017aa7cbb5054a522ead2426e5432f5a8bf25e5a9897d3326ade4c0f2a33b23202f54f976a0a94a45d5a484dca865eb517e4bcb5312fa664d5bc981e5467646405ea9f2ed4152948bab4909b95057e8fba96df928ddc192c2af8961f28798cedcba53e77e83a52917579213729f3be44fffb254d4734febad5709220d09dde01571a7d0a1084a522eb02426e53d03daf8ac3b0c2b9e6c9d82a608a2420e680286e04fa2e61194a45d61484dca7907b5f1587618573cd93b054c1144841cd0050dc09f45cc232948bac2909b94f20f6be2b0ec30ae79b2760a9822890839a00a1b813e8b984652917585213729e41ed7c561d8615cf364ec153045121073401437027d17308ca522eb0a426e53c83daf8ac3b0c2b9e6c9d82a608a2420e680286e04fa2e61194a45d61484dca79007716e3437e7f68560767cb90aa669c7ac933806f45e6633948bac2a09b94f1f0ee2dc686fcfed0ac0ecf972154cd38f5926700de8bccc672917585413729e3e1dc5b8d0df9fda1581d9f2e42a99a71eb24ce01bd17998ce522eb0a826e53c7c3b8b71a1bf3fb42b03b3e5c855334e3d6499c037a2f3319ca45d61504dca78f803293bf054e1eb0dd42df388a0c4c4757575dc6c45e8073a48bac2a19b94f1ef065277e0a9c3d61ba85be711418988eaeaebb8d88bd00e74917585433729e3de0ca4efc15387ac3750b7ce22831311d5d5d771b117a01ce922eb0a866e53c7bc1949df82a70f586ea16f9c45062623ababaee3622f4039d245d6150cdca78f783293bf054e1eb0dd42df388a0c4c4757575dc6c45e8073a48bac2a19b94f1ef065277e0a9c3d61ba85be711418988eaeaebb8d88bd00e74917585433729e3de0566154c20edd462cd8430a20278f455809b9770e7a0372932eb0a867e53c7bbf38d50230f41d0f117d4c3c38457cb2aabfb54a19f40889275d6150d0ca78f77d71aa0461e83a1e22fa9878708af965557f6a9433e811124ebac2a1a194f1eefa6f666170a6d6befdc1f718d90c50f2a5ab178464d023c89e7585434429e3ddf36adf1b8e241000b350b459aa0f000d46027164c6a049353deb0a868953c7bbe561d08fc91e82841e6e2edb4c145e4286b125258a40940e7cd6150d13a78f77c94fb3783f13678af4a923de901f1aad080e8ca7118129c0faac2a1a284f1eef912b79492afd3198a11f0de5183493820ac95baa20025525f6585434519e3ddf2156f29255fa6331423e1bca306927041592b7544004aa4becb0a868a33c7bbe4239f77d58cb28e53c48fdbc58c8ac3025d1b1047d09563bda6150d14778f77c830001535e6cb44d305ec1a0a987b688464fa464f712ae1bb5c2a1a28ff1eef9050002a6bcd9689a60bd8341530f6d108c9f48c9ee255c376b8543451fe3ddf20a00054d79b2d134c17b0682a61eda21193e9193dc4ab86ed70a868a3fc7bbe414000a9af365a26982f60d054c3db442327d2327b89570ddae150d147f8f77c828001535e6cb44d305ec1a0a987b688464fa464f712ae1bb5c2a1a28ff1eef9050002a6bcd9689a60bd8341530f6d108c9f48c9ee255c376b8543451fe3ddf20a00054d79b2d134c17b0682a61eda21193e9193dc4ab86ed70a868a3fc7bbe414000a9af365a26982f60d054c3db442327d2327b89570ddae150d147f8f77c828001535e6cb44d305ec1a0a987b688464fa464f712ae1bb5c2a1a28ff1eef9050002a6bcd9689a60bd8341530f6d108c9f48c9ee255c376b8543451fe3ddf20a00054d79b2d134c17b0682a61eda21193e9193dc4ab86ed70a868a3fc7bbe414000a9af365a26982f60d054c3db442327d2327b89570ddae150d147f8f77c828001535e6cb44d305ec1a0a987b688464fa464f712ae1bb5c2a1a28ff1eef9050002a6bcd9689a60bd8341530f6d108c9f48c9ee255c376b8543451fe3ddf20a00054d79b2d134c17b0682a61eda21193e9193dc4ab86ed70a868a3fc7bbe41400035c18f06fcfab2189d1aebd33a814fccdebde5540ddc8551d147f8f87c827fff6b831e0df9f564313a35d7a675029f99bd7bcaa81bb90aa3a28ff1f0f904fffe631894c8ca4d4b1a4131d744e063672e2739f14d3773b948451fe3e2f209fffb5243823e6afd18ec4f29d681b724f656fab63e976ee916918a3fc7c6e413fff530995d29ac5cb4906b19d4fb64a814a8a1aed92bddd3d124147f8f8ec827ffe96132ba5358b96920d633a9f6c9502951435db257bba7a24828ff1f1d904fffd24e77cd5387d554f9792d7be588fe7a9d32fdc0ac7750e89151fe3e3c209fffa32901f353e60d2caabf211fc3085b1d35123ddd55eea37523a3fc7c79413fff455203e6a7cc1a59557e423f8610b63a6a247bbaabdd46ea4747f8f8f2827ffe8a301a25fc6e973562c94aa70417ca9ccef539d154ba8f788f8ff1f1e604fffd1360344bf8dd2e6ac592954e082f95399dea73a2a9751ef11f1fe3e3cc09fffa264c7af09e90bf5842f1f0c40855889b368129a14fea3f863f3fc7c79913fff44b250839e9f7e1333db0a7b008a16f5e67ae959e9cd480b07f7f8f8f3327ffe8954a1073d3efc2667b614f601142debccf5d2b3d39a90160feff1f1e664fffd12a20334054b5e74fae8f64e81a7c1ba1996698d670520465fefe3e3ccd9fffa253406680a96bce9f5d1ec9d034f8374332cd31ace0a408cbfdfc7c799b3fff44a60cdf59ffadffc1720a59c861e6ccae6046a5b5be48133bfcf8f8f3377ffe894b19beb3ff5bff82e414b390c3cd995cc08d4b6b7c902677f9f1f1e66efffd1296337d67feb7ff05c8296721879b32b9811a96d6f9204ceff3e3e3ccddfffa252c66facffd6ffe0b9052ce430f36657302352dadf24099dfe7c7c799bbfff44a585a07f8a7b65e99d87262ae1663290dff169db7e1813563d08f8f3378ffe894af402249fc431fb668b18b8424bcb043f8d97dcbc0026c6ba21f1e66f2ffd1295d0c56eca55ca1ef892fdd30416fbeafec5f3df37d04da7b453e3ccde6ffa252b918add94ab943df125fba6082df7d5fd8be7be6fa09b4f68a7c799bcdff44a572315bb2957287be24bf74c105befabfb17cf7cdf41369ed14f8f3379bfe894ae462b7652ae50f7c497ee9820b7df57f62f9ef9be826d3da29f1e66f37fd1295c851812302a0817b4aca992c0ef24926c0a02193cd4da95854e3ccde70fa252b8f2f149eb21765794d61f88015daf0757bec8583979b5454aac799bce2f44a571d5e293d642ecaf29ac3f1002bb5e0eaf7d90b072f36a8a9558f3379c5e894ae3a4864d37533f867ed54a8284f621ffdea5e586a5b6d52f6ac1e66f38cd1295c731cdbff973e53529276167896ba9e23cf68f330b3daa791593ccde71aa252b8e539b7ff2e7ca6a524ec2cf12d753c479ed1e66167b54f22b2799bce3544a571ca736ffe5cf94d4a49d859e25aea788f3da3ccc2cf6a9e4564f3379c6a894ae39472f25566c8fd174b7d79ecadcb4f4675f3dbe19bd53e2ecae66f38d61295c72771f7037a685cb14ec7ba01538cfcb4e693fa1f34aa7e0196ccde71ad252b8e4d70005fa1a71be5555c3a2a9f105791c7d4369a6654fda72e99bce35b4a571c996c1317f0249a4d62853a7d36170d4b8a54af90c9a9fcf25e3379c6b794ae39316438888d1f971d7cd73b22642478bf0f55a17d9053fb88bd66f38d70295c7261548369c71590bdb17b3c6cc03f4fa6195785571da7f8b57bcde71ae152b8e4c135192c3b0183fe1ac33f017874fd742d5b4d0a384ff30ef89bce35c3a571c9816a3258760307fc35867e02f0e9fae85ab69a14709fe61df1379c6b874ae3930260770998dc727b22d9c22dd9ca53f8b0197684de3fcddfe36f38d70f95c726034d006bde8f4778fd804a83ab8b06195adf2f65b97f9d63c7de71ae202b8e4c0526133069f4f174b2cd5b2f4f0c6a5ab06aa1276fff3c6b90bce35c41571c98094c2660d3e9e2e9659ab65e9e18d4b560d5424edffe78d72179c6b882ae393012245f1a54aa2855830232e534280792bc56c6f9bcfcf35243f38d71065c72602348be34a95450ab060465ca68500f2578ad8df379f9e6a487e71ae20cb8e4c0461d8ec1ff7f03d8c3d591bcc8967c72ec075e42f0f3ceed10ce35c41a71c9808b3b1d83fefe07b187ab2379912cf8e5d80ebc85e1e79dda219c6b8834e3930116024d60aad271e5c7230d1b1a504ff3aac9bb67c0cf3d584438d7106ac726022b049ac155a4e3cb8e461a3634a09fe7559376cf819e7ab08871ae20d58e4c0456093582ab49c7971c8c346c69413fceab26ed9f033cf56110e35c41ab1c9808ac126b0556938f2e391868d8d2827f9d564ddb3e0679eac221c6b883563930115824d60aad271e5c7230d1b1a504ff3aac9bb67c0cf3d584438d7106ac726022b049ac155a4e3cb8e461a3634a09fe7559376cf819e7ab08871ae20d58e4c045601f6a836172dbf480900cee8c0a5b12ad1b1c4c30cf57b50f35c41ab2c9808abf3ed506c2e5b7e9012019dd1814b6255a363898619eaf6a1e6b8835659301157e09bc6632a1d254ba0cf9e2281fca72af18b38cc03d60783dd7106acc26022afb1378cc6543a4a97419f3c4503f94e55e316719807ac0f07bae20d5984c0455f626f198ca874952e833e788a07f29cabc62ce3300f581e0f75c41ab309808abec4de331950e92a5d067cf1140fe539578c59c6601eb03c1eeb8835661301157d827d8bbd6f387ce589c644a79f30552ec377b2800d60927de7106acc36022afaf4fb177ade70f9cb138c894f3e60aa5d86ef65001ac124fbce20d5986c0455f5e2b754808a481bc1a3e5751dfc27373ab8a2efc005826437ac41ab30e808abebb56ea9011490378347caea3bf84e6e757145df800b04c86f58835661d01157d7639e778cf68697320c6236f77002bf6a8d4fe4bfe609ab1ec106acc3b022afaeb73cef19ed0d2e6418c46deee0057ed51a9fc97fcc13563d820d598760455f5d673b03bea78084f3ae553e5d3f70e029e003b8bf6826c6bb141ab30ed08abebab7372d081c673212d976df39fe47a2d36acb973ea04da7b63835661db1157d75572f7f9b06348c512fba20f37bf52826805b543d109b69ac806acc3b722afaea972024c0d9cf40cddc40a466775032ccab7ace39f136ed9910d59876f455f5d517016f0c8104a9c7354dab4c6e06481901b9c233b26df57231ab30edf8abebaa16c403a3cf6f7bb9e767b9185b7272b1ae37aa2734dc0524735661dc0157d75416492cd26c451f9f4b9bd4b0364ac7e307337a0e39b82488f6acc3b812afaea815537f2fa5f0676a14040bdfebfb7245b92b19dc43706351fd598770355f5d50136823ea1946f6ffa4d47a3f575cc70b1d1a597856e0e0e40ab30ee07abebaa016d047d4328dedff49a8f47eaeb98e163a34b2f0adc1c1c815661dc0f57d75402661b5333282042a101e4b7cdcd8feac1f2d8ba12b839dd03acc3b81fafaea8035848ff1326a307f9d08f9793917dfd7e91f3d02270755e08598770405f5d50053ca456d323a892ab6de5571f195a22f7d029fc41e0ec6011b30ee081bebaa009055b06531db3a80ea890d63629126dea4c965480c1da6424661dc1047d7540110ab60ca63b67501d5121ac6c5224dbd4992ca90183b4c848cc3b8208faea8022156c194c76cea03aa24358d8a449b7a9325952030769909198770411f5d500442ad83298ed9d40754486b1b148936f5264b2a4060ed3212330ee0823ebaa008855b06531db3a80ea890d63629126dea4c965480c1da6424661dc1047d7540110377323108cd7848cdee0eebd18abe5443f0cec153b4e288dc3b82090aea8021f6ee6462119af0919bdc1dd7a3157ca887e19d82a769c511b877041215d50043e69dee4ef09c094eb4849e2ec590dbd0ba8760c51ed3a46380ee08243baa0087b5fd0228ae9e3ac8e5d59edd0a879a211fd2e74a0da7630711dc10488754010f54bb29dc2aa29dbd4877a039947516c1ea69f453eb4ee04e33b820911ea8021e9237794322ab63a60dbba2f2a85010037f980e67a69ddadc777041224d50043d146ef2864556c74c1b7745e550a02006ff301ccf4d3bb5b8eee082449aa0087a219f0a975813b6c3b3baee4a20a6228da9245f5e6a7785b1edc10489454010f4333e152eb0276d876775dc94414c451b5248bebcd4ef0b63db8209128a8021e8667c2a5d604edb0eceebb92882988a36a4917d79a9de16c7b7041225150043d0c5b97a458e03de491aa3d4d08496f6ecf3e720b323bc47cf7e08244a3a0087a174341a15e96de4bdb2140c208893d059929267261778a9df0c10489484010f42d12959b6a041f1a6e0f47ac0908d8332cfe8f40bfef16dfe2820912918021e859252b36d4083e34dc1e8f581211b06659fd1e817fde2dbfc5041225230043d0b24a566da8107c69b83d1eb0242360ccb3fa3d02ffbc5b7f8a08244a460087a16420bf33fcf75b5628470388403d1fc162a0bc61fc78b8a3151048948d010f42c7417e67f9eeb6ac508e0710807a3f82c54178c3f8f171462a2091291a021e858e0f0f28a0b3cfdb58e8d448f8eadd2d852f33e3eee2e4305541225235043d0b1b1e1e5141679fb6b1d1a891f1d5ba5b0a5e67c7ddc5c860aa8244a46a087a16363c3ca282cf3f6d63a35123e3ab74b614bccf8fbb8b90c155048948d410f42c6c048b9db274e15d7f13686fbf4d47942425e17b74172326ab091291a921e858d709173b64e9c2bafe26d0df7e9a8f28484bc2f6e82e464d561225235243d0b1ae122e76c9d38575fc4da1befd351e50909785edd05c8c9aac244a46a487a1635c245ced93a70aebf89b437dfa6a3ca1212f0bdba0b919355848948d490f42c6b848b9db274e15d7f13686fbf4d47942425e17b74172326ab091291a921e858d701d860efb728e329a39d41fe19f50ac7f6871ca7fe4667962225235253d0b1adf3b0c1df6e51c653473a83fc33ea158fed0e394ffc8ccf2c444a46a4a7a1635be022a949aa09b4d20b416a77e73a0d9f84e0985fc919b89898948d495f42c6b7b0455293541369a41682d4efce741b3f09c130bf9233713131291a92be858d6f608aa526a826d3482d05a9df9ce8367e1382617f2466e262625235257d0b1adec1154a4d504da6905a0b53bf39d06cfc2704c2fe48cdc4c4c4a46a4afa1635bd822a949aa09b4d20b416a77e73a0d9f84e0985fc919b89898948d495f42c6b7b0455293541369a41682d4efce741b3f09c130bf9233713131291a92be858d6f6016b77f54fd35cae4d2700794de94a60e2ea3db2166e406635235257e0b1adebf2d6efea9fa6b95c9a4e00f29bd294c1c5d47b642cdc80cc6a46a4afc1635bd7e5addfd53f4d72b9349c01e537a529838ba8f6c859b90198d48d495f82c6b7afc41ce5354c010d9de6046649eeb03586c216135083721d71b91a92bf158d6f5f70faeff56568436748d52f135cc64d8d2ef04c60d6e455238235257e3b1adebed1f5dfeacad086ce91aa5e26b98c9b1a5de098c1adc8aa47046a4afc7635bd7da3ebbfd595a10d9d2354bc4d73193634bbc131835b91548e08d495f8ec6b7afb4098a535f8a84365c375db1a65984ee9224688c68722c35c21a92bf1e8d6f5f671314a6bf15086cb86ebb634cb309dd2448d118d0e4586b8435257e3d1adebece26294d7e2a10d970dd76c6996613ba4891a231a1c8b0d7086a4afc7a35bd7d9c4c529afc5421b2e1baed8d32cc277491234463439161ae10d495f8f46b7afb3824b78ea57ea5e87b42a1425d8ead111cf2cb228422c50022a92bf1e9d6f5f66f496f1d4afd4bd0f6854284bb1d5a2239e5964508458a00455257e3d3adebecde1ef09342d0fa24a4d74b316e31126c6e776ee60d8b15a48ba4afc7a85bd7d9bb3de12685a1f44949ae9662dc6224d8dceeddcc1b162b4917495f8f50b7afb37607d4a5b81a4b154b29f2edb0baa7d9b489fdf4332c58362f92bf1ea26f5f66eb0fa94b7034962a9653e5db61754fb36913fbe86658b06c5f257e3d44debecdd61f5296e0692c552ca7cbb6c2ea9f66d227f7d0ccb160d8be4afc7a89bd7d9bac3ea52dc0d258aa594f976d85d53ecda44fefa19962c1b17c95f8f5137afb3758095cb42e7b13d76a6bf50303a0dbc3434c219f2fc58506fa2bf1ea27f5f66eaf12b9685cf627aed4d7ea060741b7868698433e5f8b0a0df457e3d44febecdd5e2572d0b9ec4f5da9afd40c0e836f0d0d30867cbf16141be8afc7a89fd7d9babc4ae5a173d89ebb535fa8181d06de1a1a610cf97e2c2837d15f8f513fafb3757821dd9b94879ff95e8c165832041a5c2f6e5c4ef9585213a3bf1ea2805f66eaef43bb37290f3ff2bd182cb0640834b85edcb89df2b0a427477e3d4500becdd5de1388c6fef4e26831fd1f88c006c798b865b397e26149f28ffc7a8a027d9babbb27118dfde9c4d063fa3f11800d8f3170cb672fc4c293e51ff8f51404fb3757764e231bfbd389a0c7f47e23001b1e62e196ce5f898527ca3ff1ea2809f66eaeec285890a47d75c447b5c26df82c9aedbdd9df1b100a513880e3d45014ecdd5dd750b12148faeb888f6b84dbf05935db7bb3be362014a27101c7a8a029d9babbae2d749b3ecc3993d6a3cfdfd8a8c9def213bec83d294686048f514054b375775b5ae9367d987327ad479fbfb15193bde4277d907a528d0c091ea280a966eaeeb641e4c5a80748d2125c05a75a9985a3c2fb3d7cf1a51bbc133d450153cdd5dd6b0fdbe3fce4f426dc84d176ad29696f80a2bd55e04a391c277a8a02a89babbad51fb7c7f9c9e84db909a2ed5a52d2df01457aabc09472384ef5140551375775aa3f6f8ff393d09b721345dab4a5a5be028af5578128e4709dea280aa26eaeeb540af17893fe03b99bf351dd6141a9a3ffc22d0aff51ca853cd4501545dd5dd6a715e2f127fc077337e6a3bac2835347ff845a15fea3950a79a8a02a8bbabbad4e2bc5e24ff80ee66fcd47758506a68fff08b42bfd472a14f35140551775775a9c578bc49ff01dccdf9a8eeb0a0d4d1ffe116857fa8e5429e6a280aa2eeaeeb5383b29e1ecb69e1c7701e3fe0c10f867f6cf130bf21ca9f7ce4501545ed5dd6a6f02661c86439ebba5d08e2410184ef7e84a6873e13955939d8a02a8beabbad4dd04cc390c873d774ba11c4820309defd094d0e7c272ab273b1405517d5775a9ba099872190e7aee9742389040613bdfa129a1cf84e5564e76280aa2faaeeb53741330e4321cf5dd2e84712080c277bf4253439f09caac9cec501545f55dd6a6e82661c86439ebba5d08e2410184ef7e84a6873e13955939d8a02a8beabbad4dd04cc390c873d774ba11c4820309defd094d0e7c272ab273b1405517d5775a9ba025997a3dbe116c2bf04f2bfe0a1c220d465f544b55668b6380aa2fabeeb5373f4b32f47b7c22d857e09e57fc1438441a8cbea896aacd16c701545f57dd6a6e7e227841a3cea833678e02d7f01eceb02fc5bfad2a559bd18f02a8beb0bad4dcfb44f083479d5066cf1c05afe03d9d605f8b7f5a54ab37a31e05517d6175a9b9f615f35f3c1103505604d187b87198e8b9c34110a65670ea3d0aa2fac3eb5373eb2be6be782206a0ac09a30f70e331d1738682214cace1d47a1545f587d6a6e7d657cd7cf0440d415813461ee1c663a2e70d04429959c3a8f42a8beb0fad4dcfac3bad528d5e7d0567f35265bb83256dc8c64ae12fb388f5e95517d6205a9b9f57036cfdc7935c8d87b36af36efca9038c38d81e5c67138fd3aa2fac41b5373ead06d9fb8f26b91b0f66d5e6ddf952071871b03cb8ce271fa7545f58836a6e7d5a0db3f71e4d72361ecdabcdbbf2a40e30e36079719c4e3f4ea8beb106d4dcfab41b67ee3c9ae46c3d9b579b77e5481c61c6c0f2e3389c7e9d517d620da9b9f56836cfdc7935c8d87b36af36efca9038c38d81e5c67138fd3aa2fac41b5373ead06d9fb8f26b91b0f66d5e6ddf952071871b03cb8ce271fa7545f58836a6e7d5a06751ca91ad85e4a4a78303b7209f0b08e249f316c4e598eb8beb106e4dcfab3f5ab5edd0316e4c011bcc2f66379c3e0c70d6422a89ccd5d817d620dd9b9f567d417e344d393f1aba045e86c46596a4138deee052139b4fb12fac41bc373eacf90f0ec14748e0b82bd5833580c18b7021c8201ca1273843635f5883796e7d59f11e1d828e91c17057ab066b018316e043904039424e7086c6beb106f2dcfab3e23c3b051d2382e0af560cd603062dc087208072849ce10d8d7d620de5b9f567c4048862e71d68441678dfd3fe02b9a908ed43410639c3bf1bfac41bcc73eacf870910c5ce3ad0882cf1bfa7fc05735211da86820c73877e37f5883798e7d59f0e12218b9c75a11059e37f4ff80ae6a423b50d0418e70efc6feb106f31cfab3e1c24431738eb4220b3c6fe9ff015cd48476a1a0831ce1df8dfd620de639f567c3848862e71d68441678dfd3fe02b9a908ed43410639c3bf1bfac41bcc73eacf8701d1eb590836b0586e8c0a7b84d93491854aa7cc4387987805883798f7d59f0df3a3d6b2106d60b0dd1814f709b269230a954f98870f30f00b106f31efab3e1be008d2eeee40e98d36fc8c6d92cab4c5bfeec4f0de1e7c202620de63ef567c37b011a5dddc81d31a6df918db2595698b7fdd89e1bc3cf8404c41bcc7deacf86f60234bbbb903a634dbf231b64b2ad316ffbb13c37879f0809883798fbd59f0dec046977772074c69b7e4636c9655a62dff762786f0f3e1013106f31f7ab3e1bd808d2eeee40e98d36fc8c6d92cab4c5bfeec4f0de1e7c202620de63ef567c37b011a5dddc81d31a6df918db2595698b7fdd89e1bc3cf8404c41bcc7deacf86f60234bbbb903a634dbf231b64b2ad316ffbb13c37879f0809883798fbd59f0dec046977772074c69b7e4636c9655a62dff762786f0f3e1013106f31f7ab3e1bd8019414790e4fb5627958d0124a1aa83f9989169dee7c3a6630de63ef667c37aff32828f21c9f6ac4f2b1a0249435507f33122d3bdcf874cc61bcc7deccf86f5fe65051e4393ed589e5634049286aa0fe66245a77b9f0e998c3798fbd99f0debfc561c9533fe3d33f4792e311d03b247c770cdaaf43e1ed7196f31f7b43e1bd7f7384b8314d2dceaa0bf228a31fdc2b7898dddb1e57c3f5233de63ef697c37afed70970629a5b9d5417e451463fb856f131bbb63caf87ea467bcc7ded2f86f5fda6d40650021d62d3ac95050bfed690620e3b92392f0feecd0798fbda6f0debfb3669322ad1a0edd2d5f66c977d130343c73b4a322e1ff7da1f31f7b4ee1bd7f6559389e070a803d128b93bae798be907393aba242c4009f44e63ef69ec37afec93e8394baeb62fcdce3ed9dc727db48e1d399a0828802e28acc7ded3e86f5fd9109198222ad287c7194a163864614b9be53759d021007691698fbda7e0debfb21123304455a50f8e32942c70c8c29737ca6eb3a04200ed22d31f7b4fc1bd7f6422466088ab4a1f1c652858e191852e6f94dd67408401da45a63ef69f837afec8448cc11156943e38ca50b1c3230a5cdf29bace810803b48b4c7ded3f06f5fd9081daa7ad7a8ea49d116dc605c57a9c3dfe39c2c1e0078356a8fbda7e1debfb20f3b54f5af51d493a22db8c0b8af5387bfc738583c00f06ad51f7b4fc3bd7f641e02bc440b7a0ba9fc2837a9695505377a3ab30c7501e279ab3ef69f887afec83b05788816f41753f8506f52d2aa0a6ef4756618ea03c4f3567ded3f10f5fd90760af1102de82ea7f0a0dea5a55414dde8eacc31d40789e6acfbda7e21ebfb20ec15e2205bd05d4fe141bd4b4aa829bbd1d59863a80f13cd59f7b4fc43d7f641d82bc440b7a0ba9fc2837a9695505377a3ab30c7501e279ab3ef69f887afec83b05788816f41753f8506f52d2aa0a6ef4756618ea03c4f3567ded3f10f5fd907603b235b8b594d01c1dab0824d37ac06895905793d78a00ed0bda7e21fbfb20ebf02590fc388fc863b82272c9265b6350d5e4d4e77f141c1a27b4fc4407f641d7d04b21f8711f90c77044e5924cb6c6a1abc9a9cefe2838344f69f8880fec83afa09643f0e23f218ee089cb24996d8d435793539dfc5070689ed3f1101fd9075f412c87e1c47e431dc113964932db1a86af26a73bf8a0e0d13da7e2203fb20ebe82590fc388fc863b82272c9265b6350d5e4d4e77f141c1a27b4fc4407f641d7d04b21f8711f90c77044e5924cb6c6a1abc9a9cefe2838344f69f8880fec83afa02256498f1584119856914c9163eb6b523f95f9f950720c9fd3f11020d9075f3f44ac931e2b082330ad229922c7d6d6a47f2bf3f2a0e4193fa7e22041b20ebe7e156b7ee92c72c919270b5a3d860bd543aa9a43e241c9d6804fc44084641d7cfb2ad6fdd258e592324e16b47b0c17aa87553487c48393ad009f888108c83af9f655adfba4b1cb24649c2d68f6182f550eaa690f8907275a013f1102119075f3ec376e4ff639f8cb810520f9e426bcd21801147b0f0e5058037e22042420ebe7d76edc9fec73f197020a41f3c84d79a4300228f61e1ca0b006fc44084841d7cfae69cb9885be45b0bbe14a0f889151705ab09448393943040ef888109183af9f5b5fa989b852ede42f8f5a4709190108b00d6aec6f7287ac1ef1102124075f3eb54b656c1d7c3e4b16eb7ab60a2860395ac71834dbe510fc3ee22042490ebe7d6922dd30e7cedf18e5a3bb940c471e9ab03a72c5b4ca239c7ec44084931d7cfad145ba61cf9dbe31cb477728188e3d356074e58b69944738fd888109263af9f5a217871c4c11dee64e5bb4782912d892bb960d72d0289015fc1102124d75f3eb432f0e389823bdcc9cb768f05225b125772c1ae5a051202bf82204249aebe7d6865e1c7130477b99396ed1e0a44b624aee5835cb40a24057f044084935d7cfad0c484b3b0d6559b52aaa69e9408d22bdd75cadf27e448253e18810926caf9f5a171ca8cec7a115ed0d2199fa7910a3a3a9659e40f989064bc4102124da5f3eb42d39519d8f422bda1a4333f4f221474752cb3c81f3120c9788204249b4be7d685a72a33b1e8457b4348667e9e4428e8ea5967903e624192f10408493697cfad0b47158cee9df11eb20d995fbc07b7b4545d93463c948340221810926d3f9f5a1676ec3f680948658f97ff21f78ed54b2865eab238f9069a84402124da8f3eb42cd699a45adff6f34aaccaa66e9d1078d076998a31c20d4f48904249b52e7d685995f46e408d540ec0d661af5cb986d42097f73a23541ab8d13084936a6cfad0b314aa020be80e45ad298fc138f2738ac0dab29a0678358be2710926d4e9f5a166121529a29d82b385cfebe4f1644cf801602959ccc06b3204f2124da9e3eb42cc142a53453b05670b9fd7c9e2c899f002c052b39980d66409e4249b53c7d685982115cc154370f642bc7bf6451099c2852b698cf2d1ace253d84936a79fad0b30322b982a86e1ec8578f7ec8a2133850a56d319e5a359c4a7b0926d4f3f5a1660645730550dc3d90af1efd91442670a14ada633cb46b3894f6124da9e7eb42cc0c16f8634e8edda4160ac14a80433f6a906108d565d672cded249b53d0d68598172df0c69d1dbb482c15829500867ed520c211aacbace59bda4936a7a1ad0b302e5be18d3a3b7690582b052a010cfdaa418423559759cb37b4926d4f435a16605c43d573214d4fa36822d07bfa10597c7db489072bb398136a24da9e87b42cc0b713bd3eef7101c98812671fec171120f615546a546731cad549b53d106859816d277a7ddee203931024ce3fd82e2241ec2aa8d4a8ce6395aa936a7a20d0b302da4ef4fbbdc4072620499c7fb05c4483d85551a9519cc72b5526d4f441a16605b429fc50285e70cef85fff2758aee72fab56e5aea0398ffaab4da9e88442cc0b6753f8a050bce19df0bffe4eb15dce5f56adcb5d40731ff5569b53d108859816ce3403994e5025be994cc2c55ab1fae6a807d9167de6418eae36a7a2120b302d9b6807329ca04b7d3299858ab563f5cd500fb22cfbcc831d5c6d4f442416605b365c20bde616f97d1cffd13d62be49c29acba6b5f49907deb9da9e88492cc0b66b4453d47904557cf1cc68a2bd72f1ad30438fc7e632116174b53d109359816cd514ba019edf0d7c9b65976d72dc41825b3361ebc9642466ea6a7a2127b302d9a92974033dbe1af936cb2edae5b88304b666c3d792c848cdd4d4f4424f6605b35252e8067b7c35f26d965db5cb7106096ccd87af2590919ba9a9e8849ecc0b66a431e265a3cece6792f981938ed86a3ad44751ba482124db5453d1093e9816cd4763c4cb479d9ccf25f303271db0d475a88ea374904249b6a8a7a2127d302d9a8e539bef3c119c2103b2cc76335807134bc989451d849511524f4424fb605b351b334a3724f99ac4bf325f145ea66c4e923f54e638092bc6a59e8849f7c0b66a3566946e49f335897e64be28bd4cd89d247ea9cc7012578d4b3d1093ef816cd46a593b3540bccd95b496427972900f6243a995f4dd24b0be977a2127e002d9a8d33e88c32e4ffdae20f94b1add167cec81ff6e45b74963212ff4424fc105b351a50923df09765ddef9bf5c5db2235800feab1ee76b92c7e660e8849f830b66a3491247be12ecbbbdf37eb8bb6446b001fd563dced7258fccc1d1093f0616cd4692248f7c25d9777be6fd7176c88d6003faac7b9dae4b1f9983a2127e0c2d9a8d24491ef84bb2eef7cdfae2ed911ac007f558f73b5c963f33074424fc185b351a481e5049443c407253c28c031a2bde37e55e30d2b62c800a0f8849f831b66a348f3ca092887880e4a78518063457bc6fcabc61a56c5900141f1093f0636cd4691e05537dbdc7644c06d6f63460a5d707902505a6d5b201cc3f2127e0c7d9a8d23b0aa6fb7b8ec8980dadec68c14bae0f204a0b4dab6403987e424fc18fb351a476154df6f71d91301b5bd8d182975c1e4094169b56c80730fc849f831f66a348ec2a9bedee3b226036b7b1a3052eb83c81282d36ad900e61f9093f063ecd4691d85537dbdc7644c06d6f63460a5d707902505a6d5b201cc3f2127e0c7d9a8d23b036821065c2ec0392ab8cb40cb13f19ff4cf736b3403b2be524fc18fc351a475f6d0420cb85d8072557196819627e33fe99ee6d66807657ca49f831f86a348ebe661a9a43e21291027af8f82abb5a8ff7e01f36ca00ee539593f063f1d4691d7b58478d349a87a4bcc2b8184d6d1347ea6c80c99101de4b2c27e0c7e4a8d23af53ca173160b71cc3152365892d084b7cf8543ef1f03be3a594fc18fca51a475e905553ed8ed461b1a7132d91d97679799b6ca3a3b077e18b39f831f95a348ebd10aaa7db1da8c3634e265b23b2ecf2f336d9474760efc31673f063f2b4691d7a21554fb63b5186c69c4cb64765d9e5e66db28e8ec1df862ce7e0c7e568d23af442aa9f6c76a30d8d38996c8ecbb3cbccdb651d1d83bf0c59cfc18fcad1a475e885553ed8ed461b1a7132d91d97679799b6ca3a3b077e18b39f831f95a348ebd1036ba33ca7f25e605f3214baae3511b318589a35defc4ba74f063f2b5691d7a1f6d746794fe4bcc0be6429755c6a236630b1346bbdf8974e9e0c7e56ad23af43e66fb27d6d2fa1acf994b56a383a294c0c268e974bf148dd4c18fcad6a475e87b5a08a85a7c56b856ff5cd53efda3517c31142ee67e2abfaa831f95ae48ebd0f54023a961cf0ff365cb7fd275f1a4caf30e6ab9c9fc572356063f2b5d91d7a1e90c59ab707482698363c5cce3d9a7bde0c917cf90f8afeaad0c7e56bc23af43d118b356e0e904d306c78b99c7b34f7bc1922f9f21f15fd55a18fcad78475e87a23166adc1d209a60d8f17338f669ef783245f3e43e2bfaab431f95af08ebd0f4462cd5b83a4134c1b1e2e671ecd3def0648be7c87c57f556863f2b5e11d7a1e8851ad0fb41e891aee0922f63590da06073dbf550c8b004ed1c7e56bc33af43d0f2f6c78151374b893df0c14631812340927c10616160241a48fcad78775e87a1d5ed8f02a26e97127be1828c6302468124f820c2c2c0483491f95af0eebd0f43a49c439012435650748f6798456a6f81f4b467455580aaa933f2b5e1ed7a1e8731f9acaaf1ecd4cc65eb31b00a3ac183942cf44a7b016f9277e56bc3eaf43d0e53f35955e3d9a998cbd66360147583072859e894f602df24efcad787d5e87a1ca0a7d83695197b5d1479293fa850e88dfb77f6e9bc05d889ef95af0fbbd0f439314fb06d2a32f6ba28f2527f50a1d11bf6efedd3780bb113df2b5e1f77a1e872629f60da5465ed7451e4a4fea143a237eddfdba6f0176227be56bc3eef43d0e4c53ec1b4a8cbdae8a3c949fd4287446fdbbfb74de02ec44f7cad787dde87a1c9833ea8f41efdddfcc45ef67a04746b5f6243945b905da2df095af0fbcd0f4392f67d51e83dfbbbf988bdecf408e8d6bec48728b720bb45be12b5e1f79a1e8725e5bbc95b495da01e8e483c6791378ffd33d2772e1176a5bc356bc3ef443d0e4bb438b84160216868995cdb4ea1d5027a1269141bf2ed65b87ad787de987a1c975132960d8da8f8fcaf86191cc30fe773cf964df7b5dae5b105af0fbd40f4392e92652c1b1b51f1f95f0c3239861fcee79f2c9bef6bb5cb620b5e1f7a81e8725d24ca583636a3e3f2be1864730c3f9dcf3e5937ded76b96c416bc3ef503d0e4ba4255d5f73aadf010f8fd2b6597e51e1e2776957d7ed747c83d787dea17a1c97474ababee755be021f1fa56cb2fca3c3c4eed2afafdae8f907af0fbd42f4392e8e2187d67b81de86f60c11015defa5af8489e7bb5cb5d396105e1f7a86e8725d1b430facf703bd0dec182202bbdf4b5f0913cf76b96ba72c20bc3ef50dd0e4ba361231b29adddc9e8ffd0a2d6fb4f4e60cd3e1496fd74ffc42787dea1ca1c9746b24636535bbb93d1ffa145adf69e9cc19a7c292dfae9ff884f0fbd4394392e8d648c6ca6b77727a3ff428b5bed3d398334f8525bf5d3ff109e1f7a8728725d1ac1d9fed83c5477737b51793759e0558614b4ca77bba818614c3ef50e60e4ba3573b3fdb078a8eee6f6a2f26eb3c0ab0c296994ef775030c2987dea1cc1c9746ae02920ebbeb805f96a12475ce6e73897fd974f9ebea07bc540fbd4399392e8d5b05241d77d700bf2d4248eb9cdce712ffb2e9f3d7d40f78a81f7a8732725d1ab60a483aefae017e5a8491d739b9ce25ff65d3e7afa81ef1503ef50e64e4ba356c149075df5c02fcb50923ae73739c4bfecba7cf5f503de2a07dea1cc9c9746ad82920ebbeb805f96a12475ce6e73897fd974f9ebea07bc540fbd4399392e8d5b05241d77d700bf2d4248eb9cdce712ffb2e9f3d7d40f78a81f7a8732725d1ab60309607a7b67a686015e39b93934087f10980d6f781f0b904ef50e64f4ba356bf612c0f4f6cf4d0c02bc7372726810fe21301adef03e17209dea1cc9e9746ad7e4e6a774bb04c243824549646436047bed245b7db07c48814bd43993e2e8d5afb28e7474436facb28156f54847d1eb77850cdcbb30f8ab42a7a87327d5d1ab5f551ce8e886df596502adea908fa3d6ef0a19b97661f156854f50e64faba356bea2faf75bdb24daf5822837a09ead905dbef798ac93e2c74aaea1cc9f6746ad7d35f5eeb7b649b5eb04506f413d5b20bb7def315927c58e955d43993ece8d5afa64ad02fa39f99401856d4101fa1c23f6a6a288721f8b376aca87327dad1ab5f4b21b2b7f4159502e87a6e483739e2a6cf80936a40f168915a50e64fb6a356be9543656fe82b2a05d0f4dc906e73c54d9f0126d481e2d122b4a1cc9f6d46ad7d2a12dd387d2cb68e59b67f48d4dde8c338ae900500c5a3e96a43993edb8d5afa5325ba70fa596d1cb36cfe91a9bbd186715d200a018b47d2d487327db71ab5f4a64b74e1f4b2da3966d9fd235377a30ce2ba401403168fa5a90e64fb6e356be94c22fc1c963c16f58580c06e9ee5a441c020c284032d20ef531cc9f6dd6ad7d29745f8392c782deb0b0180dd3dcb488380418508065a41dea63993edbad5afa52e1802cb05c6be58cdcfc7e2738cef2efb2f4c6c09b485614d7327db76ab5f4a5b3005960b8d7cb19b9f8fc4e719de5df65e98d813690ac29ae64fb6ed56be94b6600b2c171af963373f1f89ce33bcbbecbd31b026d2158535cc9f6ddaad7d296c4c28b0db0c5549264b053b945dd79fd426a5bc4aa42cae6c993edbb65afa52d72463ba62ef0d150462d09f20b20d67a2f98dd492485b00da327db76db5f4a5ad48c774c5de1a2a08c5a13e41641acf45f31ba92490b601b464fb6edb6be94b5a1da142389296d6c95808a47abe93c6869279ae46216da769c9f6ddb7d7d296b33b428471252dad92b01148f57d278d0d24f35c8c42db4ed393edbb6fafa52d660297618f20bddddd2ce8b9e2f0ad4214f629151585b841a827db76e05f4a5acb052ec31e417bbbba59d173c5e15a8429ec522a2b0b7083504fb6edc0be94b5960a5d863c82f77774b3a2e78bc2b50853d8a4545616e106a09f6ddb817d296b2c14bb0c7905eeeee96745cf17856a10a7b148a8ac2dc20d413edbb702fa52d658297618f20bddddd2ce8b9e2f0ad4214f629151585b841a827db76e05f4a5acb052ec31e417bbbba59d173c5e15a8429ec522a2b0b7083504fb6edc0be94b596031eabc7505d9fa0306f4a0b421aead383687a15e6e120e0af6ddb818d296b2bf63d578ea0bb3f4060de94168435d5a706d0f42bcdc241c15edbb7031a52d657e53bd4a80edca6ac3e898aac87d18dcdb8660e176b849dc2cdb76e0644a5acafb338cedaeb1f7583f9df77d88f08fe1b1b9041eea70955c5ab6edc0c994b595f56719db5d63eeb07f3beefb11e11fc36372083dd4e12ab8b56ddb8193296b2bea5a460f679e3fe3b644a41e1bb89daec19052d7a6c257156bdbb7032752d657d3409e777c12e24a24560e642f6799857dcce80b4a84afced8b76e064fa5acafa50d4f47a4fc27170078e2f056c59132f646127292096141b26edc0ca04b595f491a9e8f49f84e2e00f1c5e0ad8b2265ec8c24e52412c28364ddb8194096b2be92353d1e93f09c5c01e38bc15b1644cbd91849ca48258506c9bb7032812d657d246a7a3d27e138b803c71782b62c8997b2309394904b0a0d9376e065025acafa486106d2fc98d3f2bf5af52d644f71575f0d69851d9615bf27edc0ca05b595f48f4e1ffea6080a683682b082c09540d6b8c71566382c2d2250db81940c6b2be91d285255f8e6775324d2272d7920dfd56c3a6d286d585be8a2b7032819d657d23950a4abf1cceea649a44e5af241bfaad874da50dab0b7d1456e065033acafa4722d5bb090703fcf4b1562dddc79dd7dab95f6fdb26171468bdc0ca068595f48e35ab76120e07f9e962ac5bbb8f3bafb572bedfb64c2e28d17b81940d0b2be91c641811aee9761bfe422519f69ddd41ea9041e52c685c6be30703281a2657d238b0f148e8a05260280116966cbb206654cb47f018a0b8f2061e0650345cafa47151e291d140a4c050022d2cd97640cca9968fe0314171e40c3c0ca068b95f48e2a3c523a2814980a0045a59b2ec8199532d1fc06282e3c818781940d172be91c5404b6ccfcff9296b858115e5586915260503a684d5c7aa71003281a2f57d238a7096d99f9ff252d70b022bcab0d22a4c0a074d09ab8f54e200650345eafa4714e12db33f3fe4a5ae1604579561a45498140e9a13571ea9c400ca068bd5f48e29c25b667e7fc94b5c2c08af2ac348a930281d3426ae3d538801940d17abe91c5384b6ccfcff9296b858115e5586915260503a684d5c7aa71003281a2f57d238a7022ebf84cc8b559c2cef1f2a8c8887404b38f65a88f568601650345ebfa4714df45d7f099916ab3859de3e5519110e809671ecb511ead0c02ca068bd7f48e29be17c239dff937e9c3088df29b187ff80d7a7ff29f3d5bbc06940d17b0e91c537b2f8473bff26fd386111be53630fff01af4ffe53e7ab7780d281a2f61d238a6f65f08e77fe4dfa70c2237ca6c61ffe035e9ffca7cf56ef01a50345ec3a4714dec4a2427aca021d0d01135bcd0ba5de8668041f0f6eadf8435a068bd8848e29bd7205aa80616a62457ef31a1996b19f8c7acc63dead5c0ac6c40d17b1191c537ad40b5500c2d4c48afde634332d633f18f598c7bd5ab8158d881a2f623238a6f5a0d7cf8c530fb1417898cae5da2c60b195f5b53a8570455b20345ec474714deb31af9f18a61f6282f13195cbb458c1632beb6a750ae08ab64068bd88e8e29bd6635f3e314c3ec505e2632b9768b182c657d6d4ea15c1156c80d17b11d1c537acc6be7c62987d8a0bc4c6572ed163058cafada9d42b822ad901a2f623a38a6f59863e1e4ffe613c43065910dd222bed990a1f796827046ff21345ec475714deb2f53d622aca28a0b1897e8439c3bdbdb1bf0318901e08fa24368bd88ebe29bd65d33be9e061b7698e8fc96af306e15de328ca56e00c120e887d17b11d8c537acb9677d3c0c36ed31d1f92d5e60dc2bbc65194adc018241d10fa2f623b18a6f59725b0cd0c5443ce65bbf20e4b9aeb5a0c4ded814000485462045ec476414deb2e3422bfa375edc4f6f4b07f16b53c9698469f283fd090c30418bd88ec929bd65c5106a4d1b941b219662d60ace9df0fb03802763f7121a048417b11d93537acb8920d49a372836432cc5ac159d3be1f607004ec7ee243409082f623b26a6f5971241a9346e506c86598b582b3a77c3ec0e009d8fdc486812105ec4764d4deb2e240f64c189773b8f6ae3767e6ce5e60016ad7d7bb590d1c821bd88ec9b9bd65c471ec98312ee771ed5c6ecfcd9cbcc002d5afaf76b21a390437b11d93737acb88e3d930625dcee3dab8dd9f9b39798005ab5f5eed643472086f623b26e6f59711c073864f8903efe0ee87a1b5f258e28b0182e39a9868fe50eec4764dddeb2e2370e70c9f1207dfc1dd0f436be4b1c5160305c73530d1fca1dd88ec9bbbd65c46e1ce193e240fbf83ba1e86d7c9638a2c060b8e6a61a3f943bb11d93777acb88dc39c327c481f7f07743d0daf92c714580c171cd4c347f2877623b26eef59711b873864f8903efe0ee87a1b5f258e28b0182e39a9868fe50eec4764dddeb2e2370731ef7bede424494dc0993dca8233dfdb209912dd1fe45de88ec9bbcd65c46df7250482a92e70be184d94fb146a4a3f610557e58a3fe2fbe11d9377aacb88dbd70b2e901fc309a7ad678c75a83a76fe6cced58ae47fe037d23b26ef659711b796d782ab0cec3b7ad79b7b6acfdad07c8461d0d598ffdaafb4764ddedb2e236f16702ae0e73e9f212c0359551f1b8378b387c76b01ffcf9f78ec9bbdc65c46de15a17b4c9be3666dd4d31529bd9ce97111d3b495d3ffb97f01d9377b9cb88dbc14041c24052cf50726728cd2fa9fb561ce6b8eeb77ff8d3e13b26ef749711b7810c95dd2d7c01239c9b17c2574a54d43479b4396bfff34bc3764ddeea2e236f01192bba5af8024739362f84ae94a9a868f36872d7ffe69786ec9bbdd45c46de02325774b5f0048e726c5f095d295350d1e6d0e5afffcd2f0dd9377ba8b88dbc0464aee96be0091ce4d8be12ba52a6a1a3cda1cb5fff9a5e1bb26ef751711b780855702b849674bc817e424d6c9bab6b424785f2bcff36603864ddeea3e236f00f36f2afb6034bfbbac94ac2d12db4fe7f3b4e4176fe6e6471c9bbdd48c46de01d6de55f6c0697f775929585a25b69fcfe769c82edfcdcc8e39377ba9188dbc03a67dd1784e39271a2f1f1333cad3221f7997b61d8f9bb35c826ef752411b780735bcc87b69d8765fdb0a88e7150c26be9df391faef3780f914ddeea49236f00e543ab681a11714eb32e1744da97e2ffce6ab49b5ae6f1c3239bbdd49346de01c9136928e0f945201e28f4b1ad2624279781ab92b2cde52a48377ba9278dbc039126d251c1f28a403c51e9635a4c484f2f035725659bca54906ef7524f1b7807224da4a383e5148078a3d2c6b498909e5e06ae4acb3794a920ddeea49e36f00e44275b9fb4a08b83a9146bb561277f64b6b99ef1936f2af642bbdd493d6de01c874eb73f694117075228d76ac24efec96d733de326de55ec8577ba927adbc0390e2980d77f5890915c1e74fd7c945bbad592be224abcad7d0bef7524f6b780721b5301aefeb12122b83ce9faf928b775ab257c4495795afa17deea49ed6f00e4363215b6aa38a4c828469a1dea47cd1350f73ae527f2b79830bdd493dbde01c86b642b6d54714990508d343bd48f9a26a1ee75ca4fe56f30617ba927b7bc0390d654693355b8f5a358e72e9fa11592753e892df09ccae004c3f7524f70780721ab34e4bf58484dc9699b23673a21831277be9e3d3695c1ad88eea49ee1f00e435569c97eb0909b92d33646ce74430624ef7d3c7a6d2b835b11dd493dc3e01c86aa5fa5560df799a85e3953c4e07c6a71d9a6bb50d757085a24ba927b88c0390d534b5d04c8c595d3743f6db1b8ef330badf9b8fdabae12584a7524f71280721aa522cc623e618e29a04ba18b69d4c43f569fb457545c265495ea49ee2600e435494598c47cc31c5340974316d3a9887ead3f68aea8b84ca92bd493dc4c01c86a921743e1a65c9b2938fb4c559f496f25552b13b94e709af658a927b8990390d5232e87c34cb9365271f698ab3e92de4aaa5627729ce135ecb1524f71320721aa465d0f8699726ca4e3ed31567d25bc9554ac4ee539c26bd962a49ee2640e43548c463165dfbb3bcc7fa728d4f241d752a404e0267084d956c6493dc4c91c86a9171875246c4cda1bb71b17d1dc7a0ccd42b602a8de09b4518d927b8993390d522d30ea48d899b4376e362fa3b8f4199a856c0551bc1368a31b24f71326721aa45a61d491b133686edc6c5f4771e833350ad80aa37826d1463649ee264ce43548b44fbb7c0f3d336070a584b6dbc6c492105c57a2ed4da4306d93dc4c9ac86a91672b8950cb50c9439917cf95af83e74c1b64f1a1d79b4a04dc27b8993690d522cd5712a196a19287322f9f2b5f07ce9836c9e343af369409b84f71326d21aa459a3a379bda1987911c2c047eb605fb58684008e35b6d29b7719ee264db43548b33008190610971a4f024cf25640254d8cb2c5422b3da5512e43dc4c9b786a91665010320c212e349e0499e4ac804a9b19658a84567b4aa25c87b89936f0d522cca0206418425c693c0933c95900953632cb1508acf69544b90f71326de1aa45994040c83084b8d278126792b2012a6c65962a1159ed2a89721ee264dbc3548b32808190610971a4f024cf25640254d8cb2c5422b3da5512e43dc4c9b786a91665010320c212e349e0499e4ac804a9b19658a84567b4aa25c87b89936f0d522cca0206418425c693c0933c95900953632cb1508acf69544b90f71326de1aa45994040c83084b8d278126792b2012a6c65962a1159ed2a89721ee264dbc3548b32800da2b9b6480772dc9beb8bfa4b36f32700650fd75514883ec4c9b787a91664ff1b45736c900ee5b937d717f4966de64e00ca1faeaa29107d89936f0f522cc9fe368ae6d9201dcb726fae2fe92cdbcc9c01943f5d545220fb1326de1ea45993fc6d15cdb2403b96e4df5c5fd259b7993803287ebaa8a441f6264dbc3d48b327f8663df41156d9b0818b7ee79ca9cd5a6ab2935972514a27ed4c9b787b91664fef588e40cf8415e3bae3c3f73149f8dcd011690ee1a295f3db9936f0f822cc9fdd3d2eda4bde8e4a2d944e165a8a4fe19acf1479c0452d8bb8326de1f145993fb906700d44937f1712f56254ad0afdeb304a6b4f7d8a5cbb7164dbc3e38b327f710ce01a8926fe2e25eac4a95a15fbd66094d69efb14b976e2c9b787c71664fee219c035124dfc5c4bd58952b42bf7acc129ad3df62972edc5936f0f8e2cc9fdc433806a249bf8b897ab12a56857ef5982535a7bec52e5db8b26de1f1c5993fb886700d44937f1712f56254ad0afdeb304a6b4f7d8a5cbb7164dbc3e38b327f7105a14013f464565167910bd99561b8e03f9ac4bae4b99122d9b787c72664fee1f403a5b2b62ed4ce4bee7a32aa29544029f9af3599733c85c36f0f8e5cc9fdc3d0c870f039c3d1c814a956e4d3b88afffeb7842b02e6934b96de1f1cc993fb879190e1e07387a3902952adc9a77115fffd6f085605cd26972dbc3e399327f70f2321c3c0e70f472052a55b934ee22bfffade10ac0b9a4d2e5b787c73264fee1e46438781ce1e8e40a54ab7269dc457fff5bc215817349a5cb6f0f8e64c9fdc3c8548348e69a344acc761d0ccbaee927f963c686ffe694ef97de1f1cca93fb878f3518ea7a0acb1850b900418f543077ed73cf69fccd2b8330bc3e399627f70f1d6a31d4f4159630a17200831ea860efdae79ed3f99a570661787c732c4fee1e3a60760295018ee3fab0c72e35472007b07b8003f034afb0c3f0f8e6599fdc3c734cfe5dd6d9804aad2e548462849e375ba34263dd69610588e1f1ccb43fb878e5260f145a89631812296f30bcff9a96b1f2c723b7d2c3af12c3e399697f70f1c94c1e28b512c6302452de6179ff352d63e58e476fa5875e2587c732d2fee1e392244eaa16fbeee3007282eaebf4c882c2775eeadc4b10604c0f8e65a6fdc3c723489d542df7ddc600e505d5d7e9910584eebdd5b89620c0981f1ccb4dfb878e461d4d0108c61e0eb996d1d3a7c980330489be076e2c4325313e39969cf70f1c8b3a9a02118c3c1d732da3a74f93006609137c0edc58864a627c732d39ee1e391601465ccfeedabd9e280d76971c5ef40cd33a79b5b10e38c5f8e65a74dc3c722b028cb99fddb57b3c501aed2e38bde819a674f36b621c718bf1ccb4e9b878e4560519733fbb6af678a035da5c717bd0334ce9e6d6c438e317e39969d370f1c8ac0a32e67f76d5ecf1406bb4b8e2f7a06699d3cdad8871c62fc732d3a6e1e391581465ccfeedabd9e280d76971c5ef40cd33a79b5b10e38c5f8e65a74dc3c722b028cb99fddb57b3c501aed2e38bde819a674f36b621c718bf1ccb4e9b878e4560519733fbb6af678a035da5c717bd0334ce9e6d6c438e317e39969d370f1c8ac02f40c0a443c151cbd381738625d82e64497f36d5871e06fd732d3a6f1e39157f5e8181488782a397a702e70c4bb05cc892fe6dab0e3c0dfae65a74de3c722afe49155b3de567c9e71acbf6108dbee18bd23f37531c79bff6ccb4e9bd78e455fb1e3d0f28a1321686025e141911dbeb1250c0caa338f523ee9969d37bf1c8abf53c7a1e5142642d0c04bc283223b7d624a181954671ea47dd32d3a6f7e39157ea0506954f5b2adccfd63e785c3dcdd443ef458689e3d633bb65a74df0c722afd30a0d2a9eb655b99fac7cf0b87b9ba887de8b0d13c7ac6776cb4e9be18e455fa6141a553d6cab733f58f9e170f737510fbd161a278f58ceed969d37c31c8abf4c2834aa7ad956e67eb1f3c2e1ee6ea21f7a2c344f1eb19ddb2d3a6f8639157e98506954f5b2adccfd63e785c3dcdd443ef458689e3d633bb65a74df0c722afd302ce502983bbe1cb29495337fb018b07894f32d397ac81b6db4e9be19e455fa5f59ca0530777c3965292a66ff603160f129e65a72f59036db69d37c33c8abf4be3fa6630dc55af5821f1af5f6b6c0e9dd000f10e2eb2211b7d3a6f8689157e97b0b5f1ec861186dbc0afc13e563dffbb4ac607dc2d645c770a74df0d222afd2f516be3d90c230db7815f827cac7bff76958c0fb85ac8b8ee14e9be1a4455fa5ea2d7c7b218461b6f02bf04f958f7feed2b181f70b59171dc29d37c3488abf4bd45af8f64308c36de057e09f2b1effdda56303ee16b22e3b853a6f8691157e97a842044532e7e95e787c87664e345de345724a382a645e1b0b74df0d232afd2f4f101ae312a6353fa8c5d4f4945f19ee8590d6cc51c8bdda17e9be1a4755fa5e9d2035c6254c6a7f518ba9e928be33dd0b21ad98a3917bb42fd37c348eabf4bd3a406b8c4a98d4fea31753d2517c67ba16435b314722f7685fa6f8691d57e97a740ce97142080c7ffdfb6dcc9aef2d9c2732f8be8b45f074c04df0d23bafd2f4e719d2e2841018fffbf6db9935de5b384e65f17d168be0e9809be1a4775fa5e9ce33a5c5082031fff7edb7326bbcb6709ccbe2fa2d17c1d30137c348eebf4bd39c674b8a104063ffefdb6e64d7796ce13997c5f45a2f83a6026f8691dd7e97a7385aa96ccd572a829783a2f1a6e937ea6ddbce44b15f08f005df0d23bbfd2f4e6f4165324784b787e6d40c0b45c8cdfcd663dee55fbe13840cbe1a4778fa5e9cdd0edcbd3bdfd1928574de3e8387fa21a7740026bc7c28ac1a7c348ef2f4bd39b91db97a77bfa3250ae9bc7d070ff4434ee8004d78f8515834f8691de5e97a73723b72f4ef7f464a15d378fa0e1fe8869dd0009af1f0a2b069f0d23bcbd2f4e6e402f8428bd4ef16e373b81c14362f35364c4391e0e14704d4e1a47798a5e9cdc705f08517a9de2dc6e77038286c5e6a6c988723c1c28e09a9c348ef314bd39b8e0be10a2f53bc5b8dcee07050d8bcd4d9310e4783851c13538691de6297a7371c17c2145ea778b71b9dc0e0a1b179a9b2621c8f070a3826a70d23bcc52f4e6e382f8428bd4ef16e373b81c14362f35364c4391e0e14704d4e1a47798a5e9cdc705f08517a9de2dc6e77038286c5e6a6c988723c1c28e09a9c348ef314bd39b8e04a22fba212283b94bacd2d05822b758dbd26d43551c2d939691de62a7a7371bf20584ff0fab2f9e142608202fab5131626900467a3875673d23bcc55f4e6e37d40b09fe1f565f3c284c10405f56a262c4d2008cf470eace7a47798abe9cdc6fa0d739870c12e6a3cd6483003e132745346826d9b8e1efdd048ef3158d39b8df31ae730e1825cd479ac906007c264e8a68d04db371c3dfba091de62b1a7371be635ce61c304b9a8f35920c00f84c9d14d1a09b66e387bf74123bcc5634e6e37cc6b9cc386097351e6b241801f0993a29a34136cdc70f7ee8247798ac69cdc6f98634bdfb8e94926853149283609856d2f146935b5e1f181058ef3158e39b8df2f52aa181ea8f4cfc22f58786409690258d514c768c3e4a60c1de62b1d7371be5d316688ea284c223c2b7718c009302cac566beace87caf0193bcc563be6e37cb962cd11d45098447856ee318012605958acd7d59d0f95e0327798ac77cdc6f97251ac7c5577930ba87aa28af81b1edaac05f207371f2d6465ef3158f09b8df2e32f6b5157c5889a08c20b3de82c9bdd52b8266a6b3e5c6cccde62b1e2371be5c55ed6a2af8b11341184167bd05937baa5704cd4d67cb8d999bcc563c46e37cb8a49bf9e0bec84eadad4f31f98a8cd9d458cdc05a9f9735734798ac789dc6f97131f9194c4af6c586d76ac672947f96285c5fa6750f2e85269f3158f14b8df2e253f2329895ed8b0daed58ce528ff2c50b8bf4cea1e5d0a4d3e62b1e2971be5c4a0a58abbf9413e46da777c49d1643b211c42bf940cba2eda8cc563c53e37cb89314b1577f2827c8db4eef893a2c8764238857f2819745db5198ac78a7c6f971262962aefe504f91b69ddf1274590ec84710afe5032e8bb6a33158f14f8df2e24c52c55dfca09f236d3bbe24e8b21d908e215fca065d176d4662b1e29f1be5c498319d14a617a0c992444271c95a994916ef01f009ba307e8dc563c53f37cb892f633a294c2f4193248884e392b532922dde03e0137460fd1b8ac78a7e6f97125e5286ab4534e5a900ddcfef1d60c34c56684a1c23e8c39e38158f14fddf2e24bb311faf37402dd4b988660632b7e4c0a77cd69444d188e0712b1e29fcbe5c4975623f5e6e805ba97310cc0c656fc9814ef9ad2889a311c0e2563c53f97cb892ea50911589d719d59dee5e40c2d5f12a989f9cad10462525c5ac78a7f3f97125d32d3483c084962df3a982a97da2407d2beb7bb61d8c4bef8c58f14fe8f2e24ba55a690781092c5be7530552fb4480fa57d6f76c3b1897df18b1e29fd1e5c4974a40e467aee8bb3a8672d0cdee7f601caa5a3134733131623263c53fa4cb892e930ddb280aa7d8f7c4b267c3d4f51e614f60a4c4e362646865c78a7f4a97125d251bb650154fb1ef8964cf87a9ea3cc29ec14989c6c4c8d0cb8f14fe952e24ba4a376ca02a9f63df12c99f0f53d479853d8293138d8991a1971e29fd2a5c4974946ed940553ec7be25933e1ea7a8f30a7b0526271b1323432e3c53fa54b892e92869c4d95753f1ff02f342654748443cf0b68eaa3326482a5d78a7f4aa7125d24f5f9c0b5b7e4680bdb34af28686e6a1dc195fb0634c91f8bbf14fe955e24ba49d4b4a6f63d2ef8433335c0d05042b6bb2df01bcc399259578e29fd2acc497493922a737747c418b1e337e4201feb4ff606a45d584324ccef2c53fa55a892e9271454e6ee8f883163c66fc8403fd69fec0d48bab0864999de58a7f4ab5125d24e216af367ec768af309abf2ffff132257c5559b20dc934dfcc14fe956b24ba49c32d5e6cfd8ed15e61357e5fffe2644af8aab3641b9269bf9829fd2ad6497493865abcd9fb1da2bcc26afcbfffc4c895f15566c83724d37f3053fa55ac92e9270c418c0ca311a7fc3ca2bfa7f77fef53dd570fec6b49a8a261a7f4ab5a25d24e170f2a71f2f9b27b31124577e6f63ccfb55a6234d39352e8c44fe956b54ba49c2d1e54e3e5f364f662248aefcdec799f6ab4c469a726a5d1889fd2ad6a9749385a3ca9c7cbe6c9ecc44915df9bd8f33ed56988d34e4d4ba3113fa55ad52e9270b40565e844a3f65c405ef1e72fa844a5a57f5402999a98ea237f4ab5ab5d24e1670acbd08947ecb880bde3ce5f50894b4afea805333531d446fe956b56ba49c2ce1597a1128fd971017bc79cbea1129695fd500a666a63a88dfd2ad6ad7493859c2b2f42251fb2e202f78f397d42252d2bfaa014ccd4c7511bfa55ad5ae9270b38565e844a3f65c405ef1e72fa844a5a57f5402999a98ea237f4ab5ab5d24e167038cf6141552e0ac3ab030decfef2dcaa96c2af30531ee870e956b56ca49c2cdf719ec282aa5c158756061bd9fde5b9552d855e60a63dd0e1d2ad6ad9493859be6f4fddb22b1aadc678d25fabf2299aa5074d18be4c7d45c4a55ad5b39270b37b6ab214112c97de44be6ae74fdab15d44badc8d7998fc2f8a4ab5ab6824e166f5617680cf2f923f41499bf697abc0e28421fb76f031fa0315956b56d149c2cde94eff5a4b3587013a5ffe15274ddfed02f03949dd63f5aa2c2ad6ada393859bd12a110d434170852c8cc25246921e02008cb4efb7c7ecf85955ad5b48270b37a154221a8682e10a591984a48d243c04011969df6f8fd9f0b2ab5ab6904e166f4234568db9dc249769ffcf71123ed62ffcdf161adc1fb5856656b56d219c2cde8368ad1b73b8492ed3ff9ee2247dac5ff9be2c35b83f6b0accad6ada433859bd065d6c8f9446f4e05fcc03ec40f1b6e7ee289ac76d7ed7b99a5ad5b48770b37a0b46eb77d5644c437764ce0079d9cbf7d6fd77ead7fdb11735b5ab690fe166f41519e948579efb09a6966228eba9f617a8a73231acfb63d26c6b56d220c2cde82933d290af3df6134d2cc451d753ec2f514e646359f6c7a4d8d6ada441859bd05267a5215e7bec269a5988a3aea7d85ea29cc8c6b3ed8f49b1ad5b48830b37a0a45b5c9b69ce3acfec7fd76f55460ee53fe5d3e964db2037645ab69107166f414742cb8f8072d82290cc7506a2827bf27a77ea2ec6b64212c9b56d220f2cde828d11a977adbc12c7d965b0353cfb560cef9c16b98a6c85c9946ada441f59bd05192352ef5b78258fb2cb606a79f6ac19df382d7314d90b9328d5b4883eb37a0a3246a5deb6f04b1f6596c0d4f3ed5833be705ae629b2172651ab69107d66f41464195e161ab6f8c182fa47d1dfd10e8f778cf82850642ff0a456d220fbcde828c732bc2c356df18305f48fa3bfa21d1eef19f050a0c85fe148ada441f79bd0518e6578586adbe3060be91f477f443a3dde33e0a14190bfc2915b4883ef37a0a31c570309828e288ecf9f04b6f67ed2a3b714039e8021812923b69107df6f4146373a186bb1f2b3a0570acf95e4f4036f68d44998fd4303f6486d220fbfde828c6d00433010bbc9c365e26553c1de6506cc54d58df786099091da441f80bd0518d900866021779386cbc4caa783bcca0d98a9ab1bef0c132123b4883f017a0a31b2010cc042ef270d9789954f0779941b31535637de1826424769107e02f414636402198085de4e1b2f132a9e0ef3283662a6ac6fbc304c848ed220fc05e828c6c80433010bbc9c365e26553c1de6506cc54d58df786099091da441f80bd0518d900866021779386cbc4caa783bcca0d98a9ab1bef0c132123b4883f017a0a31b2010cc042ef270d9789954f0779941b31535637de1826424769107e02f414636402198085de4e1b2f132a9e0ef3283662a6ac6fbc304c848ed220fc05e828c6c80433010bbc9c365e26553c1de6506cc54d58df786099091da441f80bd0518d90012727a2469e94e7c976dabb4c06bc0a4575e4b091322c7b5883f017b0a31b1ff24e4f448d3d29cf92edb576980d78148aebc961226458f6b107e02f6146363fe49c9e891a7a539f25db6aed301af02915d792c244c8b1ed620fc05ec28c6c7fc1fa629d025acf69c8833859df9bc2d1d6734b4459917e1ad41f80bd9518d8ff73f4c53a04b59ed3910670b3bf3785a3ace69688b322fc35a83f017b2a31b1fee0aaaffed6d165d29ed943e6fdd4edc7049152d1364612ab607e02f6646363fdb1555ffdada2cba53db287cdfba9db8e0922a5a26c8c2556c0fc05ecc8c6c7fb62aabffb5b45974a7b650f9bf753b71c12454b44d9184aad81f80bd9918d8ff6c5557ff6b68b2e94f6ca1f37eea76e38248a9689b230955b03f017b3231b1fed836c25783a7c85556a60a0ef5cb4beeff3d952d3346144f617e02f6656363fdaf6d84af074f90aaad4c141deb9697ddfe7b2a5a668c289ec2fc05eccac6c7fb5e671bb6bb7583d81264ee63cf238de3f7a29710ca1852e186f80bd9968d8ff6bb5a49c623c16a32dc96a2ef963d79efe9f1707d9130a7670ef017b32e1b1fed7540a5e4f45936e870fa0c0724715207ce8f23571f6150721ee02f665d363fdae90d5e229588d05399c0de3640d9023797ca890a3bc2a2883ec05eccbb6c7fb5d11abc452b11a0a73381bc6c81b2046f2f951214778545107d80bd9976d8ff6ba235788a5623414e670378d9036408de5f2a2428ef0a8a20fb017b32edb1fed7446af114ac46829cce06f1b206c811bcbe544851de151441f602f665db63fdae8861f482056367bc53daa98c058681a17754d2ffb92a2a27ed05eccbb7c7fb5d0f4ffb5cb79d31fb5f8219400303616ae955e85b6f5455f3db0bd997708ff6ba1d2c09121c10c67976d0f8a7fdfd20fdcd581312dba8ad8bb717b32ee21fed743958122438218cf2eda1f14ffbfa41fb9ab02625b7515b176e2f665dc43fdae8723c36a11d197c689310a8c7efeae21f300c8ea76ba2b7d2dd5eccbb897fb5d0e3047f9ae7095b53ddee17b7d7cc22665ac55faad4457149bbbd997713ff6ba1c508ff35ce12b6a7bbdc2f6faf9844ccb58abf55a88ae293777b32ee27fed7438a11fe6b9c256d4f77b85edf5f3089996b157eab5115c526eef665dc4ffdae871423fcd7384ada9eef70bdbebe611332d62afd56a22b8a4dddeccbb89ffb5d0e2847f9ae7095b53ddee17b7d7cc22665ac55faad4457149bbbd997713ff6ba1c501c05b58e01ccfe758fbd22f17aaaf3535837b685ae2adb78b32ee280ed74389f380b6b1c0399fceb1f7a45e2f555e6a6b06f6d0b5c55b6f1665dc501dae8713e7016d6380733f9d63ef48bc5eaabcd4d60deda16b8ab6de2ccbb8a03b5d0e27c6c40051ce4ca76644aaf3f83cbb5c2956e00102a71587fc6997714086ba1c4f7649262e69ff76f806224a6ff8dc9ad2588427c51e2b2a38e32ee2811d74389ed55371e7a165161b8910f75f711f18245bcc754a0c566eb1d65dc5024ae8713d9368095a103054628eee513e61a412c8625d1053e8acf7a3bcbb8a04a5d0e27b16d012b42060a8c51ddca27cc3482590c4ba20a7d159ef47797714094ba1c4f626614af30e2779b5b885a77905f62da13438670f72b3f8cf02ee2812a74389ec3583bb70e9b51b96edd7b1718b523dc21334f3deb5680bde15dc50255e8713d853c89c6ca0d05f59587bc562960a5e03d12e0d7d3ad031fc3bb8a04acd0e27b090525e640f06e6de2dc3ed44ab7a9e874d2040ba45a07e3887714095aa1c4f6110a4bcc81e0dcdbc5b87da8956f53d0e9a4081748b40fc710ee2812b54389ec2214979903c1b9b78b70fb512adea7a1d348102e91681f8e21dc50256a8713d844292f320783736f16e1f6a255bd4f43a690205d22d03f1c43b8a04ad50e27b088525e640f06e6de2dc3ed44ab7a9e874d2040ba45a07e3887714095aa1c4f611030cf20cae4303f1354a0b14eeb9b3694ecc3d08840fe150fe2812b55389ec21f619e4195c8607e26a941629dd7366d29d987a11081fc2a1fc50256aa713d843e4f4edbd867237f051f48ed33a4cb024e5f519e1e03f9f8408a04ad55e27b087b2ab0105da4a980c20b58025f3ff42c976ae5983907f5948214095aacc4f610f5556020bb4953018416b004be7fe8592ed5cb30720feb29042812b55989ec21ea36d29a23690885bffa263174f62eda5857d8bce11fd7f60950256ab413d843d36da53446d2110b7ff44c62e9ec5db4b0afb179c23fafec12a04ad56827b087a6675cc13a7a8499b7b55eedcbcf19915c0ba54f817f617c264095aad14f610f4b5acbdb21cb6bb6273784038f94914ab2c38cfafffec49c4d812b55a39ec21e9541aa0ef06d39ef063bce2f171f80bd60335c51fcfd8adc9c0256ab483d843d290f66768db0d660c444628626355fa2bb12fafff6fb175d3904ad56917b087a511ecced1b61acc18888c50c4c6abf457625f5ffedf62eba72095aad22f610f4a23d99da36c3598311118a1898d57e8aec4bebffdbec5d74e412b55a45ec21e94407460d1a5d1588d9efda5929a15b3dd3441a5bb4d8bc8dc9256ab48cd843d2870e8c1a34ba2b11b3dfb4b25342b67ba68834b769b1791b924ad56919b087a50e1d18346974562367bf6964a6856cf74d10696ed362f2372495aad233610f4a1c3a3068d2e8ac46cf7ed2c94d0ad9ee9a20d2dda6c5e46e492b55a466c21e943800732a52a7bb1056ca6bba920c12052eede8174a8bca809356ab48ce843d286f00e654a54f7620ad94d7752418240a5ddbd02e9517950126ad56919d087a50de01cca94a9eec415b29aeea48304814bbb7a05d2a2f2a024d5aad233a10f4a1bc039952953dd882b6535dd490609029776f40ba545e54049ab55a467421e943780732a52a7bb1056ca6bba920c12052eede8174a8bca809356ab48ce843d286f00e654a54f7620ad94d7752418240a5ddbd02e9517950126ad56919d087a50de01cca94a9eec415b29aeea48304814bbb7a05d2a2f2a024d5aad233a10f4a1bc039952953dd882b6535dd490609029776f40ba545e54049ab55a467421e943780732a52a7bb1056ca6bba920c12052eede8174a8bca809356ab48ce843d286f007266fdfc4c83304ca43b4c101a6885d67c70f1149502caae56919d097a50ddff70e054a56f68e351153cc0182b2f33a7a5243e262a07395dad233a13f4a1bbfd6dd301f7b5344959f73fa8284cbc8f49f68ad849541016bc5a467428e94377f967b85c9c40cb156bbb4578488fd7468e99580c8fa821d179b48ce852d286eff15b8311e557f8ad8f43511889160cb517def2751c504546f46919d0a6a50ddfe143187c778653ddd65368590a2277922a6a274635a08c31e9d233a14e4a1bbfc11243519be30a3e647396da0c3b4d4c4f8090e868411a07d4a467429d94377f812486a337c6147cc8e72db418769a989f0121d0d082340fa948ce853b286eff02490d466f8c28f991ce5b6830ed35313e0243a1a104681f52919d0a7650ddfe041e2ce58beeb475db697cf859d0c88a76b0c99f3f08d1e2a6233a14eda1bbfc073c59cb17dd68ebb6d2f9f0b3a19114ed61933e7e11a3c54c467429db4377f80e04c5eedc91345a2572ba095f398051d56f68d8f923492e998ce853b786eff01b098bddb92268b44ae57412be7300a3aaded1b1f246925d3319d0a76f0ddfe0361317bb7244d16895cae8257ce6014755bda363e48d24ba6633a14ede1bbfc06c262f76e489a2d12b95d04af9cc028eab7b46c7c91a4974cc67429dbc377f80d84c5eedc91345a2572ba095f398051d56f68d8f923492e998ce853b786eff01b024d0343efcedc766240753df266862a8995d7b21692777329d0a76f1ddfe035f49a0687df9db8ecc480ea7be4cd0c55132baf642d24eee653a14ede3bbfc06be1f5329a8ca19a0505ce377748fffb29d11b84882a49f80cb7429dbc877f80d7b3ea65351943340a0b9c6eee91fff653a23709105493f0196e853b790eff01af6095eff4ffec903f9405405ca365cf26ef3237e07927fa72ed0a76f22dfe035eb12bdfe9ffd9207f280a80b946cb9e4dde646fc0f24ff4e5da14ede45bfc06bd6257bfd3ffb240fe501501728d973c9bbcc8df81e49fe9cbb429dbc8b7f80d7ac4af7fa7ff6481fca02a02e51b2e79377991bf03c93fd3976853b7916ff01af5822024dacc2f2c24bd206849b5c2d4ee9de7a3c7627fc16ee0a76f22efe035eaf44049b5985e58497a40d0936b85a9dd3bcf478ec4ff82ddc14ede45dfc06bd5e141b8f5fe22d8be714e03a65671363a2262b4dd59ff1ffb929dbc8bcf80d7abb28371ebfc45b17ce29c074cace26c7444c569bab3fe3ff7253b79179f01af576506e3d7f88b62f9c5380e9959c4d8e8898ad37567fc7fee4a76f22f3e035eaec2ceed3abe7cee1f073c7fb232ef9450bdd9ccaa9ff91a1ca4ede45e8c06bd5d759dda757cf9dc3e0e78ff6465df28a17bb399553ff2343949dbc8bd180d7abae3fcda75c759e0a799be61484b2433c2a22b586a4fe482b2a3b7917a401af575b0bada765c19e97ab049251015ae4a04ef1ad6946fc91fa5576f22f49035eaeb5175b4ecb833d2f560924a202b5c9409de35ad28df923f4aaede45e9206bd5d6a2eb69d97067a5eac124944056b92813bc6b5a51bf247e955dbc8bd240d7abad45d6d3b2e0cf4bd582492880ad72502778d6b4a37e48fd2abb7917a481af575a846eccf08f04bfd6815eb380da4a82ce9c718f06cc92149586f22f49135eaeb4f19ebf6beb6fa7d87f89c98133fae81ce3a743cd6924436b1de45e9236bd5d69d33d7ed7d6df4fb0ff13930267f5d039c74e879ad24886d63bc8bd246d7abad3a67afdafadbe9f61fe272604cfeba0738e9d0f35a4910dac77917a48daf575a745b720ea28e366ef791aae891f3d2366c7fe442b19223598ff22f491c5eaeb4e742f675f1f2cf60a6f01bf91bde0294d3ac0ae16024485720e45e9239bd5d69cd11ff4490bc014405acfe1a2fb26351a204581ebd48925242c8bd24747abad39923fe89217802880b59fc345f64c6a34408b03d7a9124a485917a48e8f575a73247fd1242f0051016b3f868bec98d468811607af52249490b22f491d1eaeb4e641c0c7d32b66ca2e534b6f9758978b50acf0351e74494361745e923a4d5d69cc73818fa656cd945ca696df2eb12f16a159e06a3ce89286c2e8bd24749abad398e7031f4cad9b28b94d2dbe5d625e2d42b3c0d479d1250d85d17a48e93575a731c6c76424289c799e1727df3a44223d051245ceb3724a354bb2f491d27aeb4e63764fedd31e9f1b67ab1c20f407aa5c89cf4fc326b49484d775e923a505d69cc6d56101310aa45efad304a4678eba9b934963ac0d392923eefbd2474a1bad398d938327ece2aee62122d5ab4e9cdb19a63d8b7dda4252621e07a48e94475a731b17064fd9c55dcc4245ab569d39b6334c7b16fbb484a4c43c0f491d288eb4e63626cdc53e5821c0b008230fb9f2d24918a0f21d28d949a2b82e923a512d69cc6c365cb0077da9a98b8d1281f3650a74b0eca8601182935fb06d2474a26ad398d8557a8599c8b97b4296f16666497acbe18414e5e2d526d9a0ea48e944e5a731b093b630be5ed91eb0aaaf2f4c125b7a42b2edf1857a4dcd81e491d289db4e6361102d87078b18658cd22ac117a41cd70510a008cac49bb543d923a513c69cc6c2105b0e0f1630cb19a455822f4839ae0a2140119589376a87b2474a278d398d8420b61c1e2c61963348ab045e90735c144280232b126ed50f648e944f1a731b08416c383c58c32c66915608bd20e6b8288500465624ddaa1ec91d289e34e6361082d87078b18658cd22ac117a41cd70510a008cac49bb543d923a513c69cc6c2105b0e0f1630cb19a455822f4839ae0a2140119589376a87b2474a278d398d8420422e76d937f8b60077ca868869ba3c3d2c65870f6ed6b3658e944f1b731b083f106f465f4653eeb8bc5b3508c9d2a075050d6a1bddaf0acc1d289e37e636107d20de8cbe8ca7dd7178b66a1193a540ea0a1ad437bb5e15983a513c6fcc6c20fa41bd197d194fbae2f16cd423274a81d41435a86f76bc2b3074a278df98d841f40f8c8ba70901f87daf9fd03e44f32ba2d4adacdbed79fa61e944f1c031b083e71f19174e1203f0fb5f3fa07c89e65745a95b59b7daf3f4c3d289e380636107ce3e322e9c2407e1f6be7f40f913ccae8b52b6b36fb5e7e987a513c700c6c20f9c0876b5e51e7246a549c4a9ea1df7851151afc2dc6bd177104a278e028d841f3710ed6bca3ce48d4a938953d43bef0a22a35f85b8d7a2ee20944f1c051b083e6e21dad79479c91a952712a7a877de144546bf0b71af45dc41289e380a36107cdc43b5af28f392352a4e254f50efbc288a8d7e16e35e8bb882513c70146c20f9b8137db6febd86ed0c6910c699d5d6790fc73e89c3bd191505a278e029d841f36f26fb6dfd7b0dda18d2218d33abacf21f8e7d13877a322a0b44f1c053b083e6de4df6dbfaf61bb431a4431a675759e43f1cfa270ef464541689e380a76107cdbc280010a2c299eb1b154c5cc6a511f078e636aa1ae8ca4c2e13c7014fc20f9b77500021458533d6362a98b98d4a23e0f1cc6d5435d194985c278e029f841f36ee2c129b37e0ca2f2421f79b128aa5e9de451d0468a32ad4b94f1c0540083e6ddb5825366fc1945e4843ef3625154bd3bc8a3a08d14655a9729e380a80107cdbb63c5cc58c598b3f4854a4944220f5cf73c0b66d9f8cacf6e63c70150120f9b76b04cbe3c589790148760f507c3849c6e22daf373c195b91cd78e02a0341f36ed50997c78b12f20290ec1ea0f870938dc45b5e6e7832b7239af1c0540683e6ddaa132f8f1625e40521d83d41f0e1271b88b6bcdcf0656e4735e380a80d07cdbb54265f1e2c4bc80a43b07a83e1c24e37116d79b9e0cadc8e6bc701501a0f9b76a84cbe3c589790148760f507c3849c6e22daf373c195b91cd78e02a0341f36ed50258ed15e0582abc68eb0377eff970440622943802b73ddb01c0540693e6dda9f4b1da2bc0b05578d1d606efdff2e0880c452870056e7bb60380a80d27cdbb53e224d9e24ec6d31d2078705f3f4ba38fc34e769fdadd11ac1701501a5f9b76a7b449b3c49d8da63a40f0e0be7e97471f869ced3fb5ba23582e02a034bf36ed4f61548d140881749ffeae23fc7c9470beb7fe003f3b7460f06c0540698e6dda9eb2a91a281102e93ffd5c47f8f928e17d6ffc007e76e8c1e0d80a80d31cdbb53d655234502205d27ffab88ff1f251c2fadff800fcedd183c1b01501a639b76a7ac3658e2b1171cd2b723d8263640968756ab427b9aba321c3702a034c836ed4f576cb1c5622e39a56e47b04c6c812d0ead5684f7357464386e054069906dda9eae6575e37132d5cd945c26c0d0f8b84555594c4a67e8ca14dd0a80d321dbb53d5b56fe1f8f3c0e1de08513a999e7ceb2a55edaf0ccd195cdbb1501a644b76a7ab53a0e97cb4e7ebe78d6ed7b2bc5fb8d4569f83d96a32d3f772a034c8a6ed4f569002f8843735fffa97aa11e4f825542858032d72a465c22ef54069915dda9ead1005f1086e6bfff52f5423c9f04aa850b0065ae548cb845dea80d322bbb53d5a200be210dcd7ffea5ea84793e09550a1600cb5ca919708bbd501a645776a7ab44017c421b9afffd4bd508f27c12aa142c0196b95232e1177aa034c8aeed4f568802f8843735fffa97aa11e4f825542858032d72a465c22ef54069915dda9ead1005f1086e6bfff52f5423c9f04aa850b0065ae548cb845dea80d322bbb53d5a200be210dcd7ffea5ea84793e09550a1600cb5ca919708bbd501a645776a7ab44017c421b9afffd4bd508f27c12aa142c0196b95232e1177aa034c8aeed4f568802f8843735fffa97aa11e4f825542858032d72a465c22ef54069915dda9ead1005f1086e6bfff52f5423c9f04aa850b0065ae548cb845dea80d322bbb53d5a2004a33667a566128a2513f66014b683dfb779f0516708d61511a645777a7ab43ff207925a18324d3fc6f44f3fa8d2ea3f19b806629e11c66a334c8aef04f5687fd40f24b430649a7f8de89e7f51a5d47e33700cc53c238cd4669915de09ead0ffa0df6ef32e2f5d2a989d9f7e22b18b7c11a43f4a484733e8dd322bbc23d5a1ff31bedde65c5eba55313b3efc456316f823487e94908e67d1ba64577847ab43fe637dbbccb8bd74aa62767df88ac62df04690fd29211ccfa374c8aef08f5687fcc6fb7799717ae954c4ecfbf1158c5be08d21fa5242399f46e9915de11ead0ff986b814bdb05bfad506a65a61aa7e9a40c5081a64547358cde322bbc24d5a1ff2f6314f062e1e1dd58a191742d463170134d45a8878e6cbdbd6457784aab43fe5d523c39729a263d690fe9105282c1082146cdad0c1cdb1f7bc8aef0965687fcb9308acb920aaefd89ec98489cfbe0383d39ddb61539b7e2f8915de12dad0ff97161159724155dfb13d9309139f7c0707a73bb6c2a736fc5f122bbc25b5a1ff2e24e3d86f5011e78df7f274a6be5df08ef93b93451e6e12fe3457784b7b43fe5c3288d6696d89f7476cb14bccfc21c39d9d3b4c4a0cdc403c78aef0970687fcb85511acd2db13ee8ed9629799f843873b3a76989419b88078f15de12e0d0ff970a2e47f30838e05492f9191b36fecf0f61fb156e803711b31f2bbc25c2a1ff2e135c8fe61071c0a925f232366dfd9e1ec3f62add006e23663e57784b8543fe5c26453224cdb9e3d503b12a94d3f19a6582989815fddc48707daef0970b87fcb84b1676a2484a2a2cbf2f1b519fd992f2ffdd7287f8b89284fc5de12e180ff970952ced44909454597e5e36a33fb325e5ffbae50ff1712509f8bbc25c301ff2e12a59da892128a8b2fcbc6d467f664bcbff75ca1fe2e24a13f17784b8603fe5c2543fc76aef27b3e8b145a0b4f6c2f5bff997d69bc2c495cbe3ef0970c17fcb84a70ba12e8b25ca541a580791e57c49a7eddbef9382892d3bc8de12e183ff97094d17425d164b94a834b00f23caf8934fdbb7df2705125a7791bc25c307ff2e129a2e84ba2c97295069601e4795f1269fb76fbe4e0a24b4ef23784b860ffe5c25345d0974592e52a0d2c03c8f2be24d3f6edf7c9c144969de46f0970c1ffcb84a684625415f3307c45d4d3f464fbaf8a6d86b3b942592d5608ee12e1840f97094cf185cdb6b3c720b726744b4976c4f75ab82b9844825ac651ec25c3082f2e1299d30b9b6d678e416e4ce89692ed89eeb57057308904b58ca3d84b86105e5c2533a61736dacf1c82dc99d12d25db13dd6ae0ae6112096b1947b0970c20bcb84a6744ef93406b9f2de4b06ebccb358d9d556c20e7e3e2d64ccf712e1841897094ce72a04c0ba4a483f4dda9dc15ea811d2a8305f58795acb3def25c308322e1299cd5409817494907e9bb53b82bd5023a55060beb0f2b5967bde4b8610645c25339a34255b95ff837fef373d2d7296a5729b6dbfbde26b2e9bbd970c20c9b84a6733684ab72bff06ffde6e7a5ae52d4ae536db7f7bc4d65d377b2e1841937094ce665ca7c704d4708274a9baddc250f3f26863415386acbc12f75c308327e1299ccb4561e6b67f4387a1203be37c98460ccb72c5030a5979c9efb8610650c253399516d62619d4e991fa0d3deef126ea419191cc6211b2f537e070c20ca284a673292dac4c33a9d323f41a7bdde24dd483232398c42365ea6fc0e1841945094ce6525b58986753a647e834f7bbc49ba9064647318846cbd4df81c308328a1299cca442c3897b7daf128836b59f812db034873aa56c8a97ab6304861065152533994711996ba3d1c0a7c83a3166fa51be9109218d35122f586a0a0c20ca2b4a67328d2332d747a3814f907462cdf4a37d2212431a6a245eb0d4141841945694ce651a4665ae8f47029f20e8c59be946fa44248634d448bd61a828308328ad299cca3418ddb5cb6467c0f99e515fca8452b043b8ac048e7ac4f4516106515b5339946731bb6b96c8cf81f33ca2bf9508a560877158091cf589e8a2c20ca2b6a67328ce6376d72d919f03e679457f2a114ac10ee2b01239eb13d1458419456d4ce6519c53000707f9a08a84bf51264c18f3aa1871a28070d629468c08328adb99cca337321266bcc9a397c14b68749028457c2b8f875cdeac543119106515b83399466d6424cd7993472f8296d0e920508af8571f0eb9bd58a8623220ca2b7067328cda545bf39ffcf0e1bcfa67fa38977418a8ea5fcf77b1526865419456e1ce6519b334ca3fecd0444631c1961c692546594c8101faec62a674cb8328adc49cca336569947fd9a0888c63832c38d24a8cb2990203f5d8c54ce99706515b89399466ca5f3b586017739b7ed31e999c8b778d2cb04a47ae8a9b772f0ca2b7137328cd934a89096d0549b9b573035b310d4d42540cd6eb5a1538925f19456e27e6519b2521246b86e0f5f622b2ccde5a10f8aca2c5f032b12a72c8bf328adc50cca336494248d70dc1ebec456599bcb421f159458be0656254e5917e6515b8a199466c9210a406c85a3a5b4297f9a1603a40da85c40326c1a9ccc6fdca2b7144328cd92321480d90b474b6852ff342c07481b50b88064d8353998dfb9456e2886519b24642901b2168e96d0a5fe68580e9036a17100c9b06a7331bf728adc510ca33648c11328eefa8355ccc8c9332f9c864fc28cc5b920a4e67dbef515b8a229466c91722651ddf506ab999192665f390c9f85198b724149ccfb7dea2b7144528cd922e44ca3bbea0d57332324ccbe72193f0a3316e4829399f6fbd456e288a519b245c15a6d02a180d691c315fbfc6398609410f1eec4f7340837b8adc5115a33648b72b4da054301ad23862bf7f8c730c12821e3dd89ee68106f715b8a22b466c916e569b40a86035a470c57eff18e61825043c7bb13dcd020dee2b7144568cd922dc3948d9fd96cdcb9957c42629c28e72032539be789a05bfdd56e288ae19b245b77291b3fb2d9b9732af884c53851ce4064a737cf1340b7fbaadc5115c33648b6e7135c0a33199b11d2bd6c09f0097f007412955df6818a3765b8a22b966c916db6e7dd9f33995e4f22473a935f78e08092e9507bbd032eaedb7144573cd922db5690e0c93498e4c9c15ad7a63e57a380d096c6b74a06779dc6e288ae89b245b695e2e71d3697f1beff8211cbfc1529814bf1b32e640d097b9dc5115d23648b6d1486f3c53a960ba97bd086177790358242a78c1c981a2d374b8a22ba56c916da11cf0d1542923f7e746d6eae6e864d8430133df9003474aea7144574bd922db4139e1a2a85247efce8dadd5cdd0c9b0860267bf20068e95d4e288ae97b245b68273c34550a48fdf9d1b5bab9ba193610c04cf7e400d1d2ba9c5115d2f648b6d047398e34e1f8241f2037d7f2f3984ea12b5e1587d1a3bfb548a22ba5fc916da0773441f491567069bd3c126566967fc2018050cf734799aaa144574c0922db40d729a973f01308fef744874a4c92e203adc4c75eb68f4d955288ae982245b68197147872ad8c3a296b557114188ba687064db47d3d1eb56ab5115d30548b6d0316ea1670287e9c7e537744a7b07d2f8db75f8eba4a3d85157a22ba60b916da061695526b1e63612823baebcee060419b19834334647b246b044574c1822db40c15ebca610a2cea7bc4423a1d402665b5ddcaac2898f66316188ae983145b68181498ba4ce1bffd230550d6b9ffb2adeb66597e1101ece06c4115d30638b6d03011f29a2490e62271876e0ff37ecb3e56777721e1d3d9db18922ba60c816da06013e5344921cc44e30edc1fe6fd967caceeee43c3a7b3b63124574c1902db40c0208b8e1d10feb1f19a84a24d7a92dbd988a0ad471f6786a258ae983215b6818031171c3a21fd63e33509449af525b7b311415a8e3ecf0d44b15d30642b6d0300622e387443fac7c66a128935ea4b6f662282b51c7d9e1a8962ba60c856da0600c45c70e887f58f8cd425126bd496decc45056a38fb3c3512c574c190adb40c01817a075bdd514745251687572893a01834cefa31c67884659ae983216b681802f2f40eb7baa28e8a4a2d0eae51274030699df4638cf108cb35d30642d6d03005e5e81d6f75451d14945a1d5ca24e8060d33be8c719e211966ba60c85ada0600bc4916069b7f06254a5809d38c402e341513bf74e03c43d6ce74c190b6b40c01771e3e65e3d46ecd4c7cd9cf1076ba9024d3c145bd7889519de983216e681802ed3c7ccbc7a8dd9a98f9b39e20ed752049a7828b7af112a33bd30642dcd03005da050bf03c281db7e9c02d6439d148688dfb4772f2e226ea78a60c85baa0600bb30a17e078503b6fd3805ac873a290d11bf68ee5e5c44dd4f14c190b7540c01766142fc0f0a076dfa700b590e74521a237ed1dcbcb889ba9e2983216ea81802ecc285f81e140edbf4e016b21ce8a43446fda3b9797113753c530642dd503005d9850bf03c281db7e9c02d6439d148688dfb4772f2e226ea78a60c85baa0600bb302d906031da197fefd272af321f6b39ba1530ba5944def315c190b7550c01765f5b20c063b432ffdfa4e55e643ed673742a6174b289bde62b83216eaa1802ecbe4253d9743ec882771690e4c0740b0ee301054562137d70580642dd553005d97b10ba0b9553f387a5f9e7f178de7445c0ae4ce6c126fc84b10c85baab600bb2f52174172aa7e70f4bf3cfe2f1bce88b815c99cd824df90962190b7556c01765ea42e82e554fce1e97e79fc5e379d11702b9339b049bf212c43216eaad802ecbd411e2b55775febfe79c05b3beea0056001ea9920637e5c989642dd55c005d97a723c56aaeebfd7fcf380b677dd400ac003d53240c6fcb9312c85baab800bb2f4e478ad55dd7faff9e7016cefba80158007aa64818df97262590b7557001765e9c1b280368865881f4acf3c5ef4660d7fba18eec2ebf2ff04c216eaae102ecbd37365006d10cb103e959e78bde8cc1aff7431dd85d7e5fe09842dd55c205d97a6e6ca00da2196207d2b3cf17bd19835fee863bb0bafcbfc13085baab840bb2f4dc655273f10926925d346457722964e7d7b8b9bd72f98126620b7557091765e9b756b7408ee8afa772358ed6dc4927f7aa1db5d6e2f303f0c516eaae132ecbd36d3980d9caa7c1d19c37e3d5b088ae174ee7ae09c2e609858b2dd55c275d97a6d97301b3954f83a3386fc7ab61115c2e9dcf5c1385cc130b165baab84ebb2f4db27215bfd77569c928ac557eba191685364afa83089827ba2db755709e765e9b63703dd85bc13615092571256c288b32674237620e3051185c6eaae13decbd36c56c8e096458ceacca17a872d047748cc930b1201960a3d4b9dd55c27cd97a6d89652e6b7587ffdc4bfc170d988547418d0da49c2fc1494d74baab84fab2f4db11566f2f97e6623b4fc4f4432900ecab14c78b945c82943eea755709f665e9b62138f0b7dca326f95756aeae49f8377e243b5984b6052a21d5eaae13edcbd36c4171e16fb9464df2aead5d5c93f06efc4876b3096c0a5443abd55c27db97a6d8826fd5381f62fe68152780e11fd73c208b99a86ed514aa2b58aab84fb82f4db1036bbcc8eb9c5f52e21bc7ea37a4d66911df9339a72955fab255709f715e9b6205638bea840f21287c0455fc67400afa1e6b68cf4b52ad9965aae13ee3bd36c409532a2db4f4a4d3afd57220c676741c378313fa93a55cd6cc55c27dc87a6d88113266b416bfac2a1777aa6984e3466069b26a51244abb5199ab84fb91f4db102164cd682d7f58542eef54d309c68cc0d364d4a2489576a3335709f723e9b6204255ad2907d5132b15ab6fce0b8377a9a175eba08e2aeeea67ae13ee48d36c4083376caabc8088d8e323a5c40efd4d7b3d98199d1955df78d05c27dc92a6d881056ed955790111b1c6474b881dfa9af67b30333a32abbef1a0b84fb9254db1020a69c5039ed885e6445b5d3833eb9414f10ca8d062577f8742709f724b9b6204135f9c5fea876e4f408380985fcd8651dcc593fcc1af00b285e13ee49836c408254b4b1881e53f2138d3c758b7916acbb4376a55805e03090cc27dc9316d88104922a889b0a0e0c5297454d9671933bf631b1706fdbc07b61a84fb9263db1020914551136141c18a52e8a9b2ce32677ec6362e0dfb780f6c3509f724c7b620412216b47f6f59e5975d9e198d945b2d2587189e77f3f0207c6b13ee49906c4082432d68fedeb3cb2ebb3c331b28b65a4b0e313cefe7e040f8d627dc9320d88104865ad1fdbd67965d76786636516cb4961c6279dfcfc081f1ac4fb92641b102090c41b65427a58f3da4bd92949acfc7543371361b9c810587599f724c84620412170f7f00fc2180fe0147eb512d95ecd0618eae9336020cb2b43ee49909c408242d1efe01f84301fc028fd6a25b2bd9a0c31d5d266c041965687dc932138810485a3dfc03f08603f8051fad44b657b341863aba4cd80832cad0fb926427102090b4080a608de26a72c20c20b164a5c4ab0721b6f5ad106739a2f724c84f204121671014c11bc4d4e584184162c94b89560e436deb5a20ce7345ee49909e408242ce2029823789a9cb083082c5929712ac1c86dbd6b4419ce68bdc93213c8104859c4053046f1353961061058b252e2558390db7ad688339cd17b926427902090b380cb8618afd09aed88ed13e4252a8d86cc7b1b6ce06753e30724c84f30412166f1970c315fa135db11da27c84a551b0d98f636d9c0cea7c60e49909e608242cde32e1862bf426bb623b44f9094aa361b31ec6db3819d4f8c1c93213cc104859bc65c30c57e84d76c47689f2129546c3663d8db67033a9f183926427982090b3785798715ca6fd7040b9da0c1d20ebaec7275dc8dd6755870824c84f31412166ef3b433b66245d6339407a403238358588fafdedb7ceacb21149909e638242cddd0298cf791f1d492a4dbaa85c66c9330ca23e376c9d5b082393213cc804859bb905319ef23e3a92549b7550b8cd926619447c6ed93ab6104726427990090b37720a633de47c7524a936eaa1719b24cc3288f8ddb2756c208e4c84f32012166ee414c67bc8f8ea49526dd542e33649986511f1bb64ead8411c9909e640242cddc8298cf791f1d492a4dbaa85c66c9330ca23e376c9d5b082393213cc804859bb905319ef23e3a92549b7550b8cd926619447c6ed93ab6104726427990090b37720324636f49db4cd4b3b703f11a8aaeb233bd0372456c3ace5c84f32022166ee3f648c6de93b699a9676e07e235155d64677a06e48ad8759cb909e640442cddc7e552b347f4d35b7e4ba87243e9909d4879b83388e5b105798213cc809859bb8fb3668c1ab70cdf28141d470752871d109e348cd19b6225331427990140b3771f56cd18356e19be50283a8e0ea50e3a213c6919a336c44a66284f32028166ee3ea65b55f5a999a4cbcd417e9cc98256c2239659063d88af0c609e640512cddc7d3577d176209971c3174f5fb9126a9003f1f0d7cc4b117858d13cc80a359bb8fa53b0c8770e990bb1ab6b21f1a43b02878ea5d55866230af1b27990147b3771f49022b678ea983f8ed3a2a662c7dbe78ec80fd0709c46302374f32029066ee3e910456cf1d5307f1da7454cc58fb7cf1d901fa0e1388c6046e9e640520cddc7d2208ad9e3aa60fe3b4e8a998b1f6f9e3b203f41c27118c08dd3cc80a419bb8fa44115b3c754c1fc769d1533163edf3c76407e8384e231811ba799014833771f48822b678ea983f8ed3a2a662c7dbe78ec80fd0709c46302374f32029066ee3e910456cf1d5307f1da7454cc58fb7cf1d901fa0e1388c6046e9e640520cddc7d22016ec3c573760be06575fb31765fc631aeb841e6e18c231d4cc80a41abb8fa43f2dd878ae6ec17c0caebf662ecbf8c635d7083cdc318463a999014835771f487e5bb0f15cdd82f8195d7ecc5d97f18c6bae1079b86308c7533202906aee3e90fc43743b66916872ea87c3c0b3264140d208634f6dc61332a7640520d6dc7d21f712facf79f933688cdc4da95e42e0a99ebd08fad88c28094fc80a41aeb8fa43ed25f59ef3f266d119b89b52bc85c1533d7a11f5b11850129f9014835d71f487da4beb3de7e4cda2337136a5790b82a67af423eb6230a0253f202906bae3e90fb423e8d47c9ffdc71eaf3372ea0d6374f0948a32c16141ee7f40520d76c7d21f6747d1a8f93ffb8e3d5e66e5d41ac6e9e129146582c283dcfe80a41aed8fa43ece1bb5aa9f56599f328993f3a02bebfbbcfe6b270285095dfe014835dc1f487d9b376b553eacb33e651327e74057d7f779fcd64e050a12bbfc02906bb83e90fb366ed6aa7d59667cca264fce80afafeef3f9ac9c0a142577f80520d7707d21f66c69bfada7892f7c4c1965c4f955be05e29f9b9411284c93f10a41aee1fa43ecd75f91b3fbe8c17b4fff91b1eaa1da33bfeb79841f509acbe314835dc4f487d9ad4b35c0a4a7e57957cbe98bcd3a128f7a8335643ba1373bc72906bb8ae90fb359227dd9f6262d756764993f926a8346efb2ad247442701b8f520d7716d21f66b144fbb3ec4c5aeacec9327f24d5068ddf655a48e884e0371ea41aee2da43ecd621609c0856f1858555f2b2641a06b43b976f6edce09c2123e4835dc5c487d9ac32c13810ade30b0aabe564c8340d68772ededdb9c1384247c906bb8b890fb358658270215bc6161557cac990681ad0ee5dbdbb738270848f920d7717121f66b0c3c605cd84f254562c61f5a04f9b845c663f9ca6d4e1235f341aee2e343ecd61704d3125d74ad0d7d5904dc01e9ceb3877435f0d79c260fe7835dc5c787d9ac2d09a624bae95a1afab209b803d39d670ee86be1af384c1fcf06bb8b8f0fb3585a134c4975d2b435f564137007a73ace1dd0d7c35e70983f9e0d77171e1f66b0b4269892eba5686beac826e00f4e759c3ba1af86bce1307f3c1aee2e3c3ecd61684d3125d74ad0d7d5904dc01e9ceb3877435f0d79c260fe7835dc5c787d9ac2d02674a45b6c043262ed61a835303498e9330076f084c3a0f16bb8b8f1fb35859f4ce948b6d80864c5dac3506a606931d26600ede1098741e2d77171e3f66b0b3e25e4ea1a86734c43824cc8ccb7308b9f784437bf131027c6aee2e3c8ecd6167b4bc9d4350ce69887049991996e61173ef0886f7e26204f8d5dc5c791d9ac2cf623a60116f02fb3c5d5f94b2ad32056788d533af94c42431bbb8b8f24b35859eb474c022de05f678babf29655a640acf11aa675f29884863777171e4966b0b3d61aaa5d08972151cf24ab54a342df81dce18f47e2310ab06fee2e3c93cd6167ab3554ba112e42a39e4956a94685bf03b9c31e8fc4621560dfdc5c79279ac2cf566aa974225c85473c92ad528d0b7e0773863d1f88c42ac1bfb8b8f24f35859eac616540f18f6d1130f220cd120d5a36e1b8bc9b0e885727807171e49f6b0b3d574edcda8ff53ca519b107c21c111295be1dbb921a10aff301e2e3c93fd6167aad29cc0dccc0dbcceb2ed5ac3018835376e7b9803121618a04c5c79280ac2cf55953981b9981b799d65dab58603106a6edcf73006242c314098b8f25015859eab233428fdfd9d1b664881cd8b8586b75d64b285cc18587cc14171e4a03b0b3d56366851fbfb3a36cc91039b170b0d6ebac9650b9830b0f98282e3c94076167aac6591c982c3da95c49ed398ad9580bff53d8e3cf031620d4515c79280fc2cf558b3e4b890551b53b4ba7393daaa67626a25e09fa032c434ca3b8f25020859eab1508a96ab779ccf94f1b38a34d434a753f6856500358883d4871e4a0420b3d56291152d56ef399f29e3671469a8694ea7ed0aca006b1107a90e3c94084167aac5222a5aadde733e53c6ce28d350d29d4fda159400d6220f521c79281082cf558a4454b55bbce67ca78d9c51a6a1a53a9fb42b2801ac441ea438f25021059eab14816a90424733217a980505ccc2b057bf131a75c32888578881e4a0421b3d5628f2d520848e6642f5300a0b998560af7e2634eb865110af1103c94084367aac51e5aa41091ccc85ea601417330ac15efc4c69d70ca2215e22079281086cf558a3c415a79d06ff34003cf490e594e8a0784397d3d91442d6841f250210e9eab14770ec74c4db64902bf6b5844aa937237031f3cd71f885c7484e4a0421e3d5628ed1d8e989b6c92057ed6b0895526e46e063e79ae3f10b8e909c940843c7aac51da3b1d3136d9240afdad6112aa4dc8dc0c7cf35c7e2171d21392810878f558a3b4024cbb1a88aa98b327884d4c91efe013a62914f942e54828250210f2eab1476704997635115531664f109a9923dfc0274c5229f285ca90504a0421e5d5628ece0932ec6a22aa62cc9e21353247bf804e98a453e50b9520a0940843cbaac51d9c1265d8d44554c5993c426a648f7f009d3148a7ca172a414128108797558a3b3824cbb1a88aa98b327884d4c91efe013a62914f942e54828250210f2eab1476704997635115531664f109a9923dfc0274c5229f285ca90504a0421e5d5628ece01f411f4f0108af81aed97b1c72562ce436879a4db953ae0a40843cbbac51d9bf3e823e9e02115f035db2f638e4ac59c86d0f349b72a75c148108797758a3b37e0916d5e8da8540be882c1469bfb6db8b8660c533e5505c2a0210f2efb14766fb122dabd1b50a817d105828d37f6db7170cc18a67caa0b8540421e5df628ecdf6245b57a36a1502fa20b051a6fedb6e2e198314cf954170a80843cbbec51d9bec48b6af46d42a05f44160a34dfdb6dc5c3306299f2a82e1501087977d8a3b37d81d7fb73a7eb68ea04f876e93f1cbe0b3124eaf3b550766a1210f2efc14766faf3aff6e74fd6d1d409f0edd27e397c166249d5e76aa0ecd42421e5df828ecdf5e02113596d13cbd390ae3e247bd8daac6f57d18ea541f3e85843cbbf151d9bebb04226b2da2797a7215c7c48f7b1b558deafa31d4a83e7d0b087977e2a3b37d760844d65b44f2f4e42b8f891ef636ab1bd5f463a9507cfa1610f2efc54766faec1089acb689e5e9c8571f123dec6d5637abe8c752a0f9f42c21e5df8a8ecdf5d82113596d13cbd390ae3e247bd8daac6f57d18ea541f3e85843cbbf151d9bebb04226b2da2797a7215c7c48f7b1b558deafa31d4a83e7d0b087977e2a3b37d760105fbe612591d0fa85beb9e759c8d9b80b88969207d145620f2efc55766faebf20bf7cc24b23a1f50b7d73ceb391b37017112d240fa28ac41e5df8aaecdf5d7e417ef984964743ea16fae79d672366e02e225a481f4515883cbbf155d9bebafc0f104bb602f10a8bfabbf732c4a4f5bb0887108d3e8bcf117977e2acb37d75f71e20976c05e21517f577ee658949eb76110e211a7d179e22f2efc55966faebee3c412ed80bc42a2feaefdccb1293d6ec221c4234fa2f3c45e5df8ab2cdf5d7dc0494b65cedead717a2a5e18e1b85d5d2f07ae066f4601c8ccbbf15669bebafb709296cb9dbd5ae2f454bc31c370baba5e0f5c0cde8c03919977e2acd37d75f6e1252d973b7ab5c5e8a9786386e17574bc1eb819bd18072332efc559a6faebedc24a5b2e76f56b8bd152f0c70dc2eae9783d70337a300e4665df8ab34df5d7db8494b65cedead717a2a5e18e1b85d5d2f07ae066f4601c8ccbbf15669bebafb701ea9244a93bd65ac218259bb6718e258bb9e68db8c05359a77e2acd47d75f6df3d524895277acb584304b376ce31c4b1773cd1b7180a6b34efc559a8faebedbe06b6e9d72558196852cf8ee592c1b15d9abbff6b30167a6adf8ab352f5d7db7b0d6dd3ae4ab032d0a59f1dcb258362bb3577fed6602cf4d5bf1566a5ebafb6f61adba75c956065a14b3e3b964b06c5766aeffdacc059e9ab7e2acd4bd75f6dec35b74eb92ac0cb42967c772c960d8aecd5dffb5980b3d356fc559a97aebedbd86b6e9d72558196852cf8ee592c1b15d9abbff6b30167a6adf8ab352f5d7db7b062ef93918165afc226b804aa4e9453ae03c2496302d0f15cf1566a5fbafb6f5f51f17fcfd92de23c1a36314c9386cf56b3c6eec305a386bae2acd4c075f6debd2ff5584c88be473001328a911d6bc6a813d039830b48b176c559a981ebedbd795feab099117c8e60026515223ad78d5027a07306169162ed8ab35303d7db7af24be7b9def95b9f77d190523c6c0d429afb8342092d2469dc1566a608afb6f5e323e1cc6ac919c1a76fe6cc70ce78ad30a348e00f5a4a77b92acd4c125f6debc547c398d59233834edfcd98e19cf15a614691c01eb494ef72559a9824bedbd78a1b998a57fac989558c6159bb3040dcbd3965dc3a692b82e5ab35304a7db7af13373314aff59312ab18c2b3766081b97a72cbb874d25705cb566a6094fb6f5e266e66295feb262556318566ecc10372f4e59770e9a4ae0b96acd4c129f6debc4c68deab6cacaecd642fd0f5d178650de477713dd0495dbb2e59a98254edbd78975dcfaf862fc01d802c68139ae72843c39b24d79d92bd1a5db35304aadb7af12d47b1b7b935e2bdb825964f2dc4aeaf81e28c0b38257bd8bc66a60956b6f5e2591b75c81f4227fe2817f2c6537fbb86fe715a726d4af95579cd4c12ae6debc4b136eb903e844ffc502fe58ca6ff770dfce2b4e4da95f2aaf39a98255cdbd789626dd7207d089ff8a05fcb194dfeee1bf9c569c9b52be555e735304ab9b7af12c467c099a6e7a273f88c5c5a93f43a5fee3715ef6757cc4fcf6a6095746f5e25875b938bfaa5a76aa8e57edd1fded2e7d71a6e3acbaf9a439fd4c12ae9debc4b0d433970a221b1580997c3e237b403f7a8e11ed1945f362b40a98255d4bd789619128539f119c532cafc4dec675e66174c6e7fff25be6dfa825304abaa7af12c31250a73e2338a6595f89bd8cebccc2e98dcfffe4b7cdbf504a6095754f5e258624a14e7c46714cb2bf137b19d79985d31b9fffc96f9b7ea094c12aea9ebc4b0c4203c2835a48c190faf358b32e98ee25e2042552af371781398255d54d78961874078506b4918321f5e6b1665d31dc4bc4084aa55e6e2f027304abaa9af12c30e0d02f9836892e6f6899c54c39c99b1732d4bb0a8cdc7844f609575545e25861b1a05f306d125cded1338a987393362e65a9761519b8f089ec12aeaa8bc4b0c36340be60da24b9bda2671530e7266c5ccb52ec2a3371e113d8255d5517896186c6817cc1b449737b44ce2a61ce4cd8b996a5d85466e3c227b04abaaa2f12c30d85c41f0e35f90f220668b7431bff93f2d80fd6689dc79e8f709575546e25861af44963a73958466f899dd105b7650a655ae3d2910b8f575ef12aeaa8ec4b0c35d153ecd94016b50a9008048aee2ff74a608bcae1e71ec8fdf255d551e896186b92a7d9b2802d6a1520100915dc5fee94c11795c3ce3d91fbe4abaaa3d12c30d7254fb365005ad42a4020122bb8bfdd29822f2b879c7b23f7c9575547a25861ae43608c54ce1bd07ffd0c86d6f0e59cd2af227ccf08f6622fa2aeaa8f54b0c35c76c118a99c37a0fffa190dade1cb39a55e44f99e11ecc45f455d551ea96186b8e64356de05d56a2b70fe7ddb42fc55ca674e18fbf3d9a2fe9abaaa3d62c30d71b547d346d910fc825ec95e36055e8e14796057b7b7b3603d4575547ad5861ae35350cc187f8821303a5f1eeb8a22fea89d84d52f3f66daba9aeaa8f5bb0c35c696a19830ff10426074be3dd71445fd513b09aa5e7ecdb57535d551eb76186b8d260455eccb86acec6648de2da7f1dd2220d77a7ccd9b852a7baaa3d6fc30d71a34c9d16464738204495e1edacf499cc3ec731ab96b372495075547ae0861ae345254c853964d2c340f88a0351df91c0783aa5b32a66e636a1eaa8f5c20c35c6894a990a72c9a58681f11406a3bf2380f0754b6654cdcc6d43d551eb84186b8d1221446d9269ad8fbbaeee353f74a529db96d928a69b9a7e88aaa3d70930d71a234288db24d35b1f775ddc6a7ee94a53b72db2514d3734fd115547ae1261ae344611240ef67d18c1a6887efcf5c8f2cf6907a6fe976e6b9e23aa8f5c25c35c688b22481decfa31834d10fdf9eb91e59ed20f4dfd2edcd73c47551eb84b86b8d11644903bd9f463069a21fbf3d723cb3da41e9bfa5db9ae788eaa3d70970d71a22c1532d060bf288fec10be0fa63df4a342e97a50b8735e951e547ae12f1ae344572a65a0c17e511fd8217c1f4c7be94685d2f4a170e6bd2a3ca8f5c25e35c688ae54cb4182fca23fb042f83e98f7d28d0ba5e942e1cd7a547951eb84bc6b8d115c35a8dbb2cfa7021852b6a529e6034211f814e1c09af64cf3a3d70979d71a22b76b51b7659f4e0430a56d4a53cc068423f029c38135ec99e747ae12f3ae34456e62b5c77814fe8b1917a0bc9f8e6b30428c95e2ff6bdad7cf8f5c25e85c688adb517de79d005f98e9fc07a1371334887fc56e21fbd7b753a01eb84bd1b8d115b52f0e27e6d721b48bc4d56a661cc738fa371e9ff4af704b413d7097a471a22b695e1c4fcdae43691789aad4cc398e71f46e3d3fe95ee096827ae12f48e34456d2484af84832e954e6e01bd190697b0be388bcdbcfbdc2d105f5c25e92c688ada31ca8493d3c352c858cfdcb18c9543fc1bdbc139c7b87460ceb84bd268d115b453950927a786a590b19fb963192a87f837b782738f70e8c19d7097a4d1a22b68a72a124f4f0d4b21633f72c632550ff06f6f04e71ee1d1833ae12f49a34456d147154a296b80be6e434b480be410026089a22f8e0dc3bd4685c25e935688ada276ebb9dda467a5080362f2974785e740be0884dbeb8794cd1b84bd26bd115b44d69899461635723b839247ae0e71b10126d52f77a70f43da47097a4d8a22b68995f25816f9d10ca283f0f1db9c494481f86e84af1e1ea1f49e12f49b24456d1314a5d5b8c108417084ae4636b7f86b839ba12f1e0c3d5e294c25e936588ada26120cd0fc4f76ab0c8628eeecef56b986e20683fbe87ad692a84bd26cc115b44c1419a1f89eed56190c51ddd9dead730dc40d07f7d0f5ad255097a4d9822b689820f4697c0b40d45d95701e333cc0c89b32de35af71eb748ab12f49b31456d13031e8d2f81681a8bb2ae03c667981913665bc6b5ee3d6e915625e936628ada26063d1a5f02d03517655c078ccf303226ccb78d6bdc7add22ac4bd26cc515b44c0c064716b276ccb18284d5419656c275941b5d33b5f5bbe95997a4d98b2b6898170c8e2d64ed99630509aa832cad84eb2836ba676beb77d2b32f49b31656d1302e191c5ac9db32c60a135506595b09d6506d74ced7d6efa5665e93662cada2605c3238b593b6658c1426aa0cb2b613aca0dae99dafaddf4accbd26cc595b44c0b864716b276ccb18284d5419656c275941b5d33b5f5bbe95997a4d98b2b689817054f52efbaff8b308676e5ac2ceacda7e17e8d2bbb77ecf33f49b31666d1302df35fcb6a43653e8c89ba2dd7d93b7dcf6dc1401746eff4268e93662cdda2605bd6bf96d486ca7d1913745bafb276fb9edb82802e8ddfe84d1d26cc59bb44c0b7a6405333dafb225da3b519dee453d9bd61c9261cebbfeada4a4d98b38689816f3541cbf2835c6ce6c436963d480d95fa6e5671f9a77feff4a49b31671d1302de5344bd6fd41f01f905398efa0f810e74877109b31efffa29593662ce4a2605bc96897adfa83e03f20a731df41f021ce90ee213663dfff452b26cc59c944c0b7925d41b4a1de2300f91b29e67bd6a1c51c8884c8c4c0002e574d98b39389816f234695c1f092a884aa0319f4efa3a1b233bd4bed86800200af9b3167281302de45193ddc8dfbb38c0bd2fa11d73da18c6226da370a0005a5603662ce512605bc89327bb91bf7671817a5f423ae7b4318c44db46e14000b4ac06cc59ca24c0b791264f77237eece302f4be8475cf68631889b68dc2800169580d98b39449816f22456013d1cb3fee3166496b6b1e36a8b0be314144d002ecf02b316728a302de4473814d2e63e6048e495f3955bbd333e12726a8497005f4206662ce515605bc88d7029a5cc7cc091c92be72ab77a667c24e4d5092e00be840ccc59ca2ac0b7911a6c65a445cfe3a64a24947d66eb2b204475ec6e59017eac1a98b39456816f223364dda1387629cf4c15ef22c5ccb46883981b38af02fefc36316728ae02de446555cd9b1dc2b6214ff8a46d838fc6f901dc78cd5b05ff9c6d62ce515d05bc88c937ad8ee85bcec557be0f02ff15ec19fe6533f6b30c00dcdbc59ca2bb0b7911916f5b1dd0b79d8aaf7c1e05fe2bd833fcca67ed661801b9b78b39457616f223226ac8944e459d9816c50233f44e0e8ff4411236c93005177016728aed2de4464361a38149619db2e556ca8fe0927b47e32e66c98f600bd2e12ce515db5bc88c854f595b3f999de8827a5b47b91b54b7c1090fef1bc01949c359ca2bb7b79119092ac50f2c099e53bcc17cb76a2d07977cbe623a3480343787b39457706f223211558a1e58133ca77982f96ed45a0f2ef97cc4746900686f0f6728aee0de4464223726955cfcdbd1aad2b905a0aa7c85eda5cb44cf00d2821fce515dc2bc88c8436e4d2ab9f9b7a355a5720b4154f90bdb4b96899e01a5043f9ca2bb857911908668acae20c9d1c96317aa3e7aa0503fb1436f6f39034bac803945770bf223210b5d6bb4ee6a06157dfc1aa4ed36fea75d33213a6f0698fd01728aee18e446421546e9c289aa6eadb3c4fb71d2645b76b51284d0db0d339e03e515dc32c88c842919e5ddc02b3fde1f56bd0b9cbf151564d14bfdb31a68e008ca2bb8669119085133cbbb80567fbc3ead7a17397e2a2ac9a297fb6634d1c011945770cd223210a267977700acff787d5af42e72fc545593452ff6cc69a3802328aee19a446421445b4146ae306173b282ae84ddef06d32136a24995d348a447515dc33588c842874294e60937256a1cd22331b3d46bce3d1986ef28a692ec8fa2bb866c1190850d113c24bf44ad56f1710c8b5f9f35c474df503a4e4d277d2045770cd923210a192278497e895aade2e21916bf3e6b88e9bea0749c9a4efa408aee19b24642143244f092fd12b55bc5c4322d7e7cd711d37d40e939349df48115dc33648c84286415f37ea6fbcd3a43552a82f4f00c4ba1a6c42e6f693d8d032bb866ca190850c72be6fd4df79a7486aa5505e9e01897434d885cded27b1a065770cd943210a18e57cdfa9bef34e90d54aa0bd3c0312e869b10b9bda4f6340caee19b286421431c3bae4de4b4cc54d2761a3f9f76c08507e263cf7849ee0c1a5dc33651c8428637036ef4763ffb2c5cb8faa736e3df320a7109faed93ddbc35bb866ca490850c6d06dde8ec7ff658b971f54e6dc7be6414e213f5db27bb786b770cd949210a18da0dbbd1d8ffecb172e3ea9cdb8f7cc829c427ebb64f76f0d6ee19b292421431b41b77a3b1ffd962e5c7d539b71ef99053884fd76c9eede1addc3365248428636836ef4763ffb2c5cb8faa736e3df320a7109faed93ddbc35bb866ca490850c6d06dde8ec7ff658b971f54e6dc7be6414e213f5db27bb786b770cd949210a18da067cf763cd52d99e60b6ff5b0ee2aaa96eec11761f770b16fe19b292521431b3f5bb1452680bdb683e3a61359d2b37d2889c48ac0eee306e0c336524b4286367d4374e2f9d7ddefbf94124eab9bc5224bbfcb717eddc7b1c2866ca497850c6cf912fc1ea0861e6236f4eac54f2de86c922bd93efabb9107860cd949300a18d9f125f83d410c3cc46de9d58a9e5bd0d92457b27df577220f0c19b292601431b3e24bf07a82187988dbd3ab153cb7a1b248af64fbeaee441e18336524c0286367c423f34db10755946f741c527165a18c8c0b0c53d2dc89e03166ca498150c6cf8747e69b620eab28dee838a4e2cb4319181618a7a5b913c062cd949302a18d9f0e1bdf8f70f3b8d4759d3771bd8ce45a2ad873ab48722924c69b292606431b3e1b37bf1ee1e771a8eb3a6ee37b19c8b455b0e75690e452498d36524c0c86367c366f7e3dc3cee351d674ddc6f6339168ab61cead21c8a4931a6ca498190c6cf86c6b0ed43474292664b681b5e45d80f9516fdfb640914aca35d949303318d9f0d762300115beb4cf8139c993c0b1601a9d8c01c87e2297386cb292606731b3e1ad50725ad853cc21ba40594f79591e5d35c445ecf9453014da6524c0cf6367c3592cf70e5d7dfac62c4d78c6eaa89ae26634ce35ef8a61cdb5ca49819fc6cf86b159ee1cbafbf58c589af18dd55135c4cc699c6bdf14c39b6b9493033f8d9f0d623fee9222ce4d9b6902a943a298c9b1937f7b33bb2988dad8292606801b3e1ac30bef7cf272fdb989d218af3d27f18b21ab38c373531359b1524c0d01367c358517def9e4e5fb7313a4315e7a4fe31643567186e6a626b362a4981a026cf86b0a2fbdf3c9cbf6e6274862bcf49fc62c86ace30dcd4c4d66c549303404d9f0d6145f7be79397edcc4e90c579e93f8c590d59c61b9a989acd8a92606809b3e1ac284b0a27d4063e1b54ee511bca7576da155fce933231373f1624c0d01467c3584f2226a854e2deb961a9685f8ce14bdc256bdf82616270222d4981a029cf86b09d444d50a9c5bd72c352d0bf19c297b84ad7bf04c2c4e0445a930340539f0d613a14acfa0061dd683e7267a62b7b8d98905bc0658289c22cb6260680a83e1ac273" ], "commitments": [ "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0xa572cbea904d67468808c8eb50a9450c9721db309128012543902d0ac358a62ae28f75bb8f1c7c42c39a8c5529bf0f4e", "0xa421e229565952cfff4ef3517100a97da1d4fe57956fa50a442f92af03b1bf37adacc8ad4ed209b31287ea5bb94d9d06" ], "proofs": [ "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "0xa2aeea08a9cd37fb0b089b1938bbe7eedd4ea6120dc70f45d59ad077008d08be115b858350b1eff645148fe4470b65c8" ] } } ================================================ FILE: testing/files/test_data_incorrect_proof.json ================================================ { "input": { "blob": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "commitment": "0x93efc82d2017e9c57834a1246463e64774e56183bb247c8fc9dd98c56817e878d97b05f5c8d900acf1fbbbca6f146556", "proof": "0x8e5995b8136efc6e4a6d915ecfbeef542a44c1749afef58cac423e24e8dc2d03387faea0adc29ad454cdeae0be44d139" } } ================================================ FILE: testing/forge-script/Makefile ================================================ #!/usr/bin/make -f ############################################################################### ### Kurtosis ### ############################################################################### export IP_ADDRESS := $(shell ifconfig | grep 'inet ' | grep -v '127.0.0.1' | awk '{ print $$2 }' | head -n 1) get-ip-address: @echo "IP Address: $(IP_ADDRESS)" # Starts a Kurtosis enclave containing a local devnet start-forge-script: install-kurtosis get-ip-address kurtosis run ./testing/forge-script --args-file ./testing/forge-script/forge-config.yaml \ --enclave forge-devnet # Stops the running Kurtosis enclave stop-forge-script: kurtosis enclave stop forge-devnet # Stops and removes the specified Kurtosis enclave reset-forge-script: $(MAKE) stop-forge-script kurtosis enclave rm forge-devnet # Removes the specified Kurtosis enclave rm-forge-script: kurtosis enclave rm forge-devnet --force # Lints Starlark (.star) files in the Kurtosis directory using buildifier star-lint-forge-script: @$(MAKE) buildifier-install @echo "--> Running buildifier to format starlark files..." find ./testing/forge-script -name "*.star" -exec buildifier -mode=check {} + # Automatically fixes formatting issues in Starlark (.star) files using buildifier star-fix-forge-script: @$(MAKE) buildifier-install @echo "--> Running buildifier to format starlark files..." find ./testing/forge-script -name "*.star" -exec buildifier --mode=fix {} + # Marks targets as not being associated with files .PHONY: start-forge-script stop-forge-script reset-forge-script rm-forge-script star-lint-forge-script star-fix-forge-script ================================================ FILE: testing/forge-script/README.md ================================================ # Smart Contract Deployment Instructions ## General guidelines about `forge-config.yaml` - The format of the `repository` should be `github.com//`. Refer to the Kurtosis documentation on [locators](https://docs.kurtosis.com/advanced-concepts/locators) for more information. - The `script_path` should be relative to the `repository` and `contracts_path` (if present). - For the wallet, currently only `private_key` is supported. - For `rpc_url`, - URL for externally running network. - If you want to spin up a devnet locally, you could use Kurtosis `make start-devnet`. `rpc_url` would be `http://HOST_IP_ADDRESS:8547` , Do not change the port as 8547 is the public port for the execution client node. - If the smart contract has prerequisites or dependencies, set the `dependency` `status` to true. Ensure that the `dependency.sh` file is completed or provide an appropriate shell script in the `forge-script` folder. This is necessary when additional setup is required before deployment. ## There could be different cases - - **Contract directory does not use git submodules** If the contract directory does not use git submodules, provide the path up to the contracts in the `repository` and leave `contracts_path` as an empty string. - **Contract directory use git submodules** If the contract directory uses git submodules, then we need to clone the whole repository to get the submodules. In that case, we need to provide the `repository` at the root level and `contracts_path` where the contracts are present. ## Notes: If there's a contract present locally, the only two options supported by kurtosis are : - The directory should be present inside the same kurtosis package as the current one. - Use github URL. Edge scenario: This would not be supported if the contracts are part of this repository - beacon-kit, in that case, fork the repository into your user profile and use that as a repository. I know this is a kind of workaround, until Kurtosis supports local URLs, we don't really have a choice. **Example for running contracts in beacon-kit** ```bash repository: "github.com/nidhi-singh02/beacon-kit" contracts_path: "contracts" script_path: "script/DeployAndCallERC20.s.sol" contract_name: "DeployAndCallERC20" ``` ## Example for GitHub hosted repository ```bash repository: "github.com/nidhi-singh02/solidity-scripting/" contracts_path: "" script_path: "script/NFT.s.sol" contract_name: "MyScript" ``` ## Deploy PoL Smart Contract ```bash repository: "github.com/berachain/contracts-monorepo" contracts_path: "" script_path: "script/pol/DeployPoL.s.sol" contract_name: "DeployPoL" dependency: status : true path: "dependency.sh" ``` ================================================ FILE: testing/forge-script/dependency/dependency.sh ================================================ #!/bin/sh # SPDX-License-Identifier: BUSL-1.1 # # Copyright (C) 2025, Berachain Foundation. All rights reserved. # Use of this software is governed by the Business Source License included # in the LICENSE file of this repository and at www.mariadb.com/bsl11. # # ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY # TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER # VERSIONS OF THE LICENSED WORK. # # THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF # LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF # LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). # # TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON # AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, # EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND # TITLE. apk update && apk add --no-cache nodejs npm npm --version npm install -g bun bun --version cd /app/contracts && bun install echo "Bun installation complete!" ================================================ FILE: testing/forge-script/forge-config.yaml ================================================ # SPDX-License-Identifier: BUSL-1.1 # # Copyright (C) 2025, Berachain Foundation. All rights reserved. # Use of this software is governed by the Business Source License included # in the LICENSE file of this repository and at www.mariadb.com/bsl11. # # ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY # TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER # VERSIONS OF THE LICENSED WORK. # # THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF # LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF # LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). # # TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON # AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, # EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND # TITLE. # Please refer to the README.md file for more information on how to fill this file. deployment: repository: "github.com/nidhi-singh02/beacon-kit" # give repo name if there are submodules, else give the folder till contracts contracts_path: "contracts" # give the path till contracts, if the repository is the contract folder itself, then leave it empty script_path: "script/DeployAndCallERC20.s.sol" # this must be relative to the repository path + contracts_path(if applicable) contract_name: "DeployAndCallERC20" dependency: type: "none" # type can be `git` or `local` or `none` path: "script/berps/dependency/dependency.sh" rpc_url: "http://HOST_IP_ADDRESS:8547" # If you spin up local devnet via kurtosis, then public port is 8547 wallet: type: "private_key" # currently only private_key wallet is supported. Do not change the type. value: "0xfffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306" # private key of the account which will deploy the contract. ================================================ FILE: testing/forge-script/kurtosis.yml ================================================ # SPDX-License-Identifier: BUSL-1.1 # # Copyright (C) 2025, Berachain Foundation. All rights reserved. # Use of this software is governed by the Business Source License included # in the LICENSE file of this repository and at www.mariadb.com/bsl11. # # ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY # TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER # VERSIONS OF THE LICENSED WORK. # # THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF # LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF # LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). # # TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON # AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, # EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND # TITLE. name: github.com/berachain/beacon-kit/testing/forge-script description: |- This is a package that provides a script to deploy a smart contract. It is intended to be used for development/local testing purposes. ================================================ FILE: testing/forge-script/main.star ================================================ SOURCE_DIR_PATH = "/app/contracts" IMAGE_FOUNDRY = "ghcr.io/foundry-rs/foundry:latest" ENTRYPOINT = ["/bin/sh"] DEPENDENCY_DIR_PATH = "/app/dependency" def run(plan, deployment = {}): deploy_contracts(plan, deployment) # Define the function to run the Forge script for deployment def deploy_contracts(plan, deployment): repository = deployment["repository"] contracts_path = deployment["contracts_path"] script_path = deployment["script_path"] contract_name = deployment["contract_name"] rpc_url = deployment["rpc_url"] wallet = deployment["wallet"] dependency = deployment["dependency"] dependency_type = dependency["type"] # TODO: Support other wallet options such as mnemonics, keystore, hardware wallets. if wallet["type"] == "private_key": wallet_command = "--private-key {}".format(wallet["value"]) else: fail("Wallet type {} not supported.".format(wallet["type"])) folder = plan.upload_files(src = repository, name = "contracts") dependency_artifact_name = "" if dependency_type == "local" or dependency_type == "git": dependency_path = dependency["path"] plan.upload_files(src = "dependency", name = "dependency") dependency_artifact_name = "dependency" foundry_service = plan.add_service( name = "foundry", config = get_service_config(dependency_artifact_name), ) if contracts_path: contract_path = "{}/{}".format(SOURCE_DIR_PATH, contracts_path) else: contract_path = SOURCE_DIR_PATH if dependency_type == "local": # Run shell script plan.exec( service_name = foundry_service.name, recipe = ExecRecipe( command = ["/bin/sh", "-c", "sh {}/{}".format(DEPENDENCY_DIR_PATH, dependency_path)], ), ) elif dependency_type == "git": plan.exec( service_name = foundry_service.name, recipe = ExecRecipe( command = ["/bin/sh", "-c", "cd {} && sh {}".format(contract_path, dependency_path)], ), ) if script_path: result = plan.exec( service_name = foundry_service.name, recipe = ExecRecipe( command = ["/bin/sh", "-c", "cd {} && forge build".format(contract_path)], ), ) plan.verify(result["code"], "==", 0) script_output = exec_on_service( plan, foundry_service.name, "cd {} && forge script {}:{} --broadcast --rpc-url {} {} --json --skip test > output.json ".format( contract_path, script_path, contract_name, rpc_url, wallet_command, ), ) exec_on_service( plan, foundry_service.name, "cat {}/output.json ".format(contract_path), ) if script_path: # Get the forge script output in a output.json file and grep from it transaction_file = "grep 'Transactions saved to' output.json | awk -F': ' '{print $2}'" plan.print("transaction_file", transaction_file) transaction_file_details = exec_on_service(plan, foundry_service.name, "cd {} && {}".format(contract_path, transaction_file)) if not transaction_file_details["output"]: fail("Transaction file not found.") exec_output = exec_on_service(plan, foundry_service.name, "chmod -R 777 /app/contracts && cat {}".format(transaction_file_details["output"])) plan.verify(exec_output["code"], "==", 0) def exec_on_service(plan, service_name, command): return plan.exec( service_name = service_name, recipe = ExecRecipe( command = ["/bin/sh", "-c", command], ), ) def get_service_config(dependency_artifact_name = None): files = { SOURCE_DIR_PATH: "contracts", } if dependency_artifact_name: files[DEPENDENCY_DIR_PATH] = dependency_artifact_name return ServiceConfig( image = IMAGE_FOUNDRY, entrypoint = ENTRYPOINT, files = files, ) ================================================ FILE: testing/networks/80069/app.toml ================================================ # This is a TOML config file. # For more information, see https://github.com/toml-lang/toml ############################################################################### ### Base Configuration ### ############################################################################### # default: the last 362880 states are kept, pruning at 10 block intervals # nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) # everything: 2 latest states will be kept; pruning at 10 block intervals. # custom: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' pruning = "everything" # These are applied if and only if the pruning strategy is custom. pruning-keep-recent = "0" pruning-interval = "0" # HaltHeight contains a non-zero block height at which a node will gracefully # halt and shutdown that can be used to assist upgrades and testing. # # Note: Commitment of state will be attempted on the corresponding block. halt-height = 0 # HaltTime contains a non-zero minimum block time (in Unix seconds) at which # a node will gracefully halt and shutdown that can be used to assist upgrades # and testing. # # Note: Commitment of state will be attempted on the corresponding block. halt-time = 0 # MinRetainBlocks defines the minimum block height offset from the current # block being committed, such that all blocks past this offset are pruned # from CometBFT. It is used as part of the process of determining the # ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates # that no blocks should be pruned. # # This configuration value is only responsible for pruning CometBFT blocks. # It has no bearing on application state pruning which is determined by the # "pruning-*" configurations. # # Note: CometBFT block pruning is dependant on this parameter in conjunction # with the unbonding (safety threshold) period, state pruning and state sync # snapshot parameters to determine the correct minimum value of # ResponseCommit.RetainHeight. min-retain-blocks = 0 # InterBlockCache enables inter-block caching. inter-block-cache = true # IndexEvents defines the set of events in the form {eventType}.{attributeKey}, # which informs CometBFT what to index. If empty, all events will be indexed. # # Example: # ["message.sender", "message.recipient"] index-events = [] # IavlCacheSize set the size of the iavl tree cache (in number of nodes). iavl-cache-size = 781250 # IAVLDisableFastNode enables or disables the fast node feature of IAVL. # Default is false. iavl-disable-fastnode = true # AppDBBackend defines the database backend type to use for the application and snapshots DBs. # An empty string indicates that a fallback will be used. # The fallback is the db_backend value set in CometBFT's config.toml. app-db-backend = "pebbledb" ############################################################################### ### Telemetry Configuration ### ############################################################################### [telemetry] # Prefixed with keys to separate services. service-name = "beacond_node" # Enabled enables the application telemetry functionality. When enabled, # an in-memory sink is also enabled by default. Operators may also enabled # other sinks such as Prometheus. enabled = true # Enable prefixing gauge values with hostname. enable-hostname = true # Enable adding hostname to labels. enable-hostname-label = true # Enable adding service to labels. enable-service-label = true # PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. prometheus-retention-time = 60 # GlobalLabels defines a global set of name/value label tuples applied to all # metrics emitted using the wrapper functions defined in telemetry package. # # Example: # [["chain_id", "cosmoshub-1"]] global-labels = [] # MetricsSink defines the type of metrics sink to use. metrics-sink = "" # StatsdAddr defines the address of a statsd server to send metrics to. # Only utilized if MetricsSink is set to "statsd" or "dogstatsd". statsd-addr = "" # DatadogHostname defines the hostname to use when emitting metrics to # Datadog. Only utilized if MetricsSink is set to "dogstatsd". datadog-hostname = "my_beacond_node" ############################################################################### ### BeaconKit ### ############################################################################### [beacon-kit] # ChainSpec is the type of chain spec to use. chain-spec = "testnet" # ChainSpecFilePath is the path to the chain spec file to use. chain-spec-file = "" # ShutdownTimeout is the maximum time to wait for the node to gracefully # shutdown before forcing an exit. shutdown-timeout = "5m0s" [beacon-kit.engine] # HTTP url of the execution client JSON-RPC endpoint. rpc-dial-url = "http://localhost:8551" # RPC timeout for execution client requests. rpc-timeout = "2s" # RPC retry interval for execution client requests. rpc-retry-interval = "100ms" # RPC max retry interval for execution client requests. rpc-max-retry-interval = "10s" # Interval for the startup check. rpc-startup-check-interval = "3s" # Interval for the JWT refresh. rpc-jwt-refresh-interval = "30s" # Path to the execution client JWT-secret jwt-secret-path = "~/.beacond/config/jwt.hex" [beacon-kit.logger] # TimeFormat is a string that defines the format of the time in the logger. time-format = "RFC3339" # LogLevel is the level of logging. Logger will log messages with verbosity up # to LogLevel. log-level = "info" # Style is the style of the logger. style = "pretty" [beacon-kit.kzg] # Path to the trusted setup path. trusted-setup-path = "~/.beacond/config/kzg-trusted-setup.json" # KZG implementation to use. # Options are "crate-crypto/go-kzg-4844". implementation = "crate-crypto/go-kzg-4844" [beacon-kit.payload-builder] # Enabled determines if the local payload builder is enabled. # It should be enabled for validators, but it can be disabled # for full nodes. enabled = true # Post bellatrix, this address will receive the transaction fees produced by any blocks # from this node. suggested-fee-recipient = "0x0000000000000000000000000000000000000000" # The timeout for local build payload. This should match, or be slightly less # than the configured timeout on your execution client. It also must be less than # timeout_proposal in the CometBFT configuration. payload-timeout = "850ms" [beacon-kit.validator] # Graffiti string that will be included in the graffiti field of the beacon block. graffiti = "" # AvailabilityWindow is the number of slots to keep in the store. # Setting AvailabilityWindow to 0 disables block store and does not allow the node # to serve proof or namespace apis from beacon node-api. availability-window = "8192" [beacon-kit.node-api] # Enabled determines if the node API is enabled. enabled = "false" # Address is the address to bind the node API to. address = "0.0.0.0:3500" # Logging determines if the node API logging is enabled. logging = "false" ================================================ FILE: testing/networks/80069/cl-seeds.txt ================================================ e56e965bd53832d47cf2f7cc2b7118c20c0c5b19@34.89.234.189:26656,58b349f2d3f2206798aae4f8d87141f095095503@34.159.220.160:26656,9499000274a522d85f91dbdac26945bbe2a144ba@35.234.244.49:26656,a5ccf1b754651ec080dabc7e065d078ab2bc83bb@34.95.45.160:26656,a78ae6958f2f0683d50d8342d00beac991a51b9e@67.213.122.179:26656,2c617ccd984310c0f4f3ce9e226dec6c8eda2435@206.223.224.23:26656 ================================================ FILE: testing/networks/80069/client.toml ================================================ # This is a TOML config file. # For more information, see https://github.com/toml-lang/toml ############################################################################### ### Client Configuration ### ############################################################################### # The network chain ID chain-id = "testnet-beacon-80069" # The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) keyring-backend = "test" # CLI output format (text|json) output = "text" # : to Tendermint RPC interface for this chain node = "tcp://localhost:26657" # Transaction broadcasting mode (sync|async) broadcast-mode = "sync" ================================================ FILE: testing/networks/80069/config.toml ================================================ # This is a TOML config file. # For more information, see https://github.com/toml-lang/toml # NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or # relative to the home directory (e.g. "data"). The home directory is # "$HOME/.cometbft" by default, but could be changed via $CMTHOME env variable # or --home cmd flag. # The version of the CometBFT binary that created or # last modified the config file. Do not modify this. version = "1.0.0" ####################################################################### ### Main Base Config Options ### ####################################################################### # TCP or UNIX socket address of the ABCI application, # or the name of an ABCI application compiled in with the CometBFT binary proxy_app = "tcp://127.0.0.1:26658" # A custom human readable name for this node moniker = "oogabooga" # Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb # * goleveldb (github.com/syndtr/goleveldb - most popular implementation) # - pure go # - stable # * cleveldb (uses levigo wrapper) # - fast # - requires gcc # - use cleveldb build tag (go build -tags cleveldb) # * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt) # - EXPERIMENTAL # - may be faster is some use-cases (random reads - indexer) # - use boltdb build tag (go build -tags boltdb) # * rocksdb (uses github.com/tecbot/gorocksdb) # - EXPERIMENTAL # - requires gcc # - use rocksdb build tag (go build -tags rocksdb) # * badgerdb (uses github.com/dgraph-io/badger) # - EXPERIMENTAL # - use badgerdb build tag (go build -tags badgerdb) db_backend = "pebbledb" # Database directory db_dir = "data" # Output level for logging, including package level options log_level = "info" # Output format: 'plain' (colored text) or 'json' log_format = "plain" ##### additional base config options ##### # Path to the JSON file containing the initial validator set and other meta data genesis_file = "config/genesis.json" # Path to the JSON file containing the private key to use as a validator in the consensus protocol priv_validator_key_file = "config/priv_validator_key.json" # Path to the JSON file containing the last sign state of a validator priv_validator_state_file = "data/priv_validator_state.json" # TCP or UNIX socket address for CometBFT to listen on for # connections from an external PrivValidator process priv_validator_laddr = "" # Path to the JSON file containing the private key to use for node authentication in the p2p protocol node_key_file = "config/node_key.json" # Mechanism to connect to the ABCI application: socket | grpc abci = "socket" # If true, query the ABCI app on connecting to a new peer # so the app can decide if we should keep the connection or not filter_peers = false ####################################################################### ### Advanced Configuration Options ### ####################################################################### ####################################################### ### RPC Server Configuration Options ### ####################################################### [rpc] # TCP or UNIX socket address for the RPC server to listen on laddr = "tcp://127.0.0.1:26657" # A list of origins a cross-domain request can be executed from # Default value '[]' disables cors support # Use '["*"]' to allow any origin cors_allowed_origins = [] # A list of methods the client is allowed to use with cross-domain requests cors_allowed_methods = ['HEAD', 'GET', 'POST'] # A list of non simple headers the client is allowed to use with cross-domain requests cors_allowed_headers = ['Origin', 'Accept', 'Content-Type', 'X-Requested-With', 'X-Server-Time'] # Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool unsafe = false # Maximum number of simultaneous connections (including WebSocket). # Does not include gRPC connections. See grpc_max_open_connections # If you want to accept a larger number than the default, make sure # you increase your OS limits. # 0 - unlimited. # Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} # 1024 - 40 - 10 - 50 = 924 = ~900 max_open_connections = 900 # Maximum number of unique clientIDs that can /subscribe # If you're using /broadcast_tx_commit, set to the estimated maximum number # of broadcast_tx_commit calls per block. max_subscription_clients = 100 # Maximum number of unique queries a given client can /subscribe to # If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to # the estimated # maximum number of broadcast_tx_commit calls per block. max_subscriptions_per_client = 5 # Experimental parameter to specify the maximum number of events a node will # buffer, per subscription, before returning an error and closing the # subscription. Must be set to at least 100, but higher values will accommodate # higher event throughput rates (and will use more memory). experimental_subscription_buffer_size = 200 # Experimental parameter to specify the maximum number of RPC responses that # can be buffered per WebSocket client. If clients cannot read from the # WebSocket endpoint fast enough, they will be disconnected, so increasing this # parameter may reduce the chances of them being disconnected (but will cause # the node to use more memory). # # Must be at least the same as "experimental_subscription_buffer_size", # otherwise connections could be dropped unnecessarily. This value should # ideally be somewhat higher than "experimental_subscription_buffer_size" to # accommodate non-subscription-related RPC responses. experimental_websocket_write_buffer_size = 200 # If a WebSocket client cannot read fast enough, at present we may # silently drop events instead of generating an error or disconnecting the # client. # # Enabling this experimental parameter will cause the WebSocket connection to # be closed instead if it cannot read fast enough, allowing for greater # predictability in subscription behavior. experimental_close_on_slow_client = false # How long to wait for a tx to be committed during /broadcast_tx_commit. # WARNING: Using a value larger than 10s will result in increasing the # global HTTP write timeout, which applies to all connections and endpoints. # See https://github.com/tendermint/tendermint/issues/3435 timeout_broadcast_tx_commit = "10s" # Maximum size of request body, in bytes max_body_bytes = 1000000 # Maximum size of request header, in bytes max_header_bytes = 1048576 # The path to a file containing certificate that is used to create the HTTPS server. # Might be either absolute path or path related to CometBFT's config directory. # If the certificate is signed by a certificate authority, # the certFile should be the concatenation of the server's certificate, any intermediates, # and the CA's certificate. # NOTE: both tls_cert_file and tls_key_file must be present for CometBFT to create HTTPS server. # Otherwise, HTTP server is run. tls_cert_file = "" # The path to a file containing matching private key that is used to create the HTTPS server. # Might be either absolute path or path related to CometBFT's config directory. # NOTE: both tls-cert-file and tls-key-file must be present for CometBFT to create HTTPS server. # Otherwise, HTTP server is run. tls_key_file = "" # pprof listen address (https://golang.org/pkg/net/http/pprof) #pprof_laddr = "0.0.0.0:6060" pprof_laddr = "" ####################################################### ### P2P Configuration Options ### ####################################################### [p2p] # Address to listen for incoming connections laddr = "tcp://0.0.0.0:26656" # Address to advertise to peers for them to dial. If empty, will use the same # port as the laddr, and will introspect on the listener to figure out the # address. IP and port are required. Example: 159.89.10.97:26656 external_address = "" # Comma separated list of seed nodes to connect to seeds = "e56e965bd53832d47cf2f7cc2b7118c20c0c5b19@34.89.234.189:26656,58b349f2d3f2206798aae4f8d87141f095095503@34.159.220.160:26656,9499000274a522d85f91dbdac26945bbe2a144ba@35.234.244.49:26656,a5ccf1b754651ec080dabc7e065d078ab2bc83bb@34.95.45.160:26656,a78ae6958f2f0683d50d8342d00beac991a51b9e@67.213.122.179:26656,2c617ccd984310c0f4f3ce9e226dec6c8eda2435@206.223.224.23:26656" # Comma separated list of nodes to keep persistent connections to persistent_peers = "" # Path to address book addr_book_file = "config/addrbook.json" # Set true for strict address routability rules # Set false for private or local networks addr_book_strict = true # Maximum number of inbound peers max_num_inbound_peers = 40 # Maximum number of outbound peers to connect to, excluding persistent peers max_num_outbound_peers = 10 # List of node IDs, to which a connection will be (re)established ignoring any existing limits unconditional_peer_ids = "" # Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) persistent_peers_max_dial_period = "0s" # Time to wait before flushing messages out on the connection flush_throttle_timeout = "10ms" # Maximum size of a message packet payload, in bytes max_packet_msg_payload_size = 1024 # Rate at which packets can be sent, in bytes/second send_rate = 5120000 # Rate at which packets can be received, in bytes/second recv_rate = 5120000 # Set true to enable the peer-exchange reactor pex = true # Seed mode, in which node constantly crawls the network and looks for # peers. If another node asks it for addresses, it responds and disconnects. # # Does not work if the peer-exchange reactor is disabled. seed_mode = false # Comma separated list of peer IDs to keep private (will not be gossiped to other peers) private_peer_ids = "" # Toggle to disable guard against peers connecting from the same ip. allow_duplicate_ip = false # Peer connection configuration. handshake_timeout = "20s" dial_timeout = "3s" ####################################################### ### Mempool Configuration Option ### ####################################################### [mempool] # The type of mempool for this node to use. # # Possible types: # - "flood" : concurrent linked list mempool with flooding gossip protocol # (default) # - "nop" : nop-mempool (short for no operation; the ABCI app is responsible # for storing, disseminating and proposing txs). "create_empty_blocks=false" is # not supported. type = "nop" # Recheck (default: true) defines whether CometBFT should recheck the # validity for all remaining transaction in the mempool after a block. # Since a block affects the application state, some transactions in the # mempool may become invalid. If this does not apply to your application, # you can disable rechecking. recheck = false # recheck_timeout is the time the application has during the rechecking process # to return CheckTx responses, once all requests have been sent. Responses that # arrive after the timeout expires are discarded. It only applies to # non-local ABCI clients and when recheck is enabled. recheck_timeout = "0s" # Broadcast (default: true) defines whether the mempool should relay # transactions to other peers. Setting this to false will stop the mempool # from relaying transactions to other peers until they are included in a # block. In other words, if Broadcast is disabled, only the peer you send # the tx to will see it until it is included in a block. broadcast = false # WalPath (default: "") configures the location of the Write Ahead Log # (WAL) for the mempool. The WAL is disabled by default. To enable, set # WalPath to where you want the WAL to be written (e.g. # "data/mempool.wal"). wal_dir = "" # Maximum number of transactions in the mempool size = 0 # Limit the total size of all txs in the mempool. # This only accounts for raw transactions (e.g. given 1MB transactions and # max_txs_bytes=5MB, mempool will only accept 5 transactions). max_txs_bytes = 0 # Size of the cache (used to filter transactions we saw earlier) in transactions cache_size = 0 # Do not remove invalid transactions from the cache (default: false) # Set to true if it's not possible for any invalid transaction to become valid # again in the future. keep-invalid-txs-in-cache = false # Maximum size of a single transaction. # NOTE: the max size of a tx transmitted over the network is {max_tx_bytes}. max_tx_bytes = 1048576 # Maximum size of a batch of transactions to send to a peer # Including space needed by encoding (one varint per transaction). # XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796 max_batch_size = 0 # Experimental parameters to limit gossiping txs to up to the specified number of peers. # We use two independent upper values for persistent and non-persistent peers. # Unconditional peers are not affected by this feature. # If we are connected to more than the specified number of persistent peers, only send txs to # ExperimentalMaxGossipConnectionsToPersistentPeers of them. If one of those # persistent peers disconnects, activate another persistent peer. # Similarly for non-persistent peers, with an upper limit of # ExperimentalMaxGossipConnectionsToNonPersistentPeers. # If set to 0, the feature is disabled for the corresponding group of peers, that is, the # number of active connections to that group of peers is not bounded. # For non-persistent peers, if enabled, a value of 10 is recommended based on experimental # performance results using the default P2P configuration. experimental_max_gossip_connections_to_persistent_peers = 0 experimental_max_gossip_connections_to_non_persistent_peers = 0 ####################################################### ### State Sync Configuration Options ### ####################################################### [statesync] # State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine # snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in # the network to take and serve state machine snapshots. State sync is not attempted if the node # has any local state (LastBlockHeight > 0). The node will have a truncated block history, # starting from the height of the snapshot. enable = false # RPC servers (comma-separated) for light client verification of the synced state machine and # retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding # header hash obtained from a trusted source, and a period during which validators can be trusted. # # For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2 # weeks) during which they can be financially punished (slashed) for misbehavior. rpc_servers = "" trust_height = 0 trust_hash = "" trust_period = "168h0m0s" # Time to spend discovering snapshots before initiating a restore. discovery_time = "15s" # Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). # Will create a new, randomly named directory within, and remove it when done. temp_dir = "" # The timeout duration before re-requesting a chunk, possibly from a different # peer (default: 1 minute). chunk_request_timeout = "10s" # The number of concurrent chunk fetchers to run (default: 1). chunk_fetchers = "4" ####################################################### ### Block Sync Configuration Options ### ####################################################### [blocksync] # Block Sync version to use: # # In v0.37, v1 and v2 of the block sync protocols were deprecated. # Please use v0 instead. # # 1) "v0" - the default block sync implementation version = "v0" ####################################################### ### Consensus Configuration Options ### ####################################################### [consensus] wal_file = "data/cs.wal/wal" # How long we wait for a proposal block before prevoting nil timeout_propose = "2s" # How much timeout_propose increases with each round timeout_propose_delta = "500ms" # How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) timeout_prevote = "2s" # How much the timeout_prevote increases with each round timeout_prevote_delta = "500ms" # How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) timeout_precommit = "2s" # How much the timeout_precommit increases with each round timeout_precommit_delta = "500ms" # How long we wait after committing a block, before starting on the new # height (this gives us a chance to receive some more precommits, even # though we already have +2/3). # Set to 0 if you want to make progress as soon as the node has all the precommits. timeout_commit = "500ms" # Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) skip_timeout_commit = false # How many blocks to look back to check existence of the node's consensus votes before joining consensus # When non-zero, the node will panic upon restart # if the same consensus key was used to sign {double_sign_check_height} last blocks. # So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. double_sign_check_height = 0 # EmptyBlocks mode and possible interval between empty blocks create_empty_blocks = true create_empty_blocks_interval = "0s" # Reactor sleep duration parameters peer_gossip_sleep_duration = "300ms" peer_gossip_intraloop_sleep_duration = "0s" peer_query_maj23_sleep_duration = "2s" ####################################################### ### Storage Configuration Options ### ####################################################### [storage] # Set to true to discard ABCI responses from the state store, which can save a # considerable amount of disk space. Set to false to ensure ABCI responses are # persisted. ABCI responses are required for /block_results RPC queries, and to # reindex events in the command-line tool. discard_abci_responses = true # The representation of keys in the database. # The current representation of keys in Comet's stores is considered to be v1 # Users can experiment with a different layout by setting this field to v2. # Note that this is an experimental feature and switching back from v2 to v1 # is not supported by CometBFT. # If the database was initially created with v1, it is necessary to migrate the DB # before switching to v2. The migration is not done automatically. # v1 - the legacy layout existing in Comet prior to v1. # v2 - Order preserving representation ordering entries by height. experimental_db_key_layout = "v1" # If set to true, CometBFT will force compaction to happen for databases that support this feature. # and save on storage space. Setting this to true is most benefits when used in combination # with pruning as it will physically delete the entries marked for deletion. # false by default (forcing compaction is disabled). compact = false # To avoid forcing compaction every time, this parameter instructs CometBFT to wait # the given amount of blocks to be pruned before triggering compaction. # It should be tuned depending on the number of items. If your retain height is 1 block, # it is too much of an overhead to try compaction every block. But it should also not be a very # large multiple of your retain height as it might occur bigger overheads. compaction_interval = "1000" [storage.pruning] # The time period between automated background pruning operations. interval = "10s" # # Storage pruning configuration relating only to the data companion. # [storage.pruning.data_companion] # Whether automatic pruning respects values set by the data companion. Disabled # by default. All other parameters in this section are ignored when this is # disabled. # # If disabled, only the application retain height will influence block pruning # (but not block results pruning). Only enabling this at a later stage will # potentially mean that blocks below the application-set retain height at the # time will not be available to the data companion. enabled = false # The initial value for the data companion block retain height if the data # companion has not yet explicitly set one. If the data companion has already # set a block retain height, this is ignored. initial_block_retain_height = 0 # The initial value for the data companion block results retain height if the # data companion has not yet explicitly set one. If the data companion has # already set a block results retain height, this is ignored. initial_block_results_retain_height = 0 ####################################################### ### Transaction Indexer Configuration Options ### ####################################################### [tx_index] # What indexer to use for transactions # # The application will set which txs to index. In some cases a node operator will be able # to decide which txs to index based on configuration set in the application. # # Options: # 1) "null" # 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). # - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. # 3) "psql" - the indexer services backed by PostgreSQL. # When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed. indexer = "null" # The PostgreSQL connection configuration, the connection format: # postgresql://:@:/? psql-conn = "" ####################################################### ### Instrumentation Configuration Options ### ####################################################### [instrumentation] # When true, Prometheus metrics are served under /metrics on # PrometheusListenAddr. # Check out the documentation for the list of available metrics. prometheus = true # Address to listen for Prometheus collector(s) connections prometheus_listen_addr = ":26660" # Maximum number of simultaneous connections. # If you want to accept a larger number than the default, make sure # you increase your OS limits. # 0 - unlimited. max_open_connections = 800 # Instrumentation namespace namespace = "cometbft" ================================================ FILE: testing/networks/80069/el-bootnodes.txt ================================================ enode://5c0d582c19ea9f19928cfd6b7e156372d051b5720f67a444c38b671b8119bb097abfd1e4b868a389ab4a65bb9b405ef837df0ae195c0f32a33c61c39ca54e8ab@34.107.71.151:30303,enode://59aec227e87f4cd7c0a24c6cb0f870ef77abcc0c6d640f5a536c597a206b3505f7963f6459c265952b7bed3c3f260edf8a1412bbdb05f0e59d6bd612dc4bf077@34.141.48.88:30303,enode://47f41b9ab5a45e880a78330d2ae3f95a61f5cb41f203bbc9c9ff0e37778fc6c7fd46a6ee103e65ac36df8c024075a33f535a03cd8d800800c27fa2699fa0182b@34.47.28.251:30303,enode://fe6d2429b582de7daf387c6e5436f05d9185965267b72b8b6b4924125b50afdad765a820213d73d2afbfe64a721160a1a94750b4874ed97ccbe97c51443d1c42@34.95.21.165:30303,enode://869293789a1bbdcbdd0d8c2f1eed560d20e4b4b23b21abf575c87158aea59f0396781b54fcedd8db01a6db075de71dbd29e75cfdbb83cea9cea1a6bd31bec74c@67.213.122.179:30303,enode://e4b804a4fc7833f03b6033542d72d026727a651e8b4369b42b8e6f22a1ebbe649c22b646e7180cd05843c4992c477d1999cbec101d97f0f7edc950495b846eb5@206.223.224.23:30303 ================================================ FILE: testing/networks/80069/el-peers.txt ================================================ enode://fe6d2429b582de7daf387c6e5436f05d9185965267b72b8b6b4924125b50afdad765a820213d73d2afbfe64a721160a1a94750b4874ed97ccbe97c51443d1c42@34.118.173.2:30303,enode://47f41b9ab5a45e880a78330d2ae3f95a61f5cb41f203bbc9c9ff0e37778fc6c7fd46a6ee103e65ac36df8c024075a33f535a03cd8d800800c27fa2699fa0182b@34.152.12.159:30303,enode://59aec227e87f4cd7c0a24c6cb0f870ef77abcc0c6d640f5a536c597a206b3505f7963f6459c265952b7bed3c3f260edf8a1412bbdb05f0e59d6bd612dc4bf077@34.141.116.135:30303,enode://5c0d582c19ea9f19928cfd6b7e156372d051b5720f67a444c38b671b8119bb097abfd1e4b868a389ab4a65bb9b405ef837df0ae195c0f32a33c61c39ca54e8ab@34.89.220.53:30303,enode://869293789a1bbdcbdd0d8c2f1eed560d20e4b4b23b21abf575c87158aea59f0396781b54fcedd8db01a6db075de71dbd29e75cfdbb83cea9cea1a6bd31bec74c@67.213.122.179:30303,enode://e4b804a4fc7833f03b6033542d72d026727a651e8b4369b42b8e6f22a1ebbe649c22b646e7180cd05843c4992c477d1999cbec101d97f0f7edc950495b846eb5@206.223.224.23:30303 ================================================ FILE: testing/networks/80069/eth-genesis.json ================================================ { "alloc": { "0x0000000000000000000000000000000000000000": { "balance": "0x211654585005212800000" }, "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": { "balance": "0x0", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", "nonce": "0x1" }, "0x0cF32C7C003Bd9Fdbd5Ba635DAEDCb1070E77dE0": { "balance": "0x422ca8b0a00a425000000" }, "0x4242424242424242424242424242424242424242": { "code": "0x608060405260043610610093575f3560e01c8063577212fe11610066578063c53925d91161004c578063c53925d914610231578063e12cf4cb14610250578063fea7ab7714610263575f80fd5b8063577212fe146101cc5780639eaffa96146101ed575f80fd5b806301ffc9a7146100975780632dfdf0b5146100cb5780633523f9bd14610103578063560036ec14610126575b5f80fd5b3480156100a2575f80fd5b506100b66100b1366004610bb7565b610282565b60405190151581526020015b60405180910390f35b3480156100d6575f80fd5b505f546100ea9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100c2565b34801561010e575f80fd5b5061011860015481565b6040519081526020016100c2565b348015610131575f80fd5b50610193610140366004610c2a565b80516020818301810180516003825292820191909301209152546bffffffffffffffffffffffff8116906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1682565b604080516bffffffffffffffffffffffff909316835273ffffffffffffffffffffffffffffffffffffffff9091166020830152016100c2565b3480156101d7575f80fd5b506101eb6101e6366004610d5f565b61031a565b005b3480156101f8575f80fd5b5061020c610207366004610d5f565b6103e7565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c2565b34801561023c575f80fd5b506101eb61024b366004610d5f565b610428565b6101eb61025e366004610dc1565b61063d565b34801561026e575f80fd5b506101eb61027d366004610e70565b61095c565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061031457507fffffffff0000000000000000000000000000000000000000000000000000000082167f136f920d00000000000000000000000000000000000000000000000000000000145b92915050565b6002828260405161032c929190610ec0565b908152604051908190036020019020543373ffffffffffffffffffffffffffffffffffffffff90911614610383576103837f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b60038282604051610395929190610ec0565b9081526040519081900360200181205f90556103b49083908390610ec0565b604051908190038120907f1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db905f90a25050565b5f600283836040516103fa929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f6003838360405161043b929190610ec0565b908152604051908190036020019020805490915073ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000820416906bffffffffffffffffffffffff163382146104b4576104b47f819a0d0b00000000000000000000000000000000000000000000000000000000610afc565b6bffffffffffffffffffffffff42166104d06201518083610efc565b6bffffffffffffffffffffffff16111561050d5761050d7fe8966d7a00000000000000000000000000000000000000000000000000000000610afc565b5f60028686604051610520929190610ec0565b9081526040519081900360200181205473ffffffffffffffffffffffffffffffffffffffff169150839060029061055a9089908990610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556003906105bf9088908890610ec0565b9081526040519081900360200181205f90556105de9087908790610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a2505050505050565b6030861461066e5761066e7f9f10647200000000000000000000000000000000000000000000000000000000610afc565b6020841461069f5761069f7fb39bca1600000000000000000000000000000000000000000000000000000000610afc565b606082146106d0576106d07f4be6321b00000000000000000000000000000000000000000000000000000000610afc565b5f73ffffffffffffffffffffffffffffffffffffffff16600288886040516106f9929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16036108375773ffffffffffffffffffffffffffffffffffffffff8116610768576107687f51969a7a00000000000000000000000000000000000000000000000000000000610afc565b806002888860405161077b929190610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556107dd9088908890610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff841683525f6020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a261087c565b73ffffffffffffffffffffffffffffffffffffffff81161561087c5761087c7fc4142b4100000000000000000000000000000000000000000000000000000000610afc565b5f610885610b04565b90506509184e72a00067ffffffffffffffff821610156108c8576108c87f0e1eddda00000000000000000000000000000000000000000000000000000000610afc565b5f80547f68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46918a918a918a918a9187918b918b9167ffffffffffffffff16908061091083610f20565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405161094a989796959493929190610f93565b60405180910390a15050505050505050565b5f6002848460405161096f929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690503381146109c7576109c77f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b73ffffffffffffffffffffffffffffffffffffffff8216610a0b57610a0b7fd92e233d00000000000000000000000000000000000000000000000000000000610afc565b5f60038585604051610a1e929190610ec0565b908152604051908190036020018120426bffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff86166c01000000000000000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000161781559150610a969086908690610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff8681168452851660208401524283830152905190917f7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f919081900360600190a25050505050565b805f5260045ffd5b5f610b13633b9aca003461102b565b15610b4157610b417f40567b3800000000000000000000000000000000000000000000000000000000610afc565b5f610b50633b9aca003461103e565b905067ffffffffffffffff811115610b8b57610b8b7f2aa6673400000000000000000000000000000000000000000000000000000000610afc565b610b955f34610b9a565b919050565b5f385f3884865af1610bb35763b12d13eb5f526004601cfd5b5050565b5f60208284031215610bc7575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610bf6575f80fd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215610c3a575f80fd5b813567ffffffffffffffff811115610c50575f80fd5b8201601f81018413610c60575f80fd5b803567ffffffffffffffff811115610c7a57610c7a610bfd565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715610ce657610ce6610bfd565b604052818152828201602001861015610cfd575f80fd5b816020840160208301375f91810160200191909152949350505050565b5f8083601f840112610d2a575f80fd5b50813567ffffffffffffffff811115610d41575f80fd5b602083019150836020828501011115610d58575f80fd5b9250929050565b5f8060208385031215610d70575f80fd5b823567ffffffffffffffff811115610d86575f80fd5b610d9285828601610d1a565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b95575f80fd5b5f805f805f805f6080888a031215610dd7575f80fd5b873567ffffffffffffffff811115610ded575f80fd5b610df98a828b01610d1a565b909850965050602088013567ffffffffffffffff811115610e18575f80fd5b610e248a828b01610d1a565b909650945050604088013567ffffffffffffffff811115610e43575f80fd5b610e4f8a828b01610d1a565b9094509250610e62905060608901610d9e565b905092959891949750929550565b5f805f60408486031215610e82575f80fd5b833567ffffffffffffffff811115610e98575f80fd5b610ea486828701610d1a565b9094509250610eb7905060208501610d9e565b90509250925092565b818382375f9101908152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6bffffffffffffffffffffffff818116838216019081111561031457610314610ecf565b5f67ffffffffffffffff821667ffffffffffffffff8103610f4357610f43610ecf565b60010192915050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60a081525f610fa660a083018a8c610f4c565b8281036020840152610fb981898b610f4c565b905067ffffffffffffffff871660408401528281036060840152610fde818688610f4c565b91505067ffffffffffffffff831660808301529998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261103957611039610ffe565b500690565b5f8261104c5761104c610ffe565b50049056fea164736f6c634300081a000a", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000000000000000000000000000000000000000000a", "0x0000000000000000000000000000000000000000000000000000000000000001": "0x43f7a8e2d16cceb70835172a7790a4aace27d18d39e30c43649b84231268b548", "0x03d552cd0b6a48aa44cf44494aea1dfc6c218f0e2aa352d0ca3ed7945bdb2c24": "0x000000000000000000000000e9ba99ef852936cdddcd9075df3bde410c36e0cf", "0x0faaea70c953dcfe11ad8bc316a089e2eda60e529d0bcfc62c7b7dd86b261feb": "0x0000000000000000000000000b59c939e52643cde4ef15a508cacdee8119d34c", "0x145af481a0810f44c87f9901947772fe668830e73092929093a4364c57f4ca70": "0x000000000000000000000000340d3d95c8470684ee21b8f6b64540a365b72f88", "0x148fbbe12a67f02bf75ba94d9663ea96d5bcaf77abb308716dc7919adc1283b1": "0x00000000000000000000000041707b8012929f0625b87757ce8c4ddfdd8c6837", "0x3210ca2c1c490b6cae9ec1bb36ce12596c577f8b06cb57b09eb3bd63816c6c4e": "0x000000000000000000000000f690240ad1865ab6fe8c06d7e956de7fd877cbf7", "0x3f45de2d635a6b087c80603ec1416e699edba6b2cd8d1d1e05add3dc6a01f3d2": "0x0000000000000000000000000d283a8aff77f4fb7b7a9ec78b09b26e083da304", "0x42745319680dbe6769545a89399626eedaa7c4d1d3d813b272158972cfd23e52": "0x000000000000000000000000d2b18fb965968a81e2f0dcc777775aaba5f036e8", "0x8ded9e69a1060de4ccc5b83484dc51ded413205d63a57a22c5a31f3b285693e2": "0x00000000000000000000000087784c08716671b8dc3b942e682e692f92f73381", "0xccf6e5a9e737c27836dfa6601e82b4296a23feb2775bfdf549aa2717b34a0849": "0x00000000000000000000000012e2c8eb371d43416dc9f3b92b8c84a8cce6ada0", "0xdb0c62b2ec141f0a4bb5dd01b05cb06824d445ece3979c01002904dd00fafb6f": "0x000000000000000000000000eb4a898c0ba5d0cdc5886156408edaea5b0a188d" }, "balance": "0x0", "nonce": "0x1" }, "0x4e59b44847b379578588920cA78FbF26c0B4956C": { "balance": "0x0", "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3", "nonce": "0x1" }, "0x6969696969696969696969696969696969696969": { "balance": "0x0", "code": "0x6080604052600436106100dc575f3560e01c806370a082311161007c578063a9059cbb11610057578063a9059cbb14610365578063d0e30db014610384578063d505accf1461038c578063dd62ed3e146103ab575f80fd5b806370a08231146102be5780637ecebe00146102ef57806395d89b4114610320575f80fd5b806323b872dd116100b757806323b872dd1461019b5780632e1a7d4d146101ba578063313ce567146101d95780633644e515146101f4575f80fd5b806306fdde03146100ef578063095ea7b31461014657806318160ddd14610175575f80fd5b366100eb576100e96103df565b005b5f80fd5b3480156100fa575f80fd5b5060408051808201909152600c81527f577261707065642042657261000000000000000000000000000000000000000060208201525b60405161013d9190610865565b60405180910390f35b348015610151575f80fd5b506101656101603660046108e0565b6103eb565b604051901515815260200161013d565b348015610180575f80fd5b506805345cdf77eb68f44c545b60405190815260200161013d565b3480156101a6575f80fd5b506101656101b5366004610908565b61043a565b3480156101c5575f80fd5b506100e96101d4366004610942565b6104f2565b3480156101e4575f80fd5b506040516012815260200161013d565b3480156101ff575f80fd5b50604080518082018252600c81527f577261707065642042657261000000000000000000000000000000000000000060209182015281517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f81527fb6c9387dd48cdde7d71a807357f57f1fef05232a4af3ed7fdf1f050c8e1a69fe918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69181019190915246606082015230608082015260a0902061018d565b3480156102c9575f80fd5b5061018d6102d8366004610959565b6387a211a2600c9081525f91909152602090205490565b3480156102fa575f80fd5b5061018d610309366004610959565b6338377508600c9081525f91909152602090205490565b34801561032b575f80fd5b5060408051808201909152600581527f57424552410000000000000000000000000000000000000000000000000000006020820152610130565b348015610370575f80fd5b5061016561037f3660046108e0565b610518565b6100e96103df565b348015610397575f80fd5b506100e96103a6366004610979565b61058f565b3480156103b6575f80fd5b5061018d6103c53660046109e6565b602052637f5e9f20600c9081525f91909152603490205490565b6103e93334610768565b565b5f82602052637f5e9f20600c52335f52816034600c2055815f52602c5160601c337f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560205fa350600192915050565b5f8360601b33602052637f5e9f208117600c526034600c2080548019156104765780851115610470576313be252b5f526004601cfd5b84810382555b50506387a211a28117600c526020600c2080548085111561049e5763f4d678b85f526004601cfd5b84810382555050835f526020600c208381540181555082602052600c5160601c8160601c7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a3505060019392505050565b6104fc33826107e4565b5f385f3884335af16105155763b12d13eb5f526004601cfd5b50565b5f6387a211a2600c52335f526020600c208054808411156105405763f4d678b85f526004601cfd5b83810382555050825f526020600c208281540181555081602052600c5160601c337fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a350600192915050565b60408051808201909152600c81527f57726170706564204265726100000000000000000000000000000000000000006020909101527fb6c9387dd48cdde7d71a807357f57f1fef05232a4af3ed7fdf1f050c8e1a69fe7fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64286101561061b57631a15a3cc5f526004601cfd5b6040518960601b60601c99508860601b60601c985065383775081901600e52895f526020600c2080547f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f835284602084015283604084015246606084015230608084015260a08320602e527f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c983528b60208401528a60408401528960608401528060808401528860a084015260c08320604e526042602c205f528760ff16602052866040528560605260208060805f60015afa8c3d51146107035763ddafbaef5f526004601cfd5b019055777f5e9f20000000000000000000000000000000000000000089176040526034602c20889055888a7f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925602060608501a360405250505f60605250505050505050565b6805345cdf77eb68f44c548181018181101561078b5763e5cfe9575f526004601cfd5b806805345cdf77eb68f44c5550506387a211a2600c52815f526020600c208181540181555080602052600c5160601c5f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602080a35050565b6387a211a2600c52815f526020600c2080548083111561080b5763f4d678b85f526004601cfd5b82900390556805345cdf77eb68f44c805482900390555f81815273ffffffffffffffffffffffffffffffffffffffff83167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef602083a35050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146108db575f80fd5b919050565b5f80604083850312156108f1575f80fd5b6108fa836108b8565b946020939093013593505050565b5f805f6060848603121561091a575f80fd5b610923846108b8565b9250610931602085016108b8565b929592945050506040919091013590565b5f60208284031215610952575f80fd5b5035919050565b5f60208284031215610969575f80fd5b610972826108b8565b9392505050565b5f805f805f805f60e0888a03121561098f575f80fd5b610998886108b8565b96506109a6602089016108b8565b95506040880135945060608801359350608088013560ff811681146109c9575f80fd5b9699959850939692959460a0840135945060c09093013592915050565b5f80604083850312156109f7575f80fd5b610a00836108b8565b9150610a0e602084016108b8565b9050925092905056fea164736f6c634300081a000a", "nonce": "0x1" }, "0x7d84185eed48c38eb4181ef4dd9b4321b3b67d94": { "balance": "0x422ca8b0a00a425000000" }, "0x8a73D1380345942F1cb32541F1b19C40D8e6C94B": { "balance": "0x18afa8ede3b3d3bcd800000" }, "0xB796D5cB6dC182Da6ca7EC2D2Fd0112f599A188A": { "balance": "0x422ca8b0a00a425000000" }, "0xb8dCdb8f043e8061e887A8BDD83eB2f0E242BF64": { "balance": "0x422ca8b0a00a425000000" }, "0xcA11bde05977b3631167028862bE2a173976CA11": { "balance": "0x0", "code": "0x6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461025a578063bce38bd714610275578063c3077fa914610288578063ee82ac5e1461029b57600080fd5b80634d2301cc146101ec57806372425d9d1461022157806382ad56cb1461023457806386d516e81461024757600080fd5b80633408e470116100c65780633408e47014610191578063399542e9146101a45780633e64a696146101c657806342cbb15c146101d957600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d610128366004610a85565b6102ba565b6040516101119190610bbe565b61014d610148366004610a85565b6104ef565b604051610111929190610bd8565b34801561016757600080fd5b50437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0140610107565b34801561019d57600080fd5b5046610107565b6101b76101b2366004610c60565b610690565b60405161011193929190610cba565b3480156101d257600080fd5b5048610107565b3480156101e557600080fd5b5043610107565b3480156101f857600080fd5b50610107610207366004610ce2565b73ffffffffffffffffffffffffffffffffffffffff163190565b34801561022d57600080fd5b5044610107565b61012d610242366004610a85565b6106ab565b34801561025357600080fd5b5045610107565b34801561026657600080fd5b50604051418152602001610111565b61012d610283366004610c60565b61085a565b6101b7610296366004610a85565b610a1a565b3480156102a757600080fd5b506101076102b6366004610d18565b4090565b60606000828067ffffffffffffffff8111156102d8576102d8610d31565b60405190808252806020026020018201604052801561031e57816020015b6040805180820190915260008152606060208201528152602001906001900390816102f65790505b5092503660005b8281101561047757600085828151811061034157610341610d60565b6020026020010151905087878381811061035d5761035d610d60565b905060200281019061036f9190610d8f565b6040810135958601959093506103886020850185610ce2565b73ffffffffffffffffffffffffffffffffffffffff16816103ac6060870187610dcd565b6040516103ba929190610e32565b60006040518083038185875af1925050503d80600081146103f7576040519150601f19603f3d011682016040523d82523d6000602084013e6103fc565b606091505b50602080850191909152901515808452908501351761046d577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b5050600101610325565b508234146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561050c5761050c610d31565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b5091503660005b8281101561068657600087878381811061056257610562610d60565b90506020028101906105749190610e42565b92506105836020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166105a66020850185610dcd565b6040516105b4929190610e32565b6000604051808303816000865af19150503d80600081146105f1576040519150601f19603f3d011682016040523d82523d6000602084013e6105f6565b606091505b5086848151811061060957610609610d60565b602090810291909101015290508061067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b50600101610546565b5050509250929050565b43804060606106a086868661085a565b905093509350939050565b6060818067ffffffffffffffff8111156106c7576106c7610d31565b60405190808252806020026020018201604052801561070d57816020015b6040805180820190915260008152606060208201528152602001906001900390816106e55790505b5091503660005b828110156104e657600084828151811061073057610730610d60565b6020026020010151905086868381811061074c5761074c610d60565b905060200281019061075e9190610e76565b925061076d6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166107906040850185610dcd565b60405161079e929190610e32565b6000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b506020808401919091529015158083529084013517610851577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b50600101610714565b6060818067ffffffffffffffff81111561087657610876610d31565b6040519080825280602002602001820160405280156108bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816108945790505b5091503660005b82811015610a105760008482815181106108df576108df610d60565b602002602001015190508686838181106108fb576108fb610d60565b905060200281019061090d9190610e42565b925061091c6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff1661093f6020850185610dcd565b60405161094d929190610e32565b6000604051808303816000865af19150503d806000811461098a576040519150601f19603f3d011682016040523d82523d6000602084013e61098f565b606091505b506020830152151581528715610a07578051610a07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b506001016108c3565b5050509392505050565b6000806060610a2b60018686610690565b919790965090945092505050565b60008083601f840112610a4b57600080fd5b50813567ffffffffffffffff811115610a6357600080fd5b6020830191508360208260051b8501011115610a7e57600080fd5b9250929050565b60008060208385031215610a9857600080fd5b823567ffffffffffffffff811115610aaf57600080fd5b610abb85828601610a39565b90969095509350505050565b6000815180845260005b81811015610aed57602081850181015186830182015201610ad1565b81811115610aff576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b84811015610bb1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051151584528401516040858501819052610b9d81860183610ac7565b9a86019a9450505090830190600101610b4f565b5090979650505050505050565b602081526000610bd16020830184610b32565b9392505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610c52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452610c40868351610ac7565b95509284019290840190600101610c06565b509398975050505050505050565b600080600060408486031215610c7557600080fd5b83358015158114610c8557600080fd5b9250602084013567ffffffffffffffff811115610ca157600080fd5b610cad86828701610a39565b9497909650939450505050565b838152826020820152606060408201526000610cd96060830184610b32565b95945050505050565b600060208284031215610cf457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610bd157600080fd5b600060208284031215610d2a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112610dc357600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e0257600080fd5b83018035915067ffffffffffffffff821115610e1d57600080fd5b602001915036819003821315610a7e57600080fd5b8183823760009101908152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610dc357600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610dc357600080fdfea2646970667358221220bb2b5c71a328032f97c676ae39a1ec2148d3e5d6f73d95e9b17910152d61f16264736f6c634300080c0033", "nonce": "0x1" } }, "coinbase": "0x0000000000000000000000000000000000000000", "config": { "arrowGlacierBlock": 0, "berlinBlock": 0, "byzantiumBlock": 0, "cancunTime": 0, "chainId": 80069, "constantinopleBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "ethash": {}, "grayGlacierBlock": 0, "homesteadBlock": 0, "istanbulBlock": 0, "londonBlock": 0, "mergeNetsplitBlock": 0, "muirGlacierBlock": 0, "petersburgBlock": 0, "shanghaiTime": 0, "pragueTime": 1746633600, "osakaTime": 9999999999999999, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 }, "prague": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 } }, "berachain": { "prague1": { "time": 1754496000, "baseFeeChangeDenominator": 48, "minimumBaseFeeWei": 10000000000, "polDistributorAddress": "0xD2f19a79b026Fb636A7c300bF5947df113940761" }, "prague2": { "time": 1758124800, "minimumBaseFeeWei": 0 } } }, "difficulty": "0x01", "extraData": "", "gasLimit": "0x1c9c380", "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "nonce": "0x1234", "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "timestamp": "1739976735" } ================================================ FILE: testing/networks/80069/genesis.json ================================================ { "app_name": "beacond", "app_version": "v1.1.2", "genesis_time": "2025-02-20T20:18:20.017462Z", "chain_id": "testnet-beacon-80069", "initial_height": 1, "app_hash": null, "app_state": { "beacon": { "fork_version": "0x04000000", "deposits": [ { "pubkey": "0x957004733f0c4d7e51b4f1ac3f1c08247f9c5455d302b669c723eb80d8c286515b5623757a9053a5a7b8c17ee3feed4b", "credentials": "0x0100000000000000000000008a73d1380345942f1cb32541f1b19c40d8e6c94b", "amount": "0xe35fa931a000", "signature": "0x920fb9e596c9b11677476e40d0bcc0f97620417e9ac73b885f982860a2c092b8a59352e80c689e99e8906a2f68ad922209d8e23a00d46c290ddaf239127af1ff6f76239939984a9d972095eb16565112c2cda7caa659ceae25a16b52b96b6b7d", "index": 0 }, { "pubkey": "0x97b21253b17f4e814fe7505c15c18e68c85ab2477274ad370a762df50e3eb4cb1a48451e089bc22e158d7448549a8ab9", "credentials": "0x0100000000000000000000008a73d1380345942f1cb32541f1b19c40d8e6c94b", "amount": "0xe35fa931a000", "signature": "0xaa2e572c1c3521118a1bb75c57ec0bedfba679dd32c175961c8fd2df4f8f13c70db2c798926d7b0c96c5d0f045b3cc58046989764865b06a6574f38436a30d5a5ab26dcd3768bfffc9f80a9d188edd8f876f3c15034e40b1d546d13702df8ea8", "index": 1 }, { "pubkey": "0x92203b1242e536e91159707c2a6bfb3ed1339b07eb35a724e5237b60a55919815505a82199a4a8aa63e4e1daafd37983", "credentials": "0x0100000000000000000000008a73d1380345942f1cb32541f1b19c40d8e6c94b", "amount": "0xe35fa931a000", "signature": "0x8827ffe0264c7bf7493b70406b6995f30ce791dc07727c2ea3bf0676c52686c74e02b0b5b620cd1ea66824fea8bfbfd303acfa3d88d1bb5c572567c46d9b74f740f24db0233fb80ade57406a1541bfae4f3578fb2cb266a684339dbe548285d8", "index": 2 }, { "pubkey": "0xa4e4b63514f54d61da5197359f11ff1fc2930788ba2ffdd30c2fc059cbe0221020197bf9446b16ac347f36c7517a8686", "credentials": "0x0100000000000000000000008a73d1380345942f1cb32541f1b19c40d8e6c94b", "amount": "0xe35fa931a000", "signature": "0x8ea8bc8b09b061b281b9d3825c9a5103812bc42b0d1e5dc6fa85bb77a843e58f7ac431f0623dbc41d5d059f0f1b3bc8e0f2bf64566bf98f38327096b19d65f27c49a569886daab06d5dafe3149d1f7a9b4775ffa0783681026cd4d31a245334c", "index": 3 }, { "pubkey": "0xa2705d6b27891f3f5651f26547d1bb79e256f95f249d1ad717cef087d77d38b037e5d6dbaa2538930fd0731ec9b02f3a", "credentials": "0x0100000000000000000000008a73d1380345942f1cb32541f1b19c40d8e6c94b", "amount": "0xe35fa931a000", "signature": "0xaabf262608ce6f1551968e0fc062b478fdc1503c9bf68aba89e580e216d65b4ff41f1fbf575e546b10142db8480f710e014afa9ac1458c6ce7db697e635d1191ccea4c2559eae253aaee9a8a647cabc0d73a603548d0a4eacf2486a5cd12cb27", "index": 4 }, { "pubkey": "0x8f51e63d9921a461be29e73dca1c2385e1adc5943fbb36ded4ba96025ee8a783184d1118da08171f6ea831153c878a6d", "credentials": "0x0100000000000000000000000cf32c7c003bd9fdbd5ba635daedcb1070e77de0", "amount": "0xe35fa931a000", "signature": "0xb8c4c14fcac6736ac1c9c94414a4e0f71d4a4b25367b2b76f0b6e5f8f3de25aea72b45c5d34e8f626ee57828995d2c6b006d164262f01209c1077b47f2b60d8cc2a5462b82ec3bd4447aa2cdc60fabf173ef7e8acf263fe9ba66eff39b99eac3", "index": 5 }, { "pubkey": "0xa9060589e595ea482ebd98d461c54a038e4a115ec747a448f975fd4b34e7555dcd7f3f6188b894743254999b02e4c896", "credentials": "0x0100000000000000000000000cf32c7c003bd9fdbd5ba635daedcb1070e77de0", "amount": "0xe35fa931a000", "signature": "0xb79dd04f00a1568e12afc9186b5491fd1fd40c03e3c69e0aace4f71eef2e607254026b43dfcfa4ee4d63e2d65cd7e63c13d6a685bbdf8a0afe0baf9479229b9a8b8a49407cf04d3ed592b6d4a6f0b7d4ca75e39b28469e7f190363b683bbd197", "index": 6 }, { "pubkey": "0x94ee582f23b3873a9242b0a701cd30b1b62d800c1525059624085e06fc93dd93bc52da47228f25d7da8c7988802f05c7", "credentials": "0x0100000000000000000000000cf32c7c003bd9fdbd5ba635daedcb1070e77de0", "amount": "0xe35fa931a000", "signature": "0xb95c4ad16d12967165d159b324fc9f78c22056dc6c0dda810047e656aecbbee48ab1047b4a62a155457927b21088aedd13408b685e18752e9c184ab3ec1e71b481f5eb495bc940e128533f1ecc29f79c7002783f7a05a417ca2ca41b7d9a60a3", "index": 7 }, { "pubkey": "0xb0511ec039591e98bd4e183ba70b85572214a7ad8ca1a43e96ad3495d3821054927bc542e5482ec9733e35b7ef0b1f03", "credentials": "0x0100000000000000000000000cf32c7c003bd9fdbd5ba635daedcb1070e77de0", "amount": "0xe35fa931a000", "signature": "0xb71253ef7901a1e12f0816ae305587e0770ba4b488ed43559bc5faf58095368af7ce5f15e9ca4a26da6b7a5258e789a80038a6822d74cd4c6ecd910ac906c0555dc897952c941a787ede271c704b3df35d49731407be1421f2f62fb6a442fd5c", "index": 8 }, { "pubkey": "0x9747e5a9ed44cc89806c376cec553aa3a58f3679ea0a5f22d001aee770aea252134a18ea30d40e04595ae0b64d0c6444", "credentials": "0x0100000000000000000000000cf32c7c003bd9fdbd5ba635daedcb1070e77de0", "amount": "0xe35fa931a000", "signature": "0x98f93cf85ec2bba69fc99c296aa4711ca2bbfdd2b44aebb80e9edfeffa451e9979151d00299fbec23cecddedbef267ff0f7aed094d41e0e3c071a8fab6c8bbcd98707e319ce0d47ad7611e28ddb44605dd113932e0d2c2f2a7423eebde0209cd", "index": 9 } ], "execution_payload_header": { "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000", "stateRoot": "0xaf7ac45ece564c84ee2451776587c548aebb91ba04eb6040fd2b26055539c8e3", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x0", "gasLimit": "0x1c9c380", "gasUsed": "0x0", "timestamp": "0x67b5f01f", "extraData": "0x", "baseFeePerGas": "1000000000", "blockHash": "0x0207661de38f0e54ba91c8286096e72486784c79dc6a9681fc486b38335c042f", "transactionsRoot": "0x7ffe241ea60187fdb0187bfa22de35d1f9bed7ab061d9401fd47e34a54fbede1", "withdrawalsRoot": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", "blobGasUsed": "0x0", "excessBlobGas": "0x0" } } }, "consensus": { "params": { "block": { "max_bytes": "104857600", "max_gas": "10000000" }, "evidence": { "max_age_num_blocks": "100000", "max_age_duration": "172800000000000", "max_bytes": "1048576" }, "validator": { "pub_key_types": [ "bls12_381" ] }, "version": { "app": "0" }, "synchrony": { "precision": "505000000", "message_delay": "15000000000" }, "feature": { "vote_extensions_enable_height": "0", "pbts_enable_height": "1" } } } } ================================================ FILE: testing/networks/80069/kzg-trusted-setup.json ================================================ { "g1_lagrange": [ "0xa0413c0dcafec6dbc9f47d66785cf1e8c981044f7d13cfe3e4fcbb71b5408dfde6312493cb3c1d30516cb3ca88c03654", "0x8b997fb25730d661918371bb41f2a6e899cac23f04fc5365800b75433c0a953250e15e7a98fb5ca5cc56a8cd34c20c57", "0x83302852db89424d5699f3f157e79e91dc1380f8d5895c5a772bb4ea3a5928e7c26c07db6775203ce33e62a114adaa99", "0xa759c48b7e4a685e735c01e5aa6ef9c248705001f470f9ad856cd87806983e917a8742a3bd5ee27db8d76080269b7c83", "0x967f8dc45ebc3be14c8705f43249a30ff48e96205fb02ae28daeab47b72eb3f45df0625928582aa1eb4368381c33e127", "0xa418eb1e9fb84cb32b370610f56f3cb470706a40ac5a47c411c464299c45c91f25b63ae3fcd623172aa0f273c0526c13", "0x8f44e3f0387293bc7931e978165abbaed08f53acd72a0a23ac85f6da0091196b886233bcee5b4a194db02f3d5a9b3f78", "0x97173434b336be73c89412a6d70d416e170ea355bf1956c32d464090b107c090ef2d4e1a467a5632fbc332eeb679bf2d", "0xa24052ad8d55ad04bc5d951f78e14213435681594110fd18173482609d5019105b8045182d53ffce4fc29fc8810516c1", "0xb950768136b260277590b5bec3f56bbc2f7a8bc383d44ce8600e85bf8cf19f479898bcc999d96dfbd2001ede01d94949", "0x92ab8077871037bd3b57b95cbb9fb10eb11efde9191690dcac655356986fd02841d8fdb25396faa0feadfe3f50baf56d", "0xa79b096dff98038ac30f91112dd14b78f8ad428268af36d20c292e2b3b6d9ed4fb28480bb04e465071cc67d05786b6d1", "0xb9ff71461328f370ce68bf591aa7fb13027044f42a575517f3319e2be4aa4843fa281e756d0aa5645428d6dfa857cef2", "0x8d765808c00b3543ff182e2d159c38ae174b12d1314da88ea08e13bd9d1c37184cb515e6bf6420531b5d41767987d7ce", "0xb8c9a837d20c3b53e6f578e4a257bb7ef8fc43178614ec2a154915b267ad2be135981d01ed2ee1b5fbd9d9bb27f0800a", "0xa9773d92cf23f65f98ef68f6cf95c72b53d0683af2f9bf886bb9036e4a38184b1131b26fd24397910b494fbef856f3aa", "0xb41ebe38962d112da4a01bf101cb248d808fbd50aaf749fc7c151cf332032eb3e3bdbd716db899724b734d392f26c412", "0x90fbb030167fb47dcc13d604a726c0339418567c1d287d1d87423fa0cb92eec3455fbb46bcbe2e697144a2d3972142e4", "0xb11d298bd167464b35fb923520d14832bd9ed50ed841bf6d7618424fd6f3699190af21759e351b89142d355952149da1", "0x8bc36066f69dc89f7c4d1e58d67497675050c6aa002244cebd9fc957ec5e364c46bab4735ea3db02b73b3ca43c96e019", "0xab7ab92c5d4d773068e485aa5831941ebd63db7118674ca38089635f3b4186833af2455a6fb9ed2b745df53b3ce96727", "0xaf191ca3089892cb943cd97cf11a51f38e38bd9be50844a4e8da99f27e305e876f9ed4ab0628e8ae3939066b7d34a15f", "0xa3204c1747feabc2c11339a542195e7cb6628fd3964f846e71e2e3f2d6bb379a5e51700682ea1844eba12756adb13216", "0x903a29883846b7c50c15968b20e30c471aeac07b872c40a4d19eb1a42da18b649d5bbfde4b4cf6225d215a461b0deb6d", "0x8e6e9c15ffbf1e16e5865a5fef7ed751dc81957a9757b535cb38b649e1098cda25d42381dc4f776778573cdf90c3e6e0", "0xa8f6dd26100b512a8c96c52e00715c4b2cb9ac457f17aed8ffe1cf1ea524068fe5a1ddf218149845fc1417b789ecfc98", "0xa5b0ffc819451ea639cfd1c18cbc9365cc79368d3b2e736c0ae54eba2f0801e6eb0ee14a5f373f4a70ca463bdb696c09", "0x879f91ccd56a1b9736fbfd20d8747354da743fb121f0e308a0d298ff0d9344431890e41da66b5009af3f442c636b4f43", "0x81bf3a2d9755e206b515a508ac4d1109bf933c282a46a4ae4a1b4cb4a94e1d23642fad6bd452428845afa155742ade7e", "0x8de778d4742f945df40004964e165592f9c6b1946263adcdd5a88b00244bda46c7bb49098c8eb6b3d97a0dd46148a8ca", "0xb7a57b21d13121907ee28c5c1f80ee2e3e83a3135a8101e933cf57171209a96173ff5037f5af606e9fd6d066de6ed693", "0xb0877d1963fd9200414a38753dffd9f23a10eb3198912790d7eddbc9f6b477019d52ddd4ebdcb9f60818db076938a5a9", "0x88da2d7a6611bc16adc55fc1c377480c828aba4496c645e3efe0e1a67f333c05a0307f7f1d2df8ac013602c655c6e209", "0x95719eb02e8a9dede1a888c656a778b1c69b7716fbe3d1538fe8afd4a1bc972183c7d32aa7d6073376f7701df80116d8", "0x8e8a1ca971f2444b35af3376e85dccda3abb8e8e11d095d0a4c37628dfe5d3e043a377c3de68289ef142e4308e9941a0", "0xb720caaff02f6d798ac84c4f527203e823ff685869e3943c979e388e1c34c3f77f5c242c6daa7e3b30e511aab917b866", "0x86040d55809afeec10e315d1ad950d269d37cfee8c144cd8dd4126459e3b15a53b3e68df5981df3c2346d23c7b4baaf4", "0x82d8cabf13ab853db0377504f0aec00dba3a5cd3119787e8ad378ddf2c40b022ecfc67c642b7acc8c1e3dd03ab50993e", "0xb8d873927936719d2484cd03a6687d65697e17dcf4f0d5aed6f5e4750f52ef2133d4645894e7ebfc4ef6ce6788d404c8", "0xb1235594dbb15b674a419ff2b2deb644ad2a93791ca05af402823f87114483d6aa1689b7a9bea0f547ad12fe270e4344", "0xa53fda86571b0651f5affb74312551a082fffc0385cfd24c1d779985b72a5b1cf7c78b42b4f7e51e77055f8e5e915b00", "0xb579adcfd9c6ef916a5a999e77a0cb21d378c4ea67e13b7c58709d5da23a56c2e54218691fc4ac39a4a3d74f88cc31f7", "0xab79e584011713e8a2f583e483a91a0c2a40771b77d91475825b5acbea82db4262132901cb3e4a108c46d7c9ee217a4e", "0xa0fe58ea9eb982d7654c8aaf9366230578fc1362f6faae0594f8b9e659bcb405dff4aac0c7888bbe07f614ecf0d800a6", "0x867e50e74281f28ecd4925560e2e7a6f8911b135557b688254623acce0dbc41e23ac3e706a184a45d54c586edc416eb0", "0x89f81b61adda20ea9d0b387a36d0ab073dc7c7cbff518501962038be19867042f11fcc7ff78096e5d3b68c6d8dc04d9b", "0xa58ee91bb556d43cf01f1398c5811f76dc0f11efdd569eed9ef178b3b0715e122060ec8f945b4dbf6eebfa2b90af6fa6", "0xac460be540f4c840def2eef19fc754a9af34608d107cbadb53334cf194cc91138d53b9538fcd0ec970b5d4aa455b224a", "0xb09b91f929de52c09d48ca0893be6eb44e2f5210a6c394689dc1f7729d4be4e11d0474b178e80cea8c2ac0d081f0e811", "0x8d37a442a76b06a02a4e64c2504aea72c8b9b020ab7bcc94580fe2b9603c7c50d7b1e9d70d2a7daea19c68667e8f8c31", "0xa9838d4c4e3f3a0075a952cf7dd623307ec633fcc81a7cf9e52e66c31780de33dbb3d74c320dc7f0a4b72f7a49949515", "0xa44766b6251af458fe4f5f9ed1e02950f35703520b8656f09fc42d9a2d38a700c11a7c8a0436ac2e5e9f053d0bb8ff91", "0xad78d9481c840f5202546bea0d13c776826feb8b1b7c72e83d99a947622f0bf38a4208551c4c41beb1270d7792075457", "0xb619ffa8733b470039451e224b777845021e8dc1125f247a4ff2476cc774657d0ff9c5279da841fc1236047de9d81c60", "0xaf760b0a30a1d6af3bc5cd6686f396bd41779aeeb6e0d70a09349bd5da17ca2e7965afc5c8ec22744198fbe3f02fb331", "0xa0cc209abdb768b589fcb7b376b6e1cac07743288c95a1cf1a0354b47f0cf91fca78a75c1fcafa6f5926d6c379116608", "0x864add673c89c41c754eeb3cd8dcff5cdde1d739fce65c30e474a082bb5d813cba6412e61154ce88fdb6c12c5d9be35b", "0xb091443b0ce279327dc37cb484e9a5b69b257a714ce21895d67539172f95ffa326903747b64a3649e99aea7bb10d03f7", "0xa8c452b8c4ca8e0a61942a8e08e28f17fb0ef4c5b018b4e6d1a64038280afa2bf1169202f05f14af24a06ca72f448ccd", "0xa23c24721d18bc48d5dcf70effcbef89a7ae24e67158d70ae1d8169ee75d9a051d34b14e9cf06488bac324fe58549f26", "0x92a730e30eb5f3231feb85f6720489dbb1afd42c43f05a1610c6b3c67bb949ec8fde507e924498f4ffc646f7b07d9123", "0x8dbe5abf4031ec9ba6bb06d1a47dd1121fb9e03b652804069250967fd5e9577d0039e233441b7f837a7c9d67ba18c28e", "0xaa456bcfef6a21bb88181482b279df260297b3778e84594ebddbdf337e85d9e3d46ca1d0b516622fb0b103df8ec519b7", "0xa3b31ae621bd210a2b767e0e6f22eb28fe3c4943498a7e91753225426168b9a26da0e02f1dc5264da53a5ad240d9f51b", "0xaa8d66857127e6e71874ce2202923385a7d2818b84cb73a6c42d71afe70972a70c6bdd2aad1a6e8c5e4ca728382a8ea8", "0xac7e8e7a82f439127a5e40558d90d17990f8229852d21c13d753c2e97facf077cf59582b603984c3dd3faebd80aff4f5", "0x93a8bcf4159f455d1baa73d2ef2450dcd4100420de84169bbe28b8b7a5d1746273f870091a87a057e834f754f34204b1", "0x89d0ebb287c3613cdcae7f5acc43f17f09c0213fc40c074660120b755d664109ffb9902ed981ede79e018ddb0c845698", "0xa87ccbfad431406aadbee878d9cf7d91b13649d5f7e19938b7dfd32645a43b114eef64ff3a13201398bd9b0337832e5a", "0x833c51d0d0048f70c3eefb4e70e4ff66d0809c41838e8d2c21c288dd3ae9d9dfaf26d1742bf4976dab83a2b381677011", "0x8bcd6b1c3b02fffead432e8b1680bad0a1ac5a712d4225e220690ee18df3e7406e2769e1f309e2e803b850bc96f0e768", "0xb61e3dbd88aaf4ff1401521781e2eea9ef8b66d1fac5387c83b1da9e65c2aa2a56c262dea9eceeb4ad86c90211672db0", "0x866d3090db944ecf190dd0651abf67659caafd31ae861bab9992c1e3915cb0952da7c561cc7e203560a610f48fae633b", "0xa5e8971543c14274a8dc892b0be188c1b4fbc75c692ed29f166e0ea80874bc5520c2791342b7c1d2fb5dd454b03b8a5b", "0x8f2f9fc50471bae9ea87487ebd1bc8576ef844cc42d606af5c4c0969670fdf2189afd643e4de3145864e7773d215f37f", "0xb1bb0f2527db6d51f42b9224383c0f96048bbc03d469bf01fe1383173ef8b1cc9455d9dd8ba04d46057f46949bfc92b5", "0xaa7c99d906b4d7922296cfe2520473fc50137c03d68b7865c5bfb8adbc316b1034310ec4b5670c47295f4a80fb8d61e9", "0xa5d1da4d6aba555919df44cbaa8ff79378a1c9e2cfdfbf9d39c63a4a00f284c5a5724e28ecbc2d9dba27fe4ee5018bd5", "0xa8db53224f70af4d991b9aae4ffe92d2aa5b618ad9137784b55843e9f16cefbfd25ada355d308e9bbf55f6d2f7976fb3", "0xb6536c4232bb20e22af1a8bb12de76d5fec2ad9a3b48af1f38fa67e0f8504ef60f305a73d19385095bb6a9603fe29889", "0x87f7e371a1817a63d6838a8cf4ab3a8473d19ce0d4f40fd013c03d5ddd5f4985df2956531cc9f187928ef54c68f4f9a9", "0xae13530b1dbc5e4dced9d909ea61286ec09e25c12f37a1ed2f309b0eb99863d236c3b25ed3484acc8c076ad2fa8cd430", "0x98928d850247c6f7606190e687d5c94a627550198dbdbea0161ef9515eacdb1a0f195cae3bb293112179082daccf8b35", "0x918528bb8e6a055ad4db6230d3a405e9e55866da15c4721f5ddd1f1f37962d4904aad7a419218fe6d906fe191a991806", "0xb71e31a06afe065773dd3f4a6e9ef81c3292e27a3b7fdfdd452d03e05af3b6dd654c355f7516b2a93553360c6681a73a", "0x8870b83ab78a98820866f91ac643af9f3ff792a2b7fda34185a9456a63abdce42bfe8ad4dc67f08a6392f250d4062df4", "0x91eea1b668e52f7a7a5087fabf1cab803b0316f78d9fff469fbfde2162f660c250e4336a9eea4cb0450bd30ac067bc8b", "0x8b74990946de7b72a92147ceac1bd9d55999a8b576e8df68639e40ed5dc2062cfcd727903133de482b6dca19d0aaed82", "0x8ebad537fece090ebbab662bdf2618e21ca30cf6329c50935e8346d1217dcbe3c1fe1ea28efca369c6003ce0a94703c1", "0xa8640479556fb59ebd1c40c5f368fbd960932fdbb782665e4a0e24e2bdb598fc0164ce8c0726d7759cfc59e60a62e182", "0xa9a52a6bf98ee4d749f6d38be2c60a6d54b64d5cbe4e67266633dc096cf28c97fe998596707d31968cbe2064b72256bf", "0x847953c48a4ce6032780e9b39d0ed4384e0be202c2bbe2dfda3910f5d87aa5cd3c2ffbfcfae4dddce16d6ab657599b95", "0xb6f6e1485d3ec2a06abaecd23028b200b2e4a0096c16144d07403e1720ff8f9ba9d919016b5eb8dc5103880a7a77a1d3", "0x98dfc2065b1622f596dbe27131ea60bef7a193b12922cecb27f8c571404f483014f8014572e86ae2e341ab738e4887ef", "0xacb0d205566bacc87bbe2e25d10793f63f7a1f27fd9e58f4f653ceae3ffeba511eaf658e068fad289eeb28f9edbeb35b", "0xae4411ed5b263673cee894c11fe4abc72a4bf642d94022a5c0f3369380fcdfc1c21e277f2902972252503f91ada3029a", "0xac4a7a27ba390a75d0a247d93d4a8ef1f0485f8d373a4af4e1139369ec274b91b3464d9738eeaceb19cd6f509e2f8262", "0x87379c3bf231fdafcf6472a79e9e55a938d851d4dd662ab6e0d95fd47a478ed99e2ad1e6e39be3c0fc4f6d996a7dd833", "0x81316904b035a8bcc2041199a789a2e6879486ba9fddcba0a82c745cc8dd8374a39e523b91792170cd30be7aa3005b85", "0xb8206809c6cd027ed019f472581b45f7e12288f89047928ba32b4856b6560ad30395830d71e5e30c556f6f182b1fe690", "0x88d76c028f534a62e019b4a52967bb8642ede6becfa3807be68fdd36d366fc84a4ac8dc176e80a68bc59eb62caf5dff9", "0x8c3b8be685b0f8aad131ee7544d0e12f223f08a6f8edaf464b385ac644e0ddc9eff7cc7cb5c1b50ab5d71ea0f41d2213", "0x8d91410e004f76c50fdc05784157b4d839cb5090022c629c7c97a5e0c3536eeafee17a527b54b1165c3cd81774bb54ce", "0xb25c2863bc28ec5281ce800ddf91a7e1a53f4c6d5da1e6c86ef4616e93bcf55ed49e297216d01379f5c6e7b3c1e46728", "0x865f7b09ac3ca03f20be90c48f6975dd2588838c2536c7a3532a6aa5187ed0b709cd03d91ff4048061c10d0aa72b69ce", "0xb3f7477c90c11596eb4f8bbf34adbcb832638c4ff3cdd090d4d477ee50472ac9ddaf5be9ad7eca3f148960d362bbd098", "0x8db35fd53fca04faecd1c76a8227160b3ab46ac1af070f2492445a19d8ff7c25bbaef6c9fa0c8c088444561e9f7e4eb2", "0xa478b6e9d058a2e01d2fc053b739092e113c23a6a2770a16afbef044a3709a9e32f425ace9ba7981325f02667c3f9609", "0x98caa6bd38916c08cf221722a675a4f7577f33452623de801d2b3429595f988090907a7e99960fff7c076d6d8e877b31", "0xb79aaaacefc49c3038a14d2ac468cfec8c2161e88bdae91798d63552cdbe39e0e02f9225717436b9b8a40a022c633c6e", "0x845a31006c680ee6a0cc41d3dc6c0c95d833fcf426f2e7c573fa15b2c4c641fbd6fe5ebb0e23720cc3467d6ee1d80dc4", "0xa1bc287e272cf8b74dbf6405b3a5190883195806aa351f1dc8e525aa342283f0a35ff687e3b434324dedee74946dd185", "0xa4fd2dc8db75d3783a020856e2b3aa266dc6926e84f5c491ef739a3bddd46dc8e9e0fc1177937839ef1b18d062ffbb9e", "0xacbf0d3c697f57c202bb8c5dc4f3fc341b8fc509a455d44bd86acc67cad2a04495d5537bcd3e98680185e8aa286f2587", "0xa5caf423a917352e1b8e844f5968a6da4fdeae467d10c6f4bbd82b5eea46a660b82d2f5440d3641c717b2c3c9ed0be52", "0x8a39d763c08b926599ab1233219c49c825368fad14d9afc7c0c039224d37c00d8743293fd21645bf0b91eaf579a99867", "0xb2b53a496def0ba06e80b28f36530fbe0fb5d70a601a2f10722e59abee529369c1ae8fd0f2db9184dd4a2519bb832d94", "0xa73980fcef053f1b60ebbb5d78ba6332a475e0b96a0c724741a3abf3b59dd344772527f07203cf4c9cb5155ebed81fa0", "0xa070d20acce42518ece322c9db096f16aed620303a39d8d5735a0df6e70fbeceb940e8d9f5cc38f3314b2240394ec47b", "0xa50cf591f522f19ca337b73089557f75929d9f645f3e57d4f241e14cdd1ea3fb48d84bcf05e4f0377afbb789fbdb5d20", "0x82a5ffce451096aca8eeb0cd2ae9d83db3ed76da3f531a80d9a70a346359bf05d74863ce6a7c848522b526156a5e20cd", "0x88e0e84d358cbb93755a906f329db1537c3894845f32b9b0b691c29cbb455373d9452fadd1e77e20a623f6eaf624de6f", "0xaa07ac7b84a6d6838826e0b9e350d8ec75e398a52e9824e6b0da6ae4010e5943fec4f00239e96433f291fef9d1d1e609", "0xac8887bf39366034bc63f6cc5db0c26fd27307cbc3d6cce47894a8a019c22dd51322fb5096edc018227edfafc053a8f6", "0xb7d26c26c5b33f77422191dca94977588ab1d4b9ce7d0e19c4a3b4cd1c25211b78c328dbf81e755e78cd7d1d622ad23e", "0x99a676d5af49f0ba44047009298d8474cabf2d5bca1a76ba21eff7ee3c4691a102fdefea27bc948ccad8894a658abd02", "0xb0d09a91909ab3620c183bdf1d53d43d39eb750dc7a722c661c3de3a1a5d383ad221f71bae374f8a71867505958a3f76", "0x84681a883de8e4b93d68ac10e91899c2bbb815ce2de74bb48a11a6113b2a3f4df8aceabda1f5f67bc5aacac8c9da7221", "0x9470259957780fa9b43521fab3644f555f5343281c72582b56d2efd11991d897b3b481cafa48681c5aeb80c9663b68f7", "0xab1b29f7ece686e6fa968a4815da1d64f3579fed3bc92e1f3e51cd13a3c076b6cf695ed269d373300a62463dc98a4234", "0x8ab415bfcd5f1061f7687597024c96dd9c7cb4942b5989379a7a3b5742f7d394337886317659cbeacaf030234a24f972", "0xb9b524aad924f9acc63d002d617488f31b0016e0f0548f050cada285ce7491b74a125621638f19e9c96eabb091d945be", "0x8c4c373e79415061837dd0def4f28a2d5d74d21cb13a76c9049ad678ca40228405ab0c3941df49249847ecdefc1a5b78", "0xa8edf4710b5ab2929d3db6c1c0e3e242261bbaa8bcec56908ddadd7d2dad2dca9d6eb9de630b960b122ebeea41040421", "0x8d66bb3b50b9df8f373163629f9221b3d4b6980a05ea81dc3741bfe9519cf3ebba7ab98e98390bae475e8ede5821bd5c", "0x8d3c21bae7f0cfb97c56952bb22084b58e7bb718890935b73103f33adf5e4d99cd262f929c6eeab96209814f0dbae50a", "0xa5c66cfab3d9ebf733c4af24bebc97070e7989fe3c73e79ac85fb0e4d40ae44fb571e0fad4ad72560e13ed453900d14f", "0x9362e6b50b43dbefbc3254471372297b5dcce809cd3b60bf74a1268ab68bdb50e46e462cbd78f0d6c056330e982846af", "0x854630d08e3f0243d570cc2e856234cb4c1a158d9c1883bf028a76525aaa34be897fe918d5f6da9764a3735fa9ebd24a", "0x8c7d246985469ff252c3f4df6c7c9196fc79f05c1c66a609d84725c78001d0837c7a7049394ba5cf7e863e2d58af8417", "0xae050271e01b528925302e71903f785b782f7bf4e4e7a7f537140219bc352dc7540c657ed03d3a297ad36798ecdb98cd", "0x8d2ae9179fcf2b0c69850554580b52c1f4a5bd865af5f3028f222f4acad9c1ad69a8ef6c7dc7b03715ee5c506b74325e", "0xb8ef8de6ce6369a8851cd36db0ccf00a85077e816c14c4e601f533330af9e3acf0743a95d28962ed8bfcfc2520ef3cfe", "0xa6ecad6fdfb851b40356a8b1060f38235407a0f2706e7b8bb4a13465ca3f81d4f5b99466ac2565c60af15f022d26732e", "0x819ff14cdea3ab89d98e133cd2d0379361e2e2c67ad94eeddcdb9232efd509f51d12f4f03ebd4dd953bd262a886281f7", "0x8561cd0f7a6dbcddd83fcd7f472d7dbcba95b2d4fb98276f48fccf69f76d284e626d7e41314b633352df8e6333fd52a1", "0xb42557ccce32d9a894d538c48712cb3e212d06ac05cd5e0527ccd2db1078ee6ae399bf6a601ffdab1f5913d35fc0b20c", "0x89b4008d767aad3c6f93c349d3b956e28307311a5b1cec237e8d74bb0dee7e972c24f347fd56afd915a2342bd7bc32f0", "0x877487384b207e53f5492f4e36c832c2227f92d1bb60542cfeb35e025a4a7afc2b885fae2528b33b40ab09510398f83e", "0x8c411050b63c9053dd0cd81dacb48753c3d7f162028098e024d17cd6348482703a69df31ad6256e3d25a8bbf7783de39", "0xa8506b54a88d17ac10fb1b0d1fe4aa40eae7553a064863d7f6b52ccc4236dd4b82d01dca6ba87da9a239e3069ba879fb", "0xb1a24caef9df64750c1350789bb8d8a0db0f39474a1c74ea9ba064b1516db6923f00af8d57c632d58844fb8786c3d47a", "0x959d6e255f212b0708c58a2f75cb1fe932248c9d93424612c1b8d1e640149656059737e4db2139afd5556bcdacf3eda2", "0x84525af21a8d78748680b6535bbc9dc2f0cf9a1d1740d12f382f6ecb2e73811d6c1da2ad9956070b1a617c61fcff9fe5", "0xb74417d84597a485d0a8e1be07bf78f17ebb2e7b3521b748f73935b9afbbd82f34b710fb7749e7d4ab55b0c7f9de127d", "0xa4a9aecb19a6bab167af96d8b9d9aa5308eab19e6bfb78f5a580f9bf89bdf250a7b52a09b75f715d651cb73febd08e84", "0x9777b30be2c5ffe7d29cc2803a562a32fb43b59d8c3f05a707ab60ec05b28293716230a7d264d7cd9dd358fc031cc13e", "0x95dce7a3d4f23ac0050c510999f5fbf8042f771e8f8f94192e17bcbfa213470802ebdbe33a876cb621cf42e275cbfc8b", "0xb0b963ebcbbee847ab8ae740478544350b3ac7e86887e4dfb2299ee5096247cd2b03c1de74c774d9bde94ae2ee2dcd59", "0xa4ab20bafa316030264e13f7ef5891a2c3b29ab62e1668fcb5881f50a9acac6adbe3d706c07e62f2539715db768f6c43", "0x901478a297669d608e406fe4989be75264b6c8be12169aa9e0ad5234f459ca377f78484ffd2099a2fe2db5e457826427", "0x88c76e5c250810c057004a03408b85cd918e0c8903dc55a0dd8bb9b4fc2b25c87f9b8cf5943eb19fbbe99d36490050c5", "0x91607322bbad4a4f03fc0012d0821eff5f8c516fda45d1ec1133bface6f858bf04b25547be24159cab931a7aa08344d4", "0x843203e07fce3c6c81f84bc6dc5fb5e9d1c50c8811ace522dc66e8658433a0ef9784c947e6a62c11bf705307ef05212e", "0x91dd8813a5d6dddcda7b0f87f672b83198cd0959d8311b2b26fb1fae745185c01f796fbd03aad9db9b58482483fdadd8", "0x8d15911aacf76c8bcd7136e958febd6963104addcd751ce5c06b6c37213f9c4fb0ffd4e0d12c8e40c36d658999724bfd", "0x8a36c5732d3f1b497ebe9250610605ee62a78eaa9e1a45f329d09aaa1061131cf1d9df00f3a7d0fe8ad614a1ff9caaae", "0xa407d06affae03660881ce20dab5e2d2d6cddc23cd09b95502a9181c465e57597841144cb34d22889902aff23a76d049", "0xb5fd856d0578620a7e25674d9503be7d97a2222900e1b4738c1d81ff6483b144e19e46802e91161e246271f90270e6cf", "0x91b7708869cdb5a7317f88c0312d103f8ce90be14fb4f219c2e074045a2a83636fdc3e69e862049fc7c1ef000e832541", "0xb64719cc5480709d1dae958f1d3082b32a43376da446c8f9f64cb02a301effc9c34d9102051733315a8179aed94d53cc", "0x94347a9542ff9d18f7d9eaa2f4d9b832d0e535fe49d52aa2de08aa8192400eddabdb6444a2a78883e27c779eed7fdf5a", "0x840ef44a733ff1376466698cd26f82cf56bb44811e196340467f932efa3ae1ef9958a0701b3b032f50fd9c1d2aed9ab5", "0x90ab3f6f67688888a31ffc2a882bb37adab32d1a4b278951a21646f90d03385fc976715fc639a785d015751171016f10", "0xb56f35d164c24b557dbcbc8a4bfa681ec916f8741ffcb27fb389c164f4e3ed2be325210ef5bdaeae7a172ca9599ab442", "0xa7921a5a80d7cf6ae81ba9ee05e0579b18c20cd2852762c89d6496aa4c8ca9d1ca2434a67b2c16d333ea8e382cdab1e3", "0xa506bcfbd7e7e5a92f68a1bd87d07ad5fe3b97aeee40af2bf2cae4efcd77fff03f872732c5b7883aa6584bee65d6f8cb", "0xa8c46cff58931a1ce9cbe1501e1da90b174cddd6d50f3dfdfb759d1d4ad4673c0a8feed6c1f24c7af32865a7d6c984e5", "0xb45686265a83bff69e312c5149db7bb70ac3ec790dc92e392b54d9c85a656e2bf58596ce269f014a906eafc97461aa5f", "0x8d4009a75ccb2f29f54a5f16684b93202c570d7a56ec1a8b20173269c5f7115894f210c26b41e8d54d4072de2d1c75d0", "0xaef8810af4fc676bf84a0d57b189760ddc3375c64e982539107422e3de2580b89bd27aa6da44e827b56db1b5555e4ee8", "0x888f0e1e4a34f48eb9a18ef4de334c27564d72f2cf8073e3d46d881853ac1424d79e88d8ddb251914890588937c8f711", "0xb64b0aa7b3a8f6e0d4b3499fe54e751b8c3e946377c0d5a6dbb677be23736b86a7e8a6be022411601dd75012012c3555", "0x8d57776f519f0dd912ea14f79fbab53a30624e102f9575c0bad08d2dc754e6be54f39b11278c290977d9b9c7c0e1e0ad", "0xa018fc00d532ceb2e4de908a15606db9b6e0665dd77190e2338da7c87a1713e6b9b61554e7c1462f0f6d4934b960b15c", "0x8c932be83ace46f65c78e145b384f58e41546dc0395270c1397874d88626fdeda395c8a289d602b4c312fe98c1311856", "0x89174838e21639d6bdd91a0621f04dc056907b88e305dd66e46a08f6d65f731dea72ae87ca5e3042d609e8de8de9aa26", "0xb7b7f508bb74f7a827ac8189daa855598ff1d96fa3a02394891fd105d8f0816224cd50ac4bf2ed1cf469ace516c48184", "0xb31877ad682583283baadd68dc1bebd83f5748b165aadd7fe9ef61a343773b88bcd3a022f36d6c92f339b7bfd72820a9", "0xb79d77260b25daf9126dab7a193df2d7d30542786fa1733ffaf6261734770275d3ca8bae1d9915d1181a78510b3439db", "0x91894fb94cd4c1dd2ceaf9c53a7020c5799ba1217cf2d251ea5bc91ed26e1159dd758e98282ebe35a0395ef9f1ed15a0", "0xab59895cdafd33934ceedfc3f0d5d89880482cba6c99a6db93245f9e41987efd76e0640e80aef31782c9a8c7a83fccec", "0xaa22ea63654315e033e09d4d4432331904a6fc5fb1732557987846e3c564668ca67c60a324b4af01663a23af11a9ce4b", "0xb53ba3ef342601467e1f71aa280e100fbabbd38518fa0193e0099505036ee517c1ac78e96e9baeb549bb6879bb698fb0", "0x943fd69fd656f37487cca3605dc7e5a215fddd811caf228595ec428751fc1de484a0cb84c667fe4d7c35599bfa0e5e34", "0x9353128b5ebe0dddc555093cf3e5942754f938173541033e8788d7331fafc56f68d9f97b4131e37963ab7f1c8946f5f1", "0xa76cd3c566691f65cfb86453b5b31dbaf3cab8f84fe1f795dd1e570784b9b01bdd5f0b3c1e233942b1b5838290e00598", "0x983d84b2e53ffa4ae7f3ba29ef2345247ea2377686b74a10479a0ef105ecf90427bf53b74c96dfa346d0f842b6ffb25b", "0x92e0fe9063306894a2c6970c001781cff416c87e87cb5fbac927a3192655c3da4063e6fa93539f6ff58efac6adcc5514", "0xb00a81f03c2b8703acd4e2e4c21e06973aba696415d0ea1a648ace2b0ea19b242fede10e4f9d7dcd61c546ab878bc8f9", "0xb0d08d880f3b456a10bf65cff983f754f545c840c413aea90ce7101a66eb0a0b9b1549d6c4d57725315828607963f15a", "0x90cb64d03534f913b411375cce88a9e8b1329ce67a9f89ca5df8a22b8c1c97707fec727dbcbb9737f20c4cf751359277", "0x8327c2d42590dfcdb78477fc18dcf71608686ad66c49bce64d7ee874668be7e1c17cc1042a754bbc77c9daf50b2dae07", "0x8532171ea13aa7e37178e51a6c775da469d2e26ec854eb16e60f3307db4acec110d2155832c202e9ba525fc99174e3b0", "0x83ca44b15393d021de2a511fa5511c5bd4e0ac7d67259dce5a5328f38a3cce9c3a269405959a2486016bc27bb140f9ff", "0xb1d36e8ca812be545505c8214943b36cabee48112cf0de369957afa796d37f86bf7249d9f36e8e990f26f1076f292b13", "0x9803abf45be5271e2f3164c328d449efc4b8fc92dfc1225d38e09630909fe92e90a5c77618daa5f592d23fc3ad667094", "0xb268ad68c7bf432a01039cd889afae815c3e120f57930d463aece10af4fd330b5bd7d8869ef1bcf6b2e78e4229922edc", "0xa4c91a0d6f16b1553264592b4cbbbf3ca5da32ab053ffbdd3dbb1aed1afb650fb6e0dc5274f71a51d7160856477228db", "0xad89d043c2f0f17806277ffdf3ecf007448e93968663f8a0b674254f36170447b7527d5906035e5e56f4146b89b5af56", "0x8b6964f757a72a22a642e4d69102951897e20c21449184e44717bd0681d75f7c5bfa5ee5397f6e53febf85a1810d6ed1", "0xb08f5cdaabec910856920cd6e836c830b863eb578423edf0b32529488f71fe8257d90aed4a127448204df498b6815d79", "0xaf26bb3358be9d280d39b21d831bb53145c4527a642446073fee5a86215c4c89ff49a3877a7a549486262f6f57a0f476", "0xb4010b37ec4d7c2af20800e272539200a6b623ae4636ecbd0e619484f4ab9240d02bc5541ace3a3fb955dc0a3d774212", "0x82752ab52bdcc3cc2fc405cb05a2e694d3df4a3a68f2179ec0652536d067b43660b96f85f573f26fbd664a9ef899f650", "0x96d392dde067473a81faf2d1fea55b6429126b88b160e39b4210d31d0a82833ffd3a80e07d24d495aea2d96be7251547", "0xa76d8236d6671204d440c33ac5b8deb71fa389f6563d80e73be8b043ec77d4c9b06f9a586117c7f957f4af0331cbc871", "0xb6c90961f68b5e385d85c9830ec765d22a425f506904c4d506b87d8944c2b2c09615e740ed351df0f9321a7b93979cae", "0xa6ec5ea80c7558403485b3b1869cdc63bde239bafdf936d9b62a37031628402a36a2cfa5cfbb8e26ac922cb0a209b3ba", "0x8c3195bbdbf9bc0fc95fa7e3d7f739353c947f7767d1e3cb24d8c8602d8ea0a1790ac30b815be2a2ba26caa5227891e2", "0xa7f8a63d809f1155722c57f375ea00412b00147776ae4444f342550279ef4415450d6f400000a326bf11fea6c77bf941", "0x97fa404df48433a00c85793440e89bb1af44c7267588ae937a1f5d53e01e1c4d4fc8e4a6d517f3978bfdd6c2dfde012f", "0xa984a0a3836de3d8d909c4629a2636aacb85393f6f214a2ef68860081e9db05ad608024762db0dc35e895dc00e2d4cdd", "0x9526cf088ab90335add1db4d3a4ac631b58cbfbe88fa0845a877d33247d1cfeb85994522e1eb8f8874651bfb1df03e2a", "0xac83443fd0afe99ad49de9bf8230158c118e2814c9c89db5ac951c240d6c2ce45e7677221279d9e97848ec466b99aafe", "0xaeeefdbaba612e971697798ceaf63b247949dc823a0ad771ae5b988a5e882b338a98d3d0796230f49d533ec5ba411b39", "0xae3f248b5a7b0f92b7820a6c5ae21e5bd8f4265d4f6e21a22512079b8ee9be06393fd3133ce8ebac0faf23f4f8517e36", "0xa64a831b908eee784b8388b45447d2885ec0551b26b0c2b15e5f417d0a12c79e867fb7bd3d008d0af98b44336f8ec1ad", "0xb242238cd8362b6e440ba21806905714dd55172db25ec7195f3fc4937b2aba146d5cbf3cf691a1384b4752dc3b54d627", "0x819f97f337eea1ffb2a678cc25f556f1aab751c6b048993a1d430fe1a3ddd8bb411c152e12ca60ec6e057c190cd1db9a", "0xb9d7d187407380df54ee9fef224c54eec1bfabf17dc8abf60765b7951f538f59aa26fffd5846cfe05546c35f59b573f4", "0xaa6e3c14efa6a5962812e3f94f8ce673a433f4a82d07a67577285ea0eaa07f8be7115853122d12d6d4e1fdf64c504be1", "0x82268bee9c1662d3ddb5fb785abfae6fb8b774190f30267f1d47091d2cd4b3874db4372625aa36c32f27b0eee986269b", "0xb236459565b7b966166c4a35b2fa71030b40321821b8e96879d95f0e83a0baf33fa25721f30af4a631df209e25b96061", "0x8708d752632d2435d2d5b1db4ad1fa2558d776a013655f88e9a3556d86b71976e7dfe5b8834fdec97682cd94560d0d0d", "0xae1424a68ae2dbfb0f01211f11773732a50510b5585c1fb005cb892b2c6a58f4a55490b5c5b4483c6fce40e9d3236a52", "0xb3f5f722af9dddb07293c871ce97abbccba0093ca98c8d74b1318fa21396fc1b45b69c15084f63d728f9908442024506", "0x9606f3ce5e63886853ca476dc0949e7f1051889d529365c0cb0296fdc02abd088f0f0318ecd2cf36740a3634132d36f6", "0xb11a833a49fa138db46b25ff8cdda665295226595bc212c0931b4931d0a55c99da972c12b4ef753f7e37c6332356e350", "0xafede34e7dab0a9e074bc19a7daddb27df65735581ca24ad70c891c98b1349fcebbcf3ba6b32c2617fe06a5818dabc2d", "0x97993d456e459e66322d01f8eb13918979761c3e8590910453944bdff90b24091bb018ac6499792515c9923be289f99f", "0x977e3e967eff19290a192cd11df3667d511b398fb3ac9a5114a0f3707e25a0edcb56105648b1b85a8b7519fc529fc6f6", "0xb873a7c88bf58731fe1bf61ff6828bf114cf5228f254083304a4570e854e83748fc98683ddba62d978fff7909f2c5c47", "0xad4b2691f6f19da1d123aaa23cca3e876247ed9a4ab23c599afdbc0d3aa49776442a7ceaa996ac550d0313d9b9a36cee", "0xb9210713c78e19685608c6475bfa974b57ac276808a443f8b280945c5d5f9c39da43effa294bfb1a6c6f7b6b9f85bf6c", "0xa65152f376113e61a0e468759de38d742caa260291b4753391ee408dea55927af08a4d4a9918600a3bdf1df462dffe76", "0x8bf8c27ad5140dde7f3d2280fd4cc6b29ab76537e8d7aa7011a9d2796ee3e56e9a60c27b5c2da6c5e14fc866301dc195", "0x92fde8effc9f61393a2771155812b863cff2a0c5423d7d40aa04d621d396b44af94ddd376c28e7d2f53c930aea947484", "0x97a01d1dd9ee30553ce676011aea97fa93d55038ada95f0057d2362ae9437f3ed13de8290e2ff21e3167dd7ba10b9c3f", "0x89affffaa63cb2df3490f76f0d1e1d6ca35c221dd34057176ba739fa18d492355e6d2a5a5ad93a136d3b1fed0bb8aa19", "0x928b8e255a77e1f0495c86d3c63b83677b4561a5fcbbe5d3210f1e0fc947496e426d6bf3b49394a5df796c9f25673fc4", "0x842a0af91799c9b533e79ee081efe2a634cac6c584c2f054fb7d1db67dde90ae36de36cbf712ec9cd1a0c7ee79e151ea", "0xa65b946cf637e090baf2107c9a42f354b390e7316beb8913638130dbc67c918926eb87bec3b1fe92ef72bc77a170fa3b", "0xaafc0f19bfd71ab5ae4a8510c7861458b70ad062a44107b1b1dbacbfa44ba3217028c2824bd7058e2fa32455f624040b", "0x95269dc787653814e0be899c95dba8cfa384f575a25e671c0806fd80816ad6797dc819d30ae06e1d0ed9cb01c3950d47", "0xa1e760f7fa5775a1b2964b719ff961a92083c5c617f637fc46e0c9c20ab233f8686f7f38c3cb27d825c54dd95e93a59b", "0xac3b8a7c2317ea967f229eddc3e23e279427f665c4705c7532ed33443f1243d33453c1088f57088d2ab1e3df690a9cc9", "0xb787beeddfbfe36dd51ec4efd9cf83e59e84d354c3353cc9c447be53ae53d366ed1c59b686e52a92f002142c8652bfe0", "0xb7a64198300cb6716aa7ac6b25621f8bdec46ad5c07a27e165b3f774cdf65bcfdbf31e9bae0c16b44de4b00ada7a4244", "0xb8ae9f1452909e0c412c7a7fe075027691ea8df1347f65a5507bc8848f1d2c833d69748076db1129e5b4fb912f65c86c", "0x9682e41872456b9fa67def89e71f06d362d6c8ca85c9c48536615bc401442711e1c9803f10ab7f8ab5feaec0f9df20a6", "0x88889ff4e271dc1c7e21989cc39f73cde2f0475acd98078281591ff6c944fadeb9954e72334319050205d745d4df73df", "0x8f79b5b8159e7fd0d93b0645f3c416464f39aec353b57d99ecf24f96272df8a068ad67a6c90c78d82c63b40bb73989bb", "0x838c01a009a3d8558a3f0bdd5e22de21af71ca1aefc8423c91dc577d50920e9516880e87dce3e6d086e11cd45c9052d9", "0xb97f1c6eee8a78f137c840667cc288256e39294268a3009419298a04a1d0087c9c9077b33c917c65caf76637702dda8a", "0x972284ce72f96a61c899260203dfa06fc3268981732bef74060641c1a5068ead723e3399431c247ca034b0dae861e8df", "0x945a8d52d6d3db6663dbd3110c6587f9e9c44132045eeffba15621576d178315cb52870fa5861669f84f0bee646183fe", "0xa0a547b5f0967b1c3e5ec6c6a9a99f0578521489180dfdfbb5561f4d166baac43a2f06f950f645ce991664e167537eed", "0xa0592cda5cdddf1340033a745fd13a6eff2021f2e26587116c61c60edead067e0f217bc2bef4172a3c9839b0b978ab35", "0xb9c223b65a3281587fa44ec829e609154b32f801fd1de6950e01eafb07a8324243b960d5735288d0f89f0078b2c42b5b", "0x99ebfc3b8f9f98249f4d37a0023149ed85edd7a5abe062c8fb30c8c84555258b998bdcdd1d400bc0fa2a4aaa8b224466", "0x955b68526e6cb3937b26843270f4e60f9c6c8ece2fa9308fe3e23afa433309c068c66a4bc16ee2cf04220f095e9afce4", "0xb766caeafcc00378135ae53397f8a67ed586f5e30795462c4a35853de6681b1f17401a1c40958de32b197c083b7279c1", "0x921bf87cad947c2c33fa596d819423c10337a76fe5a63813c0a9dc78a728207ae7b339407a402fc4d0f7cba3af6da6fc", "0xa74ba1f3bc3e6c025db411308f49b347ec91da1c916bda9da61e510ec8d71d25e0ac0f124811b7860e5204f93099af27", "0xa29b4d144e0bf17a7e8353f2824cef0ce85621396babe8a0b873ca1e8a5f8d508b87866cf86da348470649fceefd735c", "0xa8040e12ffc3480dd83a349d06741d1572ef91932c46f5cf03aee8454254156ee95786fd013d5654725e674c920cec32", "0x8c4cf34ca60afd33923f219ffed054f90cd3f253ffeb2204a3b61b0183417e366c16c07fae860e362b0f2bfe3e1a1d35", "0x8195eede4ddb1c950459df6c396b2e99d83059f282b420acc34220cadeed16ab65c856f2c52568d86d3c682818ed7b37", "0x91fff19e54c15932260aa990c7fcb3c3c3da94845cc5aa8740ef56cf9f58d19b4c3c55596f8d6c877f9f4d22921d93aa", "0xa3e0bf7e5d02a80b75cf75f2db7e66cb625250c45436e3c136d86297d652590ec97c2311bafe407ad357c79ab29d107b", "0x81917ff87e5ed2ae4656b481a63ced9e6e5ff653b8aa6b7986911b8bc1ee5b8ef4f4d7882c3f250f2238e141b227e510", "0x915fdbe5e7de09c66c0416ae14a8750db9412e11dc576cf6158755fdcaf67abdbf0fa79b554cac4fe91c4ec245be073f", "0x8df27eafb5c3996ba4dc5773c1a45ca77e626b52e454dc1c4058aa94c2067c18332280630cc3d364821ee53bf2b8c130", "0x934f8a17c5cbb827d7868f5c8ca00cb027728a841000a16a3428ab16aa28733f16b52f58c9c4fbf75ccc45df72d9c4df", "0xb83f4da811f9183c25de8958bc73b504cf790e0f357cbe74ef696efa7aca97ad3b7ead1faf76e9f982c65b6a4d888fc2", "0x87188213c8b5c268dc2b6da413f0501c95749e953791b727450af3e43714149c115b596b33b63a2f006a1a271b87efd0", "0x83e9e888ab9c3e30761de635d9aabd31248cdd92f7675fc43e4b21fd96a03ec1dc4ad2ec94fec857ffb52683ac98e360", "0xb4b9a1823fe2d983dc4ec4e3aaea297e581c3fc5ab4b4af5fa1370caa37af2d1cc7fc6bfc5e7da60ad8fdce27dfe4b24", "0x856388bc78aef465dbcdd1f559252e028c9e9a2225c37d645c138e78f008f764124522705822a61326a6d1c79781e189", "0xa6431b36db93c3b47353ba22e7c9592c9cdfb9cbdd052ecf2cc3793f5b60c1e89bc96e6bae117bfd047f2308da00dd2f", "0xb619972d48e7e4291542dcde08f7a9cdc883c892986ded2f23ccb216e245cd8d9ad1d285347b0f9d7611d63bf4cee2bc", "0x8845cca6ff8595955f37440232f8e61d5351500bd016dfadd182b9d39544db77a62f4e0102ff74dd4173ae2c181d24ef", "0xb2f5f7fa26dcd3b6550879520172db2d64ee6aaa213cbef1a12befbce03f0973a22eb4e5d7b977f466ac2bf8323dcedd", "0x858b7f7e2d44bdf5235841164aa8b4f3d33934e8cb122794d90e0c1cac726417b220529e4f896d7b77902ab0ccd35b3a", "0x80b0408a092dae2b287a5e32ea1ad52b78b10e9c12f49282976cd738f5d834e03d1ad59b09c5ccaccc39818b87d06092", "0xb996b0a9c6a2d14d984edcd6ab56bc941674102980d65b3ad9733455f49473d3f587c8cbf661228a7e125ddbe07e3198", "0x90224fcebb36865293bd63af786e0c5ade6b67c4938d77eb0cbae730d514fdd0fe2d6632788e858afd29d46310cf86df", "0xb71351fdfff7168b0a5ec48397ecc27ac36657a8033d9981e97002dcca0303e3715ce6dd3f39423bc8ef286fa2e9e669", "0xae2a3f078b89fb753ce4ed87e0c1a58bb19b4f0cfb6586dedb9fcab99d097d659a489fb40e14651741e1375cfc4b6c5f", "0x8ef476b118e0b868caed297c161f4231bbeb863cdfa5e2eaa0fc6b6669425ce7af50dc374abceac154c287de50c22307", "0x92e46ab472c56cfc6458955270d3c72b7bde563bb32f7d4ab4d959db6f885764a3d864e1aa19802fefaa5e16b0cb0b54", "0x96a3f68323d1c94e73d5938a18a377af31b782f56212de3f489d22bc289cf24793a95b37f1d6776edf88114b5c1fa695", "0x962cc068cfce6faaa27213c4e43e44eeff0dfbb6d25b814e82c7da981fb81d7d91868fa2344f05fb552362f98cfd4a72", "0x895d4e4c4ad670abf66d43d59675b1add7afad7438ada8f42a0360c704cee2060f9ac15b4d27e9b9d0996bb801276fe3", "0xb3ad18d7ece71f89f2ef749b853c45dc56bf1c796250024b39a1e91ed11ca32713864049c9aaaea60cde309b47486bbf", "0x8f05404e0c0258fdbae50e97ccb9b72ee17e0bd2400d9102c0dad981dac8c4c71585f03e9b5d50086d0a2d3334cb55d1", "0x8bd877e9d4591d02c63c6f9fc9976c109de2d0d2df2bfa5f6a3232bab5b0b8b46e255679520480c2d7a318545efa1245", "0x8d4c16b5d98957c9da13d3f36c46f176e64e5be879f22be3179a2c0e624fe4758a82bf8c8027410002f973a3b84cd55a", "0x86e2a8dea86427b424fa8eada881bdff896907084a495546e66556cbdf070b78ba312bf441eb1be6a80006d25d5097a3", "0x8608b0c117fd8652fdab0495b08fadbeba95d9c37068e570de6fddfef1ba4a1773b42ac2be212836141d1bdcdef11a17", "0xa13d6febf5fb993ae76cae08423ca28da8b818d6ef0fde32976a4db57839cd45b085026b28ee5795f10a9a8e3098c683", "0x8e261967fa6de96f00bc94a199d7f72896a6ad8a7bbb1d6187cca8fad824e522880e20f766620f4f7e191c53321d70f9", "0x8b8e8972ac0218d7e3d922c734302803878ad508ca19f5f012bc047babd8a5c5a53deb5fe7c15a4c00fd6d1cb9b1dbd0", "0xb5616b233fb3574a2717d125a434a2682ff68546dccf116dd8a3b750a096982f185614b9fb6c7678107ff40a451f56fa", "0xaa6adf9b0c3334b0d0663f583a4914523b2ac2e7adffdb026ab9109295ff6af003ef8357026dbcf789896d2afded8d73", "0xacb72df56a0b65496cd534448ed4f62950bb1e11e50873b6ed349c088ee364441821294ce0f7c61bd7d38105bea3b442", "0xabae12df83e01ec947249fedd0115dc501d2b03ff7232092979eda531dbbca29ace1d46923427c7dde4c17bdf3fd7708", "0x820b4fc2b63a9fda7964acf5caf19a2fc4965007cb6d6b511fcafcb1f71c3f673a1c0791d3f86e3a9a1eb6955b191cc0", "0xaf277259d78c6b0f4f030a10c53577555df5e83319ddbad91afbd7c30bc58e7671c56d00d66ec3ab5ef56470cd910cee", "0xad4a861c59f1f5ca1beedd488fb3d131dea924fffd8e038741a1a7371fad7370ca5cf80dc01f177fbb9576713bb9a5b3", "0xb67a5162982ce6a55ccfb2f177b1ec26b110043cf18abd6a6c451cf140b5af2d634591eb4f28ad92177d8c7e5cd0a5e8", "0x96176d0a83816330187798072d449cbfccff682561e668faf6b1220c9a6535b32a6e4f852e8abb00f79abb87493df16b", "0xb0afe6e7cb672e18f0206e4423f51f8bd0017bf464c4b186d46332c5a5847647f89ff7fa4801a41c1b0b42f6135bcc92", "0x8fc5e7a95ef20c1278c645892811f6fe3f15c431ebc998a32ec0da44e7213ea934ed2be65239f3f49b8ec471e9914160", "0xb7793e41adda6c82ba1f2a31f656f6205f65bf8a3d50d836ee631bc7ce77c153345a2d0fc5c60edf8b37457c3729c4ec", "0xa504dd7e4d6b2f4379f22cc867c65535079c75ccc575955f961677fa63ecb9f74026fa2f60c9fb6323c1699259e5e9c8", "0xab899d00ae693649cc1afdf30fb80d728973d2177c006e428bf61c7be01e183866614e05410041bc82cb14a33330e69c", "0x8a3bd8b0b1be570b65c4432a0f6dc42f48a2000e30ab089cf781d38f4090467b54f79c0d472fcbf18ef6a00df69cc6f3", "0xb4d7028f7f76a96a3d7803fca7f507ae11a77c5346e9cdfccb120a833a59bda1f4264e425aa588e7a16f8e7638061d84", "0xb9c7511a76ea5fb105de905d44b02edb17008335766ee357ed386b7b3cf19640a98b38785cb14603c1192bee5886c9b6", "0x8563afb12e53aed71ac7103ab8602bfa8371ae095207cb0d59e8fd389b6ad1aff0641147e53cb6a7ca16c7f37c9c5e6b", "0x8e108be614604e09974a9ed90960c28c4ea330a3d9a0cb4af6dd6f193f84ab282b243ecdf549b3131036bebc8905690c", "0xb794d127fbedb9c5b58e31822361706ffac55ce023fbfe55716c3c48c2fd2f2c7660a67346864dfe588812d369cb50b6", "0xb797a3442fc3b44f41baefd30346f9ac7f96e770d010d53c146ce74ce424c10fb62758b7e108b8abfdc5fafd89d745cb", "0x993bb71e031e8096442e6205625e1bfddfe6dd6a83a81f3e2f84fafa9e5082ab4cad80a099f21eff2e81c83457c725c3", "0x8711ab833fc03e37acf2e1e74cfd9133b101ff4144fe30260654398ae48912ab46549d552eb9d15d2ea57760d35ac62e", "0xb21321fd2a12083863a1576c5930e1aecb330391ef83326d9d92e1f6f0d066d1394519284ddab55b2cb77417d4b0292f", "0x877d98f731ffe3ee94b0b5b72d127630fa8a96f6ca4f913d2aa581f67732df6709493693053b3e22b0181632ac6c1e3b", "0xae391c12e0eb8c145103c62ea64f41345973311c3bf7281fa6bf9b7faafac87bcf0998e5649b9ef81e288c369c827e07", "0xb83a2842f36998890492ab1cd5a088d9423d192681b9a3a90ec518d4c541bce63e6c5f4df0f734f31fbfdd87785a2463", "0xa21b6a790011396e1569ec5b2a423857b9bec16f543e63af28024e116c1ea24a3b96e8e4c75c6537c3e4611fd265e896", "0xb4251a9c4aab3a495da7a42e684ba4860dbcf940ad1da4b6d5ec46050cbe8dab0ab9ae6b63b5879de97b905723a41576", "0x8222f70aebfe6ac037f8543a08498f4cadb3edaac00336fc00437eb09f2cba758f6c38e887cc634b4d5b7112b6334836", "0x86f05038e060594c46b5d94621a1d9620aa8ba59a6995baf448734e21f58e23c1ea2993d3002ad5250d6edd5ba59b34f", "0xa7c0c749baef811ab31b973c39ceb1d94750e2bc559c90dc5eeb20d8bb6b78586a2b363c599ba2107d6be65cd435f24e", "0x861d46a5d70b38d6c1cd72817a2813803d9f34c00320c8b62f8b9deb67f5b5687bc0b37c16d28fd017367b92e05da9ca", "0xb3365d3dab639bffbe38e35383686a435c8c88b397b717cd4aeced2772ea1053ceb670f811f883f4e02975e5f1c4ac58", "0xa5750285f61ab8f64cd771f6466e2c0395e01b692fd878f2ef2d5c78bdd8212a73a3b1dfa5e4c8d9e1afda7c84857d3b", "0x835a10809ccf939bc46cf950a33b36d71be418774f51861f1cd98a016ade30f289114a88225a2c11e771b8b346cbe6ef", "0xa4f59473a037077181a0a62f1856ec271028546ca9452b45cedfcb229d0f4d1aabfc13062b07e536cc8a0d4b113156a2", "0x95cd14802180b224d44a73cc1ed599d6c4ca62ddcaa503513ccdc80aaa8be050cc98bd4b4f3b639549beb4587ac6caf9", "0x973b731992a3e69996253d7f36dd7a0af1982b5ed21624b77a7965d69e9a377b010d6dabf88a8a97eec2a476259859cc", "0xaf8a1655d6f9c78c8eb9a95051aa3baaf9c811adf0ae8c944a8d3fcba87b15f61021f3baf6996fa0aa51c81b3cb69de1", "0x835aad5c56872d2a2d6c252507b85dd742bf9b8c211ccb6b25b52d15c07245b6d89b2a40f722aeb5083a47cca159c947", "0xabf4e970b02bef8a102df983e22e97e2541dd3650b46e26be9ee394a3ea8b577019331857241d3d12b41d4eacd29a3ac", "0xa13c32449dbedf158721c13db9539ae076a6ce5aeaf68491e90e6ad4e20e20d1cdcc4a89ed9fd49cb8c0dd50c17633c1", "0x8c8f78f88b7e22dd7e9150ab1c000f10c28e696e21d85d6469a6fe315254740f32e73d81ab1f3c1cf8f544c86df506e8", "0xb4b77f2acfe945abf81f2605f906c10b88fb4d28628487fb4feb3a09f17f28e9780445dfcee4878349d4c6387a9d17d4", "0x8d255c235f3812c6ecc646f855fa3832be5cb4dbb9c9e544989fafdf3f69f05bfd370732eaf954012f0044aa013fc9c6", "0xb982efd3f34b47df37c910148ac56a84e8116647bea24145a49e34e0a6c0176e3284d838dae6230cb40d0be91c078b85", "0x983f365aa09bd85df2a6a2ad8e4318996b1e27d02090755391d4486144e40d80b1fbfe1c798d626db92f52e33aa634da", "0x95fd1981271f3ea3a41d654cf497e6696730d9ff7369f26bc4d7d15c7adb4823dd0c42e4a005a810af12d234065e5390", "0xa9f5219bd4b913c186ef30c02f995a08f0f6f1462614ea5f236964e02bdaa33db9d9b816c4aee5829947840a9a07ba60", "0x9210e6ceb05c09b46fd09d036287ca33c45124ab86315e5d6911ff89054f1101faaa3e83d123b7805056d388bcec6664", "0x8ed9cbf69c6ff3a5c62dd9fe0d7264578c0f826a29e614bc2fb4d621d90c8c9992438accdd7a614b1dca5d1bb73dc315", "0x85cf2a8cca93e00da459e3cecd22c342d697eee13c74d5851634844fc215f60053cf84b0e03c327cb395f48d1c71a8a4", "0x8818a18e9a2ec90a271b784400c1903089ffb0e0b40bc5abbbe12fbebe0f731f91959d98c5519ef1694543e31e2016d4", "0x8dabc130f296fa7a82870bf9a8405aaf542b222ed9276bba9bd3c3555a0f473acb97d655ee7280baff766a827a8993f0", "0xac7952b84b0dc60c4d858f034093b4d322c35959605a3dad2b806af9813a4680cb038c6d7f4485b4d6b2ff502aaeca25", "0xad65cb6d57b48a2602568d2ec8010baed0eb440eec7638c5ec8f02687d764e9de5b5d42ad5582934e592b48471c22d26", "0xa02ab8bd4c3d114ea23aebdd880952f9495912817da8c0c08eabc4e6755439899d635034413d51134c72a6320f807f1c", "0x8319567764b8295402ec1ebef4c2930a138480b37e6d7d01c8b4c9cd1f2fc3f6e9a44ae6e380a0c469b25b06db23305f", "0xafec53b2301dc0caa8034cd9daef78c48905e6068d692ca23d589b84a6fa9ddc2ed24a39480597e19cb3e83eec213b3f", "0xac0b4ffdb5ae08e586a9cdb98f9fe56f4712af3a97065e89e274feacfb52b53c839565aee93c4cfaaccfe51432c4fab0", "0x8972cbf07a738549205b1094c5987818124144bf187bc0a85287c94fdb22ce038c0f11df1aa16ec5992e91b44d1af793", "0xb7267aa6f9e3de864179b7da30319f1d4cb2a3560f2ea980254775963f1523b44c680f917095879bebfa3dc2b603efcf", "0x80f68f4bfc337952e29504ee5149f15093824ea7ab02507efd1317a670f6cbc3611201848560312e3e52e9d9af72eccf", "0x8897fee93ce8fc1e1122e46b6d640bba309384dbd92e46e185e6364aa8210ebf5f9ee7e5e604b6ffba99aa80a10dd7d0", "0xb58ea6c02f2360be60595223d692e82ee64874fda41a9f75930f7d28586f89be34b1083e03bbc1575bbfdda2d30db1ea", "0x85a523a33d903280d70ac5938770453a58293480170c84926457ac2df45c10d5ff34322ab130ef4a38c916e70d81af53", "0xa2cbf045e1bed38937492c1f2f93a5ba41875f1f262291914bc1fc40c60bd0740fb3fea428faf6da38b7c180fe8ac109", "0x8c09328770ed8eb17afc6ac7ddd87bb476de18ed63cab80027234a605806895959990c47bd10d259d7f3e2ecb50074c9", "0xb4b9e19edb4a33bde8b7289956568a5b6b6557404e0a34584b5721fe6f564821091013fbb158e2858c6d398293bb4b59", "0x8a47377df61733a2aa5a0e945fce00267f8e950f37e109d4487d92d878fb8b573317bb382d902de515b544e9e233458d", "0xb5804c9d97efeff5ca94f3689b8088c62422d92a1506fd1d8d3b1b30e8a866ad0d6dad4abfa051dfc4471250cac4c5d9", "0x9084a6ee8ec22d4881e9dcc8a9eb3c2513523d8bc141942370fd191ad2601bf9537a0b1e84316f3209b3d8a54368051e", "0x85447eea2fa26656a649f8519fa67279183044791d61cf8563d0783d46d747d96af31d0a93507bbb2242666aa87d3720", "0x97566a84481027b60116c751aec552adfff2d9038e68d48c4db9811fb0cbfdb3f1d91fc176a0b0d988a765f8a020bce1", "0xae87e5c1b9e86c49a23dceda4ecfd1dcf08567f1db8e5b6ec752ebd45433c11e7da4988573cdaebbb6f4135814fc059e", "0xabee05cf9abdbc52897ac1ce9ed157f5466ed6c383d6497de28616238d60409e5e92619e528af8b62cc552bf09970dc2", "0xae6d31cd7bf9599e5ee0828bab00ceb4856d829bba967278a73706b5f388465367aa8a6c7da24b5e5f1fdd3256ef8e63", "0xac33e7b1ee47e1ee4af472e37ab9e9175260e506a4e5ce449788075da1b53c44cb035f3792d1eea2aa24b1f688cc6ed3", "0x80f65b205666b0e089bb62152251c48c380a831e5f277f11f3ef4f0d52533f0851c1b612267042802f019ec900dc0e8f", "0x858520ad7aa1c9fed738e3b583c84168f2927837ad0e1d326afe9935c26e9b473d7f8c382e82ef1fe37d2b39bb40a1ee", "0xb842dd4af8befe00a97c2d0f0c33c93974761e2cb9e5ab8331b25170318ddd5e4bdbc02d8f90cbfdd5f348f4f371c1f7", "0x8bf2cb79bc783cb57088aae7363320cbeaabd078ffdec9d41bc74ff49e0043d0dad0086a30e5112b689fd2f5a606365d", "0x982eb03bbe563e8850847cd37e6a3306d298ab08c4d63ab6334e6b8c1fa13fce80cf2693b09714c7621d74261a0ff306", "0xb143edb113dec9f1e5105d4a93fbe502b859e587640d3db2f628c09a17060e6aec9e900e2c8c411cda99bc301ff96625", "0xaf472d9befa750dcebc5428fe1a024f18ec1c07bca0f95643ce6b5f4189892a910285afb03fd7ed7068fbe614e80d33c", "0xa97e3bc57ede73ecd1bbf02de8f51b4e7c1a067da68a3cd719f4ba26a0156cbf1cef2169fd35a18c5a4cced50d475998", "0xa862253c937cf3d75d7183e5f5be6a4385d526aeda5171c1c60a8381fea79f88f5f52a4fab244ecc70765d5765e6dfd5", "0x90cb776f8e5a108f1719df4a355bebb04bf023349356382cae55991b31720f0fd03206b895fa10c56c98f52453be8778", "0xa7614e8d0769dccd520ea4b46f7646e12489951efaef5176bc889e9eb65f6e31758df136b5bf1e9107e68472fa9b46ec", "0xac3a9b80a3254c42e5ed3a090a0dd7aee2352f480de96ad187027a3bb6c791eddfc3074b6ffd74eea825188f107cda4d", "0x82a01d0168238ef04180d4b6e0a0e39024c02c2d75b065017c2928039e154d093e1af4503f4d1f3d8a948917abb5d09f", "0x8fab000a2b0eef851a483aec8d2dd85fe60504794411a2f73ed82e116960547ac58766cb73df71aea71079302630258d", "0x872451a35c6db61c63e9b8bb9f16b217f985c20be4451c14282c814adb29d7fb13f201367c664435c7f1d4d9375d7a58", "0x887d9ff54cc96b35d562df4a537ff972d7c4b3fd91ab06354969a4cfede0b9fc68bbffb61d0dbf1a58948dc701e54f5a", "0x8cb5c2a6bd956875d88f41ae24574434f1308514d44057b55c9c70f13a3366ed054150eed0955a38fda3f757be73d55f", "0x89ad0163cad93e24129d63f8e38422b7674632a8d0a9016ee8636184cab177659a676c4ee7efba3abe1a68807c656d60", "0xb9ec01c7cab6d00359b5a0b4a1573467d09476e05ca51a9227cd16b589a9943d161eef62dcc73f0de2ec504d81f4d252", "0x8031d17635d39dfe9705c485d2c94830b6fc9bc67b91300d9d2591b51e36a782e77ab5904662effa9382d9cca201f525", "0x8be5a5f6bc8d680e5092d6f9a6585acbaaaa2ddc671da560dcf5cfa4472f4f184b9597b5b539438accd40dda885687cc", "0xb1fc0f052fae038a2e3de3b3a96b0a1024b009de8457b8b3adb2d315ae68a89af905720108a30038e5ab8d0d97087785", "0x8b8bdc77bd3a6bc7ca5492b6f8c614852c39a70d6c8a74916eaca0aeb4533b11898b8820a4c2620a97bf35e275480029", "0xaf35f4dc538d4ad5cdf710caa38fd1eb496c3fa890a047b6a659619c5ad3054158371d1e88e0894428282eed9f47f76b", "0x8166454a7089cc07758ad78724654f4e7a1a13e305bbf88ddb86f1a4b2904c4fc8ab872d7da364cdd6a6c0365239e2ad", "0xab287c7d3addce74ce40491871c768abe01daaa0833481276ff2e56926b38a7c6d2681ffe837d2cc323045ad1a4414f9", "0xb90317f4505793094d89365beb35537f55a6b5618904236258dd04ca61f21476837624a2f45fef8168acf732cab65579", "0x98ae5ea27448e236b6657ab5ef7b1cccb5372f92ab25f5fa651fbac97d08353a1dae1b280b1cd42b17d2c6a70a63ab9d", "0xadcf54e752d32cbaa6cb98fbca48d8cd087b1db1d131d465705a0d8042c8393c8f4d26b59006eb50129b21e6240f0c06", "0xb591a3e4db18a7345fa935a8dd7994bbac5cc270b8ebd84c8304c44484c7a74afb45471fdbe4ab22156a30fae1149b40", "0x806b53ac049a42f1dcc1d6335505371da0bf27c614f441b03bbf2e356be7b2fb4eed7117eabcce9e427a542eaa2bf7d8", "0x800482e7a772d49210b81c4a907f5ce97f270b959e745621ee293cf8c71e8989363d61f66a98f2d16914439544ca84c7", "0x99de9eafdad3617445312341644f2bb888680ff01ce95ca9276b1d2e5ef83fa02dab5e948ebf66c17df0752f1bd37b70", "0x961ee30810aa4c93ae157fbe9009b8e443c082192bd36a73a6764ff9b2ad8b0948fe9a73344556e01399dd77badb4257", "0xae0a361067c52efbe56c8adf982c00432cd478929459fc7f74052c8ee9531cd031fe1335418fde53f7c2ef34254eb7ac", "0xa3503d16b6b27eb20c1b177bcf90d13706169220523a6271b85b2ce35a9a2b9c5bed088540031c0a4ebfdae3a4c6ab04", "0x909420122c3e723289ca4e7b81c2df5aff312972a2203f4c45821b176e7c862bf9cac7f7df3adf1d59278f02694d06e7", "0x989f42380ae904b982f85d0c6186c1aef5d6bcba29bcfbb658e811b587eb2749c65c6e4a8cc6409c229a107499a4f5d7", "0x8037a6337195c8e26a27ea4ef218c6e7d79a9720aaab43932d343192abc2320fe72955f5e431c109093bda074103330a", "0xb312e168663842099b88445e940249cc508f080ab0c94331f672e7760258dbd86be5267e4cf25ea25facb80bff82a7e9", "0xaaa3ff8639496864fcdbfdda1ac97edc4f08e3c9288b768f6c8073038c9fbbf7e1c4bea169b4d45c31935cdf0680d45e", "0x97dbd3df37f0b481a311dfc5f40e59227720f367912200d71908ef6650f32cc985cb05b981e3eea38958f7e48d10a15d", "0xa89d49d1e267bb452d6cb621b9a90826fe55e9b489c0427b94442d02a16f390eed758e209991687f73f6b5a032321f42", "0x9530dea4e0e19d6496f536f2e75cf7d814d65fde567055eb20db48fd8d20d501cd2a22fb506db566b94c9ee10f413d43", "0x81a7009b9e67f1965fa7da6a57591c307de91bf0cd35ab4348dc4a98a4961e096d004d7e7ad318000011dc4342c1b809", "0x83440a9402b766045d7aca61a58bba2aa29cac1cf718199e472ba086f5d48093d9dda4d135292ba51d049a23964eceae", "0xa06c9ce5e802df14f6b064a3d1a0735d429b452f0e2e276042800b0a4f16df988fd94cf3945921d5dd3802ab2636f867", "0xb1359e358b89936dee9e678a187aad3e9ab14ac40e96a0a68f70ee2583cdcf467ae03bef4215e92893f4e12f902adec8", "0x835304f8619188b4d14674d803103d5a3fa594d48e96d9699e653115dd05fdc2dda6ba3641cf7ad53994d448da155f02", "0x8327cba5a9ff0d3f5cd0ae55e77167448926d5fcf76550c0ad978092a14122723090c51c415e88e42a2b62eb07cc3981", "0xb373dcdaea85f85ce9978b1426a7ef4945f65f2d3467a9f1cc551a99766aac95df4a09e2251d3f89ca8c9d1a7cfd7b0e", "0xab1422dc41af2a227b973a6fd124dfcb2367e2a11a21faa1d381d404f51b7257e5bc82e9cf20cd7fe37d7ae761a2ab37", "0xa93774a03519d2f20fdf2ef46547b0a5b77c137d6a3434b48d56a2cbef9e77120d1b85d0092cf8842909213826699477", "0x8eb967a495a38130ea28711580b7e61bcd1d051cd9e4f2dbf62f1380bd86e0d60e978d72f6f31e909eb97b3b9a2b867c", "0xae8213378da1287ba1fe4242e1acaec19b877b6fe872400013c6eac1084b8d03156792fa3020201725b08228a1e80f49", "0xb143daf6893d674d607772b3b02d8ac48f294237e2f2c87963c0d4e26d9227d94a2a13512457c3d5883544bbc259f0ef", "0xb343bd2aca8973888e42542218924e2dda2e938fd1150d06878af76f777546213912b7c7a34a0f94186817d80ffa185c", "0xb188ebc6a8c3007001aa347ae72cc0b15d09bc6c19a80e386ee4b334734ec0cc2fe8b493c2422f38d1e6d133cc3db6fe", "0xb795f6a8b9b826aaeee18ccd6baf6c5adeeec85f95eb5b6d19450085ec7217e95a2d9e221d77f583b297d0872073ba0e", "0xb1c7dbd998ad32ae57bfa95deafa147024afd57389e98992c36b6e52df915d3d5a39db585141ec2423173e85d212fed8", "0x812bcdeb9fe5f12d0e1df9964798056e1f1c3de3b17b6bd2919b6356c4b86d8e763c01933efbe0224c86a96d5198a4be", "0xb19ebeda61c23d255cbf472ef0b8a441f4c55b70f0d8ed47078c248b1d3c7c62e076b43b95c00a958ec8b16d5a7cb0d7", "0xb02adc9aaa20e0368a989c2af14ff48b67233d28ebee44ff3418bb0473592e6b681af1cc45450bd4b175df9051df63d9", "0x8d87f0714acee522eb58cec00360e762adc411901dba46adc9227124fa70ee679f9a47e91a6306d6030dd4eb8de2f3c1", "0x8be54cec21e74bcc71de29dc621444263737db15f16d0bb13670f64e42f818154e04b484593d19ef95f2ee17e4b3fe21", "0xab8e20546c1db38d31493b5d5f535758afb17e459645c1b70813b1cf7d242fd5d1f4354a7c929e8f7259f6a25302e351", "0x89f035a1ed8a1e302ac893349ba8ddf967580fcb6e73d44af09e3929cde445e97ff60c87dafe489e2c0ab9c9986cfa00", "0x8b2b0851a795c19191a692af55f7e72ad2474efdc5401bc3733cfdd910e34c918aaebe69d5ea951bdddf3c01cabbfc67", "0xa4edb52c2b51495ccd1ee6450fc14b7b3ede8b3d106808929d02fb31475bacb403e112ba9c818d2857651e508b3a7dd1", "0x9569341fded45d19f00bcf3cbf3f20eb2b4d82ef92aba3c8abd95866398438a2387437e580d8b646f17cf6fde8c5af23", "0xaa4b671c6d20f72f2f18a939a6ff21cc37e0084b44b4a717f1be859a80b39fb1be026b3205adec2a66a608ec2bcd578f", "0x94902e980de23c4de394ad8aec91b46f888d18f045753541492bfbb92c59d3daa8de37ae755a6853744af8472ba7b72b", "0xaf651ef1b2a0d30a7884557edfad95b6b5d445a7561caebdc46a485aedd25932c62c0798465c340a76f6feaa196dd712", "0xb7b669b8e5a763452128846dd46b530dca4893ace5cc5881c7ddcd3d45969d7e73fbebdb0e78aa81686e5f7b22ec5759", "0x82507fd4ebe9fa656a7f2e084d64a1fa6777a2b0bc106d686e2d9d2edafc58997e58cb6bfd0453b2bf415704aa82ae62", "0xb40bce2b42b88678400ecd52955bbdadd15f8b9e1b3751a1a3375dc0efb5ca3ee258cf201e1140b3c09ad41217d1d49e", "0xb0210d0cbb3fbf3b8cdb39e862f036b0ff941cd838e7aaf3a8354e24246e64778d22f3de34572e6b2a580614fb6425be", "0x876693cba4301b251523c7d034108831df3ce133d8be5a514e7a2ca494c268ca0556fa2ad8310a1d92a16b55bcd99ea9", "0x8660281406d22a4950f5ef050bf71dd3090edb16eff27fa29ef600cdea628315e2054211ed2cc6eaf8f2a1771ef689fd", "0xa610e7e41e41ab66955b809ba4ade0330b8e9057d8efc9144753caed81995edeb1a42a53f93ce93540feca1fae708dac", "0xa49e2c176a350251daef1218efaccc07a1e06203386ede59c136699d25ca5cb2ac1b800c25b28dd05678f14e78e51891", "0x83e0915aa2b09359604566080d411874af8c993beba97d4547782fdbe1a68e59324b800ff1f07b8db30c71adcbd102a8", "0xa19e84e3541fb6498e9bb8a099c495cbfcad113330e0262a7e4c6544495bb8a754b2208d0c2d895c93463558013a5a32", "0x87f2bd49859a364912023aca7b19a592c60214b8d6239e2be887ae80b69ebdeb59742bdebcfa73a586ab23b2c945586c", "0xb8e8fdddae934a14b57bc274b8dcd0d45ebb95ddbaabef4454e0f6ce7d3a5a61c86181929546b3d60c447a15134d08e1", "0x87e0c31dcb736ea4604727e92dc1d9a3cf00adcff79df3546e02108355260f3dd171531c3c0f57be78d8b28058fcc8c0", "0x9617d74e8f808a4165a8ac2e30878c349e1c3d40972006f0787b31ea62d248c2d9f3fc3da83181c6e57e95feedfd0e8c", "0x8949e2cee582a2f8db86e89785a6e46bc1565c2d8627d5b6bf43ba71ffadfab7e3c5710f88dcb5fb2fc6edf6f4fae216", "0xad3fa7b0edceb83118972a2935a09f409d09a8db3869f30be3a76f67aa9fb379cabb3a3aff805ba023a331cad7d7eb64", "0x8c95718a4112512c4efbd496be38bf3ca6cdcaad8a0d128f32a3f9aae57f3a57bdf295a3b372a8c549fda8f4707cffed", "0x88f3261d1e28a58b2dee3fcc799777ad1c0eb68b3560f9b4410d134672d9533532a91ea7be28a041784872632d3c9d80", "0xb47472a41d72dd2e8b72f5c4f8ad626737dde3717f63d6bc776639ab299e564cbad0a2ad5452a07f02ff49a359c437e5", "0x9896d21dc2e8aad87b76d6df1654f10cd7bceed4884159d50a818bea391f8e473e01e14684814c7780235f28e69dca6e", "0x82d47c332bbd31bbe83b5eb44a23da76d4a7a06c45d7f80f395035822bc27f62f59281d5174e6f8e77cc9b5c3193d6f0", "0x95c74cd46206e7f70c9766117c34c0ec45c2b0f927a15ea167901a160e1530d8522943c29b61e03568aa0f9c55926c53", "0xa89d7757825ae73a6e81829ff788ea7b3d7409857b378ebccd7df73fdbe62c8d9073741cf038314971b39af6c29c9030", "0x8c1cd212d0b010905d560688cfc036ae6535bc334fa8b812519d810b7e7dcf1bb7c5f43deaa40f097158358987324a7f", "0xb86993c383c015ed8d847c6b795164114dd3e9efd25143f509da318bfba89389ea72a420699e339423afd68b6512fafb", "0x8d06bd379c6d87c6ed841d8c6e9d2d0de21653a073725ff74be1934301cc3a79b81ef6dd0aad4e7a9dc6eac9b73019bc", "0x81af4d2d87219985b9b1202d724fe39ef988f14fef07dfe3c3b11714e90ffba2a97250838e8535eb63f107abfe645e96", "0x8c5e0af6330a8becb787e4b502f34f528ef5756e298a77dc0c7467433454347f3a2e0bd2641fbc2a45b95e231c6e1c02", "0x8e2a8f0f04562820dc8e7da681d5cad9fe2e85dd11c785fb6fba6786c57a857e0b3bd838fb849b0376c34ce1665e4837", "0xa39be8269449bfdfc61b1f62077033649f18dae9bef7c6163b9314ca8923691fb832f42776f0160b9e8abd4d143aa4e1", "0x8c154e665706355e1cc98e0a4cabf294ab019545ba9c4c399d666e6ec5c869ca9e1faf8fb06cd9c0a5c2f51a7d51b70a", "0xa046a7d4de879d3ebd4284f08f24398e9e3bf006cd4e25b5c67273ade248689c69affff92ae810c07941e4904296a563", "0xafd94c1cb48758e5917804df03fb38a6da0e48cd9b6262413ea13b26973f9e266690a1b7d9d24bbaf7e82718e0e594b0", "0x859e21080310c8d6a38e12e2ac9f90a156578cdeb4bb2e324700e97d9a5511cd6045dc39d1d0de3f94aeed043a24119d", "0xa219fb0303c379d0ab50893264919f598e753aac9065e1f23ef2949abc992577ab43c636a1d2c089203ec9ddb941e27d", "0xb0fdb639d449588a2ca730afcba59334e7c387342d56defdfb7ef79c493f7fd0e5277eff18e7203e756c7bdda5803047", "0x87f9c3b7ed01f54368aca6dbcf2f6e06bff96e183c4b2c65f8baa23b377988863a0a125d5cdd41a072da8462ced4c070", "0x99ef7a5d5ac2f1c567160e1f8c95f2f38d41881850f30c461a205f7b1b9fb181277311333839b13fb3ae203447e17727", "0xaeaca9b1c2afd24e443326cc68de67b4d9cedb22ad7b501a799d30d39c85bb2ea910d4672673e39e154d699e12d9b3dc", "0xa11675a1721a4ba24dd3d0e4c3c33a6edf4cd1b9f6b471070b4386c61f77452266eae6e3f566a40cfc885eada9a29f23", "0xb228334445e37b9b49cb4f2cc56b454575e92173ddb01370a553bba665adadd52df353ad74470d512561c2c3473c7bb9", "0xa18177087c996572d76f81178d18ed1ceebc8362a396348ce289f1d8bd708b9e99539be6fccd4acb1112381cfc5749b4", "0x8e7b8bf460f0d3c99abb19803b9e43422e91507a1c0c22b29ee8b2c52d1a384da4b87c292e28eff040db5be7b1f8641f", "0xb03d038d813e29688b6e6f444eb56fec3abba64c3d6f890a6bcf2e916507091cdb2b9d2c7484617be6b26552ed1c56cb", "0xa1c88ccd30e934adfc5494b72655f8afe1865a84196abfb376968f22ddc07761210b6a9fb7638f1413d1b4073d430290", "0x961b714faebf172ad2dbc11902461e286e4f24a99a939152a53406117767682a571057044decbeb3d3feef81f4488497", "0xa03dc4059b46effdd786a0a03cc17cfee8585683faa35bb07936ded3fa3f3a097f518c0b8e2db92fd700149db1937789", "0xadf60180c99ca574191cbcc23e8d025b2f931f98ca7dfcebfc380226239b6329347100fcb8b0fcb12db108c6ad101c07", "0x805d4f5ef24d46911cbf942f62cb84b0346e5e712284f82b0db223db26d51aabf43204755eb19519b00e665c7719fcaa", "0x8dea7243e9c139662a7fe3526c6c601eee72fd8847c54c8e1f2ad93ef7f9e1826b170afe58817dac212427164a88e87f", "0xa2ba42356606d651b077983de1ad643650997bb2babb188c9a3b27245bb65d2036e46667c37d4ce02cb1be5ae8547abe", "0xaf2ae50b392bdc013db2d12ce2544883472d72424fc767d3f5cb0ca2d973fc7d1f425880101e61970e1a988d0670c81b", "0x98e6bec0568d3939b31d00eb1040e9b8b2a35db46ddf4369bdaee41bbb63cc84423d29ee510a170fb5b0e2df434ba589", "0x822ff3cd12fbef4f508f3ca813c04a2e0b9b799c99848e5ad3563265979e753ee61a48f6adc2984a850f1b46c1a43d35", "0x891e8b8b92a394f36653d55725ef514bd2e2a46840a0a2975c76c2a935577f85289026aaa74384da0afe26775cbddfb9", "0xb2a3131a5d2fe7c8967047aa66e4524babae941d90552171cc109527f345f42aa0df06dcbb2fa01b33d0043917bbed69", "0x80c869469900431f3eeefafdbe07b8afd8cee7739e659e6d0109b397cacff85a88247698f87dc4e2fe39a592f250ac64", "0x9091594f488b38f9d2bb5df49fd8b4f8829d9c2f11a197dd1431ed5abbc5c954bbde3387088f9ee3a5a834beb7619bce", "0xb472e241e6956146cca57b97a8a204668d050423b4e76f857bad5b47f43b203a04c8391ba9d9c3e95093c071f9d376a1", "0xb7dd2de0284844392f7dfb56fe7ca3ede41e27519753ffc579a0a8d2d65ceb8108d06b6b0d4c3c1a2588951297bd1a1e", "0x902116ce70d0a079ac190321c1f48701318c05f8e69ee09694754885d33a835a849cafe56f499a2f49f6cda413ddf9a7", "0xb18105cc736787fafaf7c3c11c448bce9466e683159dff52723b7951dff429565e466e4841d982e3aaa9ee2066838666", "0x97ab9911f3f659691762d568ae0b7faa1047b0aed1009c319fa79d15d0db8db9f808fc385dc9a68fa388c10224985379", "0xb2a2cba65f5b927e64d2904ba412e2bac1cf18c9c3eda9c72fb70262497ecf505b640827e2afebecf10eebbcf48ccd3e", "0xb36a3fd677baa0d3ef0dac4f1548ff50a1730286b8c99d276a0a45d576e17b39b3cbadd2fe55e003796d370d4be43ce3", "0xa5dfec96ca3c272566e89dc453a458909247e3895d3e44831528130bc47cc9d0a0dac78dd3cad680a4351d399d241967", "0x8029382113909af6340959c3e61db27392531d62d90f92370a432aec3eb1e4c36ae1d4ef2ba8ec6edb4d7320c7a453f6", "0x971d85121ea108e6769d54f9c51299b0381ece8b51d46d49c89f65bedc123bab4d5a8bc14d6f67f4f680077529cbae4c", "0x98ff6afc01d0bec80a278f25912e1b1ebff80117adae72e31d5b9fa4d9624db4ba2065b444df49b489b0607c45e26c4c", "0x8fa29be10fb3ab30ce25920fec0187e6e91e458947009dabb869aade7136c8ba23602682b71e390c251f3743164cbdaa", "0xb3345c89eb1653418fe3940cf3e56a9a9c66526389b98f45ca02dd62bfb37baa69a4baaa7132d7320695f8ea6ad1fd94", "0xb72c7f5541c9ac6b60a7ec9f5415e7fb14da03f7164ea529952a29399f3a071576608dbbcc0d45994f21f92ddbeb1e19", "0xaa3450bb155a5f9043d0ef95f546a2e6ade167280bfb75c9f09c6f9cdb1fffb7ce8181436161a538433afa3681c7a141", "0x92a18fecaded7854b349f441e7102b638ababa75b1b0281dd0bded6541abe7aa37d96693595be0b01fe0a2e2133d50f9", "0x980756ddf9d2253cfe6c94960b516c94889d09e612810935150892627d2ecee9a2517e04968eea295d0106850c04ca44", "0xae68c6ccc454318cdd92f32b11d89116a3b8350207a36d22a0f626718cad671d960090e054c0c77ac3162ae180ecfd4b", "0x99f31f66eaaa551749ad91d48a0d4e3ff4d82ef0e8b28f3184c54e852422ba1bdafd53b1e753f3a070f3b55f3c23b6a2", "0xa44eaeaa6589206069e9c0a45ff9fc51c68da38d4edff1d15529b7932e6f403d12b9387019c44a1488a5d5f27782a51f", "0xb80b5d54d4b344840e45b79e621bd77a3f83fb4ce6d8796b7d6915107b3f3c34d2e7d95bdafd120f285669e5acf2437a", "0xb36c069ec085a612b5908314d6b84c00a83031780261d1c77a0384c406867c9847d5b0845deddfa512cc04a8df2046fb", "0xb09dbe501583220f640d201acea7ee3e39bf9eda8b91aa07b5c50b7641d86d71acb619b38d27835ce97c3759787f08e9", "0x87403d46a2bf63170fff0b857acacf42ee801afe9ccba8e5b4aea967b68eac73a499a65ca46906c2eb4c8f27bc739faa", "0x82b93669f42a0a2aa5e250ffe6097269da06a9c02fcd1801abbad415a7729a64f830754bafc702e64600ba47671c2208", "0x8e3a3029be7edb8dd3ab1f8216664c8dc50d395f603736061d802cef77627db7b859ef287ed850382c13b4d22d6a2d80", "0x968e9ec7194ff424409d182ce0259acd950c384c163c04463bc8700a40b79beba6146d22b7fa7016875a249b7b31c602", "0x8b42c984bbe4996e0c20862059167c6bdc5164b1ffcd928f29512664459212d263e89f0f0e30eed4e672ffa5ed0b01b5", "0x96bac54062110dada905363211133f1f15dc7e4fd80a4c6e4a83bc9a0bcbbaba11cd2c7a13debcf0985e1a954c1da66b", "0xa16dc8a653d67a7cd7ae90b2fffac0bf1ca587005430fe5ba9403edd70ca33e38ba5661d2ed6e9d2864400d997626a62", "0xa68ab11a570a27853c8d67e491591dcba746bfbee08a2e75ae0790399130d027ed387f41ef1d7de8df38b472df309161", "0x92532b74886874447c0300d07eda9bbe4b41ed25349a3da2e072a93fe32c89d280f740d8ff70d5816793d7f2b97373cc", "0x88e35711b471e89218fd5f4d0eadea8a29405af1cd81974427bc4a5fb26ed60798daaf94f726c96e779b403a2cd82820", "0xb5c72aa4147c19f8c4f3a0a62d32315b0f4606e0a7025edc5445571eaf4daff64f4b7a585464821574dd50dbe1b49d08", "0x9305d9b4095258e79744338683fd93f9e657367b3ab32d78080e51d54eec331edbc224fad5093ebf8ee4bd4286757eb8", "0xb2a17abb3f6a05bcb14dc7b98321fa8b46d299626c73d7c6eb12140bf4c3f8e1795250870947af817834f033c88a59d6", "0xb3477004837dbd8ba594e4296f960fc91ab3f13551458445e6c232eb04b326da803c4d93e2e8dcd268b4413305ff84da", "0x924b4b2ebaafdcfdfedb2829a8bf46cd32e1407d8d725a5bd28bdc821f1bafb3614f030ea4352c671076a63494275a3f", "0x8b81b9ef6125c82a9bece6fdcb9888a767ac16e70527753428cc87c56a1236e437da8be4f7ecfe57b9296dc3ae7ba807", "0x906e19ec8b8edd58bdf9ae05610a86e4ea2282b1bbc1e8b00b7021d093194e0837d74cf27ac9916bdb8ec308b00da3da", "0xb41c5185869071760ac786078a57a2ab4e2af60a890037ac0c0c28d6826f15c2cf028fddd42a9b6de632c3d550bfbc14", "0xa646e5dec1b713ae9dfdf7bdc6cd474d5731a320403c7dfcfd666ffc9ae0cff4b5a79530e8df3f4aa9cb80568cb138e9", "0xb0efad22827e562bd3c3e925acbd0d9425d19057868608d78c2209a531cccd0f2c43dc5673acf9822247428ffa2bb821", "0xa94c19468d14b6f99002fc52ac06bbe59e5c472e4a0cdb225144a62f8870b3f10593749df7a2de0bd3c9476ce682e148", "0x803864a91162f0273d49271dafaab632d93d494d1af935aefa522768af058fce52165018512e8d6774976d52bd797e22", "0xa08711c2f7d45c68fb340ac23597332e1bcaec9198f72967b9921204b9d48a7843561ff318f87908c05a44fc35e3cc9d", "0x91c3cad94a11a3197ae4f9461faab91a669e0dddb0371d3cab3ed9aeb1267badc797d8375181130e461eadd05099b2a2", "0x81bdaaf48aae4f7b480fc13f1e7f4dd3023a41439ba231760409ce9292c11128ab2b0bdbbf28b98af4f97b3551f363af", "0x8d60f9df9fd303f625af90e8272c4ecb95bb94e6efc5da17b8ab663ee3b3f673e9f6420d890ccc94acf4d2cae7a860d8", "0xa7b75901520c06e9495ab983f70b61483504c7ff2a0980c51115d11e0744683ce022d76e3e09f4e99e698cbd21432a0d", "0x82956072df0586562fda7e7738226f694e1c73518dd86e0799d2e820d7f79233667192c9236dcb27637e4c65ef19d493", "0xa586beb9b6ffd06ad200957490803a7cd8c9bf76e782734e0f55e04a3dc38949de75dc607822ec405736c576cf83bca3", "0xa179a30d00def9b34a7e85607a447eea0401e32ab5abeee1a281f2acd1cf6ec81a178020666f641d9492b1bdf66f05a3", "0x83e129705c538787ed8e0fdc1275e6466a3f4ee21a1e6abedd239393b1df72244723b92f9d9d9339a0cab6ebf28f5a16", "0x811bd8d1e3722b64cd2f5b431167e7f91456e8bba2cc669d3fbbce7d553e29c3c19f629fcedd2498bc26d33a24891d17", "0xa243c030c858f1f60cccd26b45b024698cc6d9d9e6198c1ed4964a235d9f8d0baf9cde10c8e63dfaa47f8e74e51a6e85", "0xab839eb82e23ca52663281f863b55b0a3d6d4425c33ffb4eeb1d7979488ab068bf99e2a60e82cea4dc42c56c26cbfebe", "0x8b896f9bb21d49343e67aec6ad175b58c0c81a3ca73d44d113ae4354a0065d98eb1a5cafedaf232a2bb9cdc62152f309", "0xaf6230340cc0b66f5bf845540ed4fc3e7d6077f361d60762e488d57834c3e7eb7eacc1b0ed73a7d134f174a01410e50c", "0x88975e1b1af678d1b5179f72300a30900736af580dd748fd9461ef7afccc91ccd9bed33f9da55c8711a7635b800e831f", "0xa97486bb9047391661718a54b8dd5a5e363964e495eae6c692730264478c927cf3e66dd3602413189a3699fbeae26e15", "0xa5973c161ab38732885d1d2785fd74bf156ba34881980cba27fe239caef06b24a533ffe6dbbbeca5e6566682cc00300a", "0xa24776e9a840afda0003fa73b415d5bd6ecd9b5c2cc842b643ee51b8c6087f4eead4d0bfbd987eb174c489a7b952ff2a", "0xa8a6ee06e3af053b705a12b59777267c546f33ba8a0f49493af8e6df4e15cf8dd2d4fb4daf7e84c6b5d3a7363118ff03", "0xa28e59ce6ad02c2ce725067c0123117e12ac5a52c8f5af13eec75f4a9efc4f696777db18a374fa33bcae82e0734ebd16", "0x86dfc3b78e841c708aff677baa8ee654c808e5d257158715097c1025d46ece94993efe12c9d188252ad98a1e0e331fec", "0xa88d0275510f242eab11fdb0410ff6e1b9d7a3cbd3658333539815f1b450a84816e6613d15aa8a8eb15d87cdad4b27a2", "0x8440acea2931118a5b481268ff9f180ee4ede85d14a52c026adc882410825b8275caa44aff0b50c2b88d39f21b1a0696", "0xa7c3182eab25bd6785bacf12079d0afb0a9b165d6ed327814e2177148539f249eb9b5b2554538f54f3c882d37c0a8abe", "0x85291fbe10538d7da38efdd55a7acebf03b1848428a2f664c3ce55367aece60039f4f320b1771c9c89a35941797f717c", "0xa2c6414eeb1234728ab0de94aa98fc06433a58efa646ca3fcbd97dbfb8d98ae59f7ce6d528f669c8149e1e13266f69c9", "0x840c8462785591ee93aee2538d9f1ec44ba2ca61a569ab51d335ac873f5d48099ae8d7a7efa0725d9ff8f9475bfa4f56", "0xa7065a9d02fb3673acf7702a488fbc01aa69580964932f6f40b6c2d1c386b19e50b0e104fcac24ea26c4e723611d0238", "0xb72db6d141267438279e032c95e6106c2ccb3164b842ba857a2018f3a35f4b040da92680881eb17cd61d0920d5b8f006", "0xa8005d6c5960e090374747307ef0be2871a7a43fa4e76a16c35d2baab808e9777b496e9f57a4218b23390887c33a0b55", "0x8e152cea1e00a451ca47c20a1e8875873419700af15a5f38ee2268d3fbc974d4bd5f4be38008fa6f404dbdedd6e6e710", "0xa3391aed1fcd68761f06a7d1008ec62a09b1cb3d0203cd04e300a0c91adfed1812d8bc1e4a3fd7976dc0aae0e99f52f1", "0x967eb57bf2aa503ee0c6e67438098149eac305089c155f1762cf5e84e31f0fbf27c34a9af05621e34645c1ec96afaec8", "0x88af97ddc4937a95ec0dcd25e4173127260f91c8db2f6eac84afb789b363705fb3196235af631c70cafd09411d233589", "0xa32df75b3f2c921b8767638fd289bcfc61e08597170186637a7128ffedd52c798c434485ac2c7de07014f9e895c2c3d8", "0xb0a783832153650aa0d766a3a73ec208b6ce5caeb40b87177ffc035ab03c7705ecdd1090b6456a29f5fb7e90e2fa8930", "0xb59c8e803b4c3486777d15fc2311b97f9ded1602fa570c7b0200bada36a49ee9ef4d4c1474265af8e1c38a93eb66b18b", "0x982f2c85f83e852022998ff91bafbb6ff093ef22cf9d5063e083a48b29175ccbd51b9c6557151409e439096300981a6c", "0x939e3b5989fefebb9d272a954659a4eb125b98c9da6953f5e628d26266bd0525ec38304b8d56f08d65abc4d6da4a8dbb", "0x8898212fe05bc8de7d18503cb84a1c1337cc2c09d1eeef2b475aa79185b7322bf1f8e065f1bf871c0c927dd19faf1f6d", "0x94b0393a41cd00f724aee2d4bc72103d626a5aecb4b5486dd1ef8ac27528398edf56df9db5c3d238d8579af368afeb09", "0x96ac564450d998e7445dd2ea8e3fc7974d575508fa19e1c60c308d83b645864c029f2f6b7396d4ff4c1b24e92e3bac37", "0x8adf6638e18aff3eb3b47617da696eb6c4bdfbecbbc3c45d3d0ab0b12cbad00e462fdfbe0c35780d21aa973fc150285e", "0xb53f94612f818571b5565bbb295e74bada9b5f9794b3b91125915e44d6ddcc4da25510eab718e251a09c99534d6042d9", "0x8b96462508d77ee083c376cd90807aebad8de96bca43983c84a4a6f196d5faf6619a2351f43bfeec101864c3bf255519", "0xaeadf34657083fc71df33bd44af73bf5281c9ca6d906b9c745536e1819ea90b56107c55e2178ebad08f3ba75b3f81c86", "0x9784ba29b2f0057b5af1d3ab2796d439b8753f1f749c73e791037461bdfc3f7097394283105b8ab01788ea5255a96710", "0x8756241bda159d4a33bf74faba0d4594d963c370fb6a18431f279b4a865b070b0547a6d1613cf45b8cfb5f9236bbf831", "0xb03ebfd6b71421dfd49a30460f9f57063eebfe31b9ceaa2a05c37c61522b35bdc09d7db3ad75c76c253c00ba282d3cd2", "0xb34e7e6341fa9d854b2d3153bdda0c4ae2b2f442ab7af6f99a0975d45725aa48e36ae5f7011edd249862e91f499687d4", "0xb462ee09dc3963a14354244313e3444de5cc37ea5ccfbf14cd9aca8027b59c4cb2a949bc30474497cab8123e768460e6", "0xaea753290e51e2f6a21a9a0ee67d3a2713f95c2a5c17fe41116c87d3aa77b1683761264d704df1ac34f8b873bc88ef7b", "0x98430592afd414394f98ddfff9f280fcb1c322dbe3510f45e1e9c4bb8ee306b3e0cf0282c0ee73ebb8ba087d4d9e0858", "0xb95d3b5aaf54ffca11f4be8d57f76e14afdb20afc859dc7c7471e0b42031e8f3d461b726ecb979bdb2f353498dfe95ea", "0x984d17f9b11a683132e0b5a9ee5945e3ff7054c2d5c716be73b29078db1d36f54c6e652fd2f52a19da313112e97ade07", "0xab232f756b3fff3262be418a1af61a7e0c95ceebbc775389622a8e10610508cd6784ab7960441917a83cc191c58829ea", "0xa28f41678d6e60de76b0e36ab10e4516e53e02e9c77d2b5af3cfeee3ce94cfa30c5797bd1daab20c98e1cad83ad0f633", "0xb55395fca84dd3ccc05dd480cb9b430bf8631ff06e24cb51d54519703d667268c2f8afcde4ba4ed16bece8cc7bc8c6e0", "0x8a8a5392a0e2ea3c7a8c51328fab11156004e84a9c63483b64e8f8ebf18a58b6ffa8fe8b9d95af0a2f655f601d096396", "0xab480000fe194d23f08a7a9ec1c392334e9c687e06851f083845121ce502c06b54dda8c43092bcc1035df45cc752fe9b", "0xb265644c29f628d1c7e8e25a5e845cabb21799371814730a41a363e1bda8a7be50fee7c3996a365b7fcba4642add10db", "0xb8a915a3c685c2d4728f6931c4d29487cad764c5ce23c25e64b1a3259ac27235e41b23bfe7ae982921b4cb84463097df", "0x8efa7338442a4b6318145a5440fc213b97869647eeae41b9aa3c0a27ee51285b73e3ae3b4a9423df255e6add58864aa9", "0x9106d65444f74d217f4187dfc8fcf3810b916d1e4275f94f6a86d1c4f3565b131fd6cde1fa708bc05fe183c49f14941a", "0x948252dac8026bbbdb0a06b3c9d66ec4cf9532163bab68076fda1bd2357b69e4b514729c15aaa83b5618b1977bbc60c4", "0xae6596ccfdf5cbbc5782efe3bb0b101bb132dbe1d568854ca24cacc0b2e0e9fabcb2ca7ab42aecec412efd15cf8cb7a2", "0x84a0b6c198ff64fd7958dfd1b40eac9638e8e0b2c4cd8cf5d8cdf80419baee76a05184bce6c5b635f6bf2d30055476a7", "0x8893118be4a055c2b3da593dbca51b1ae2ea2469911acfb27ee42faf3e6c3ad0693d3914c508c0b05b36a88c8b312b76", "0xb097479e967504deb6734785db7e60d1d8034d6ca5ba9552887e937f5e17bb413fccac2c1d1082154ed76609127860ad", "0xa0294e6b9958f244d29943debf24b00b538b3da1116269b6e452bb12dc742226712fd1a15b9c88195afeb5d2415f505c", "0xb3cc15f635080bc038f61b615f62b5b5c6f2870586191f59476e8368a73641d6ac2f7d0c1f54621982defdb318020230", "0x99856f49b9fe1604d917c94d09cc0ed753d13d015d30587a94e6631ffd964b214e607deb8a69a8b5e349a7edf4309206", "0xa8571e113ea22b4b4fce41a094da8c70de37830ae32e62c65c2fa5ad06a9bc29e884b945e73d448c72b176d6ecebfb58", "0xa9e9c6e52beb0013273c29844956b3ce291023678107cdc785f7b44eff5003462841ad8780761b86aefc6b734adde7cf", "0x80a784b0b27edb51ef2bad3aee80e51778dcaa0f3f5d3dcb5dc5d4f4b2cf7ae35b08de6680ea9dac53f8438b92eb09ef", "0x827b543e609ea328e97e373f70ad72d4915a2d1daae0c60d44ac637231070e164c43a2a58db80a64df1c624a042b38f9", "0xb449c65e8195202efdcb9bdb4e869a437313b118fef8b510cbbf8b79a4e99376adb749b37e9c20b51b31ed3310169e27", "0x8ea3028f4548a79a94c717e1ed28ad4d8725b8d6ab18b021063ce46f665c79da3c49440c6577319dab2d036b7e08f387", "0x897798431cfb17fe39f08f5f854005dc37b1c1ec1edba6c24bc8acb3b88838d0534a75475325a5ea98b326ad47dbad75", "0x89cf232e6303b0751561960fd4dea5754a28c594daf930326b4541274ffb03c7dd75938e411eb9a375006a70ce38097f", "0x9727c6ae7f0840f0b6c8bfb3a1a5582ceee705e0b5c59b97def7a7a2283edd4d3f47b7971e902a3a2079e40b53ff69b8", "0xb76ed72b122c48679d221072efc0eeea063cb205cbf5f9ef0101fd10cb1075b8628166c83577cced654e1c001c7882f7", "0xae908c42d208759da5ee9b405df85a6532ea35c6f0f6a1288d22870f59d98edc896841b8ac890a538e6c8d1e8b02d359", "0x809d12fe4039a0ec80dc9be6a89acaab7797e5f7f9b163378f52f9a75a1d73b2e9ae6e3dd49e32ced439783c1cabbef5", "0xa4149530b7f85d1098ba534d69548c6c612c416e8d35992fc1f64f4deeb41e09e49c6cf7aadbed7e846b91299358fe2d", "0xa49342eacd1ec1148b8df1e253b1c015f603c39de11fa0a364ccb86ea32d69c34fd7aa6980a1fadcd8e785a57fa46f60", "0x87d43eff5a006dc4dddcf76cc96c656a1f3a68f19f124181feab86c6cc9a52cb9189cdbb423414defdd9bb0ca8ff1ddc", "0x861367e87a9aa2f0f68296ba50aa5dbc5713008d260cc2c7e62d407c2063064749324c4e8156dc21b749656cfebce26b", "0xb5303c2f72e84e170e66ae1b0fbd51b8c7a6f27476eaf5694b64e8737d5c84b51fe90100b256465a4c4156dd873cddb0", "0xb62849a4f891415d74f434cdc1d23c4a69074487659ca96e1762466b2b7a5d8525b056b891d0feea6fe6845cba8bc7fb", "0x923dd9e0d6590a9307e8c4c23f13bae3306b580e297a937711a8b13e8de85e41a61462f25b7d352b682e8437bf2b4ab3", "0x9147379860cd713cd46c94b8cdf75125d36c37517fbecf81ace9680b98ce6291cd1c3e472f84249cc3b2b445e314b1b6", "0xa808a4f17ac21e3fb5cfef404e61fae3693ca3e688d375f99b6116779696059a146c27b06de3ac36da349b0649befd56", "0x87787e9322e1b75e66c1f0d9ea0915722a232770930c2d2a95e9478c4b950d15ab767e30cea128f9ed65893bfc2d0743", "0x9036a6ee2577223be105defe1081c48ea7319e112fff9110eb9f61110c319da25a6cea0464ce65e858635b079691ef1f", "0xaf5548c7c24e1088c23b57ee14d26c12a83484c9fd9296edf1012d8dcf88243f20039b43c8c548c265ef9a1ffe9c1c88", "0xa0fff520045e14065965fb8accd17e878d3fcaf9e0af2962c8954e50be6683d31fa0bf4816ab68f08630dbac6bfce52a", "0xb4c1b249e079f6ae1781af1d97a60b15855f49864c50496c09c91fe1946266915b799f0406084d7783f5b1039116dd8b", "0x8b0ffa5e7c498cb3879dddca34743b41eee8e2dea3d4317a6e961b58adb699ef0c92400c068d5228881a2b08121226bf", "0x852ae8b19a1d80aa8ae5382e7ee5c8e7670ceb16640871c56b20b96b66b3b60e00015a3dde039446972e57b49a999ddd", "0xa49942f04234a7d8492169da232cfff8051df86e8e1ba3db46aede02422c689c87dc1d99699c25f96cb763f5ca0983e5", "0xb04b597b7760cf5dcf411ef896d1661e6d5b0db3257ac2cf64b20b60c6cc18fa10523bb958a48d010b55bac7b02ab3b1", "0xa494591b51ea8285daecc194b5e5bd45ae35767d0246ac94fae204d674ee180c8e97ff15f71f28b7aeb175b8aea59710", "0x97d2624919e78406e7460730680dea8e71c8571cf988e11441aeea54512b95bd820e78562c99372d535d96f7e200d20d", "0xac693ddb00e48f76e667243b9b6a7008424043fb779e4f2252330285232c3fccac4da25cbd6d95fe9ad959ff305a91f6", "0x8d20ca0a71a64a3f702a0825bb46bd810d03bebfb227683680d474a52f965716ff99e19a165ebaf6567987f4f9ee3c94", "0xa5c516a438f916d1d68ca76996404792e0a66e97b7f18fc54c917bf10cf3211b62387932756e39e67e47b0bd6e88385a", "0xb089614d830abc0afa435034cec7f851f2f095d479cacf1a3fb57272da826c499a52e7dcbc0eb85f4166fb94778e18e9", "0xa8dacc943765d930848288192f4c69e2461c4b9bc6e79e30eeef9a543318cf9ae9569d6986c65c5668a89d49993f8e07", "0xab5a9361fa339eec8c621bdad0a58078983abd8942d4282b22835d7a3a47e132d42414b7c359694986f7db39386c2e19", "0x94230517fb57bd8eb26c6f64129b8b2abd0282323bf7b94b8bac7fab27b4ecc2c4290c294275e1a759de19f2216134f3", "0xb8f158ea5006bc3b90b285246625faaa6ac9b5f5030dc69701b12f3b79a53ec7e92eeb5a63bbd1f9509a0a3469ff3ffc", "0x8b6944fd8cb8540957a91a142fdcda827762aa777a31e8810ca6d026e50370ee1636fc351724767e817ca38804ebe005", "0x82d1ee40fe1569c29644f79fa6c4033b7ed45cd2c3b343881f6eb0de2e79548fded4787fae19bed6ee76ed76ff9f2f11", "0xa8924c7035e99eaed244ca165607e7e568b6c8085510dcdbaf6ebdbed405af2e6c14ee27d94ffef10d30aa52a60bf66d", "0x956f82a6c2ae044635e85812581e4866c5fa2f427b01942047d81f6d79a14192f66fbbe77c9ffeaef4e6147097fdd2b5", "0xb1100255a1bcf5e05b6aff1dfeb6e1d55b5d68d43a7457ba10cc76b61885f67f4d0d5179abda786e037ae95deb8eea45", "0x99510799025e3e5e8fbf06dedb14c060c6548ba2bda824f687d3999dc395e794b1fb6514b9013f3892b6cf65cb0d65aa", "0x8f9091cebf5e9c809aab415942172258f894e66e625d7388a05289183f01b8d994d52e05a8e69f784fba41db9ea357f0", "0xa13d2eeb0776bdee9820ecb6693536720232848c51936bb4ef4fe65588d3f920d08a21907e1fdb881c1ad70b3725e726", "0xa68b8f18922d550284c5e5dc2dda771f24c21965a6a4d5e7a71678178f46df4d8a421497aad8fcb4c7e241aba26378a0", "0x8b7601f0a3c6ad27f03f2d23e785c81c1460d60100f91ea9d1cab978aa03b523150206c6d52ce7c7769c71d2c8228e9e", "0xa8e02926430813caa851bb2b46de7f0420f0a64eb5f6b805401c11c9091d3b6d67d841b5674fa2b1dce0867714124cd8", "0xb7968ecba568b8193b3058400af02c183f0a6df995a744450b3f7e0af7a772454677c3857f99c140bbdb2a09e832e8e0", "0x8f20b1e9ba87d0a3f35309b985f3c18d2e8800f1ca7f0c52cadef773f1496b6070c936eea48c4a1cae83fd2524e9d233", "0x88aef260042db0d641a51f40639dbeeefa9e9811df30bee695f3791f88a2f84d318f04e8926b7f47bf25956cb9e3754f", "0x9725345893b647e9ba4e6a29e12f96751f1ae25fcaec2173e9a259921a1a7edb7a47159b3c8767e44d9e2689f5aa0f72", "0x8c281e6f72752cb11e239e4df9341c45106eb7993c160e54423c2bffe10bc39d42624b45a1f673936ef2e1a02fc92f1a", "0x90aba2f68bddb2fcce6c51430dacdfeec43ea8dc379660c99095df11017691ccf5faa27665cf4b9f0eea7728ae53c327", "0xb7022695c16521c5704f49b7ddbdbec9b5f57ce0ceebe537bc0ebb0906d8196cc855a9afeb8950a1710f6a654464d93f", "0x8fe1b9dd3c6a258116415d36e08374e094b22f0afb104385a5da48be17123e86fb8327baacc4f0d9ebae923d55d99bb5", "0x817e85d8e3d19a4cbc1dec31597142c2daa4871bda89c2177fa719c00eda3344eb08b82eb92d4aa91a9eaacb3fc09783", "0xb59053e1081d2603f1ca0ba553804d6fa696e1fd996631db8f62087b26a40dfef02098b0326bb75f99ec83b9267ca738", "0x990a173d857d3ba81ff3789b931bfc9f5609cde0169b7f055fa3cb56451748d593d62d46ba33f80f9cafffe02b68dd14", "0xb0c538dbba4954b809ab26f9f94a3cf1dcb77ce289eaec1d19f556c0ae4be1fa03af4a9b7057837541c3cc0a80538736", "0xac3ba42f5f44f9e1fc453ce49c4ab79d0e1d5c42d3b30b1e098f3ab3f414c4c262fa12fb2be249f52d4aaf3c5224beb9", "0xaf47467eb152e59870e21f0d4da2f43e093daf40180ab01438030684b114d025326928eaab12c41b81a066d94fce8436", "0x98d1b58ba22e7289b1c45c79a24624f19b1d89e00f778eef327ec4856a9a897278e6f1a9a7e673844b31dde949153000", "0x97ccb15dfadc7c59dca08cfe0d22df2e52c684cf97de1d94bc00d7ba24e020025130b0a39c0f4d46e4fc872771ee7875", "0xb699e4ed9a000ff96ca296b2f09dce278832bc8ac96851ff3cff99ed3f6f752cfc0fea8571be28cd9b5a7ec36f1a08ee", "0xb9f49f0edb7941cc296435ff0a912e3ad16848ee8765ab5f60a050b280d6ea585e5b34051b15f6b8934ef01ceb85f648", "0xac3893df7b4ceab23c6b9054e48e8ba40d6e5beda8fbe90b814f992f52494186969b35d8c4cdc3c99890a222c9c09008", "0xa41293ad22fae81dea94467bc1488c3707f3d4765059173980be93995fa4fcc3c9340796e3eed0beeb0ba0d9bb4fa3aa", "0xa0543e77acd2aeecde13d18d258aeb2c7397b77f17c35a1992e8666ea7abcd8a38ec6c2741bd929abba2f766138618cc", "0x92e79b22bc40e69f6527c969500ca543899105837b6b1075fa1796755c723462059b3d1b028e0b3df2559fa440e09175", "0xa1fa1eac8f41a5197a6fb4aa1eae1a031c89f9c13ff9448338b222780cf9022e0b0925d930c37501a0ef7b2b00fdaf83", "0xb3cb29ff73229f0637335f28a08ad8c5f166066f27c6c175164d0f26766a927f843b987ee9b309ed71cbf0a65d483831", "0x84d4ab787f0ac00f104f4a734dc693d62d48c2aeb03913153da62c2ae2c27d11b1110dcef8980368dd84682ea2c1a308", "0xab6a8e4bbc78d4a7b291ad3e9a8fe2d65f640524ba3181123b09d2d18a9e300e2509ccf7000fe47e75b65f3e992a2e7e", "0xb7805ebe4f1a4df414003dc10bca805f2ab86ca75820012653e8f9b79c405196b0e2cab099f2ab953d67f0d60d31a0f9", "0xb12c582454148338ea605d22bd00a754109063e22617f1f8ac8ddf5502c22a181c50c216c3617b9852aa5f26af56b323", "0x86333ad9f898947e31ce747728dc8c887479e18d36ff3013f69ebef807d82c6981543b5c3788af93c4d912ba084d3cba", "0xb514efa310dc4ad1258add138891e540d8c87142a881b5f46563cc58ecd1488e6d3a2fca54c0b72a929f3364ca8c333e", "0xaa0a30f92843cf2f484066a783a1d75a7aa6f41f00b421d4baf20a6ac7886c468d0eea7ca8b17dd22f4f74631b62b640", "0xb3b7dc63baec9a752e8433c0cdee4d0f9bc41f66f2b8d132faf925eef9cf89aae756fc132c45910f057122462605dc10", "0xb9b8190dac5bfdeb59fd44f4da41a57e7f1e7d2c21faba9da91fa45cbeca06dcf299c9ae22f0c89ece11ac46352d619f", "0x89f8cf36501ad8bdfeab863752a9090e3bfda57cf8fdeca2944864dc05925f501e252c048221bcc57136ab09a64b64b2", "0xb0cbfaf317f05f97be47fc9d69eda2dd82500e00d42612f271a1fe24626408c28881f171e855bd5bd67409f9847502b4", "0xa7c21a8fcede581bfd9847b6835eda62ba250bea81f1bb17372c800a19c732abe03064e64a2f865d974fb636cab4b859", "0x95f9df524ba7a4667351696c4176b505d8ea3659f5ff2701173064acc624af69a0fad4970963736383b979830cb32260", "0x856a74fe8b37a2e3afeac858c8632200485d438422a16ae3b29f359e470e8244995c63ad79c7e007ed063f178d0306fd", "0xb37faa4d78fdc0bb9d403674dbea0176c2014a171c7be8527b54f7d1a32a76883d3422a3e7a5f5fcc5e9b31b57822eeb", "0x8d37234d8594ec3fe75670b5c9cc1ec3537564d4739b2682a75b18b08401869a4264c0f264354219d8d896cded715db4", "0xb5289ee5737f0e0bde485d32096d23387d68dab8f01f47821ab4f06cc79a967afe7355e72dc0c751d96b2747b26f6255", "0x9085e1fdf9f813e9c3b8232d3c8863cd84ab30d45e8e0d3d6a0abd9ebc6fd70cdf749ff4d04390000e14c7d8c6655fc7", "0x93a388c83630331eca4da37ea4a97b3b453238af474817cc0a0727fd3138dcb4a22de38c04783ec829c22cb459cb4e8e", "0xa5377116027c5d061dbe24c240b891c08cdd8cd3f0899e848d682c873aff5b8132c1e7cfe76d2e5ed97ee0eb1d42cb68", "0xa274c84b04338ed28d74683e2a7519c2591a3ce37c294d6f6e678f7d628be2db8eff253ede21823e2df7183e6552f622", "0x8bc201147a842453a50bec3ac97671397bc086d6dfc9377fa38c2124cdc286abda69b7324f47d64da094ae011d98d9d9", "0x9842d0c066c524592b76fbec5132bc628e5e1d21c424bec4555efca8619cc1fd8ea3161febcb8b9e8ab54702f4e815e2", "0xa19191b713a07efe85c266f839d14e25660ee74452e6c691cd9997d85ae4f732052d802d3deb018bdd847caa298a894b", "0xa24f71fc0db504da4e287dd118a4a74301cbcd16033937ba2abc8417956fcb4ae19b8e63b931795544a978137eff51cb", "0xa90eec4a6a3a4b8f9a5b93d978b5026fcf812fe65585b008d7e08c4aaf21195a1d0699f12fc16f79b6a18a369af45771", "0x8b551cf89737d7d06d9b3b9c4c1c73b41f2ea0af4540999c70b82dabff8580797cf0a3caf34c86c59a7069eb2e38f087", "0xb8d312e6c635e7a216a1cda075ae77ba3e1d2fd501dc31e83496e6e81ed5d9c7799f8e578869c2e0e256fb29f5de10a7", "0x8d144bdb8cae0b2cdb5b33d44bbc96984a5925202506a8cc65eb67ac904b466f5a7fe3e1cbf04aa785bbb7348c4bb73c", "0xa101b3d58b7a98659244b88de0b478b3fb87dc5fc6031f6e689b99edf498abd43e151fd32bd4bbd240e0b3e59c440359", "0x907453abca7d8e7151a05cc3d506c988007692fe7401395dc93177d0d07d114ab6cca0cc658eb94c0223fe8658295cad", "0x825329ffbe2147ddb68f63a0a67f32d7f309657b8e5d9ab5bb34b3730bfa2c77a23eaaadb05def7d9f94a9e08fdc1e96", "0x88ee923c95c1dac99ae7ed6067906d734d793c5dc5d26339c1bb3314abe201c5dccb33b9007351885eb2754e9a8ea06c", "0x98bc9798543f5f1adc9f2cfcfa72331989420e9c3f6598c45269f0dc9b7c8607bbeaf03faa0aea2ddde2b8f17fdceff5", "0x8ee87877702a79aef923ab970db6fa81561b3c07d5bf1a072af0a7bad765b4cbaec910afe1a91703feacc7822fa38a94", "0x8060b9584aa294fe8adc2b22f67e988bc6da768eae91e429dcc43ddc53cfcc5d6753fdc1b420b268c7eb2fb50736a970", "0xb344a5524d80a2f051870c7001f74fcf348a70fcf78dbd20c6ff9ca85d81567d2318c8b8089f2c4f195d6aec9fc15fa6", "0x8f5a5d893e1936ed062149d20eb73d98b62b7f50ab5d93a6429c03656b36688d1c80cb5010e4977491e51fa0d7dd35d5", "0x86fa32ebbf97328c5f5f15564e1238297e289ec3219b9a741724e9f3ae8d5c15277008f555863a478b247ba5dc601d44", "0x9557e55377e279f4b6b5e0ffe01eca037cc13aac242d67dfcd0374a1e775c5ed5cb30c25fe21143fee54e3302d34a3ea", "0x8cb6bcbc39372d23464a416ea7039f57ba8413cf3f00d9a7a5b356ab20dcb8ed11b3561f7bce372b8534d2870c7ee270", "0xb5d59075cb5abde5391f64b6c3b8b50adc6e1f654e2a580b6d6d6eff3f4fbdd8fffc92e06809c393f5c8eab37f774c4b", "0xafcfb6903ef13e493a1f7308675582f15af0403b6553e8c37afb8b2808ad21b88b347dc139464367dc260df075fea1ad", "0x810fbbe808375735dd22d5bc7fc3828dc49fdd22cc2d7661604e7ac9c4535c1df578780affb3b895a0831640a945bcad", "0x8056b0c678803b416f924e09a6299a33cf9ad7da6fe1ad7accefe95c179e0077da36815fde3716711c394e2c5ea7127f", "0x8b67403702d06979be19f1d6dc3ec73cc2e81254d6b7d0cc49cd4fdda8cd51ab0835c1d2d26fc0ecab5df90585c2f351", "0x87f97f9e6d4be07e8db250e5dd2bffdf1390665bc5709f2b631a6fa69a7fca958f19bd7cc617183da1f50ee63e9352b5", "0xae151310985940471e6803fcf37600d7fa98830613e381e00dab943aec32c14162d51c4598e8847148148000d6e5af5c", "0x81eb537b35b7602c45441cfc61b27fa9a30d3998fad35a064e05bc9479e9f10b62eba2b234b348219eea3cadcaac64bb", "0x8a441434934180ab6f5bc541f86ebd06eadbee01f438836d797e930fa803a51510e005c9248cecc231a775b74d12b5e9", "0x81f3c250a27ba14d8496a5092b145629eb2c2e6a5298438670375363f57e2798207832c8027c3e9238ad94ecdadfc4df", "0xa6217c311f2f3db02ceaa5b6096849fe92b6f4b6f1491535ef8525f6ccee6130bed2809e625073ecbaddd4a3eb3df186", "0x82d1c396f0388b942cf22b119d7ef1ad03d3dad49a74d9d01649ee284f377c8daddd095d596871669e16160299a210db", "0xa40ddf7043c5d72a7246bd727b07f7fff1549f0e443d611de6f9976c37448b21664c5089c57f20105102d935ab82f27b", "0xb6c03c1c97adf0c4bf4447ec71366c6c1bff401ba46236cd4a33d39291e7a1f0bb34bd078ba3a18d15c98993b153a279", "0x8a94f5f632068399c359c4b3a3653cb6df2b207379b3d0cdace51afdf70d6d5cce6b89a2b0fee66744eba86c98fb21c2", "0xb2f19e78ee85073f680c3bba1f07fd31b057c00b97040357d97855b54a0b5accb0d3b05b2a294568fcd6a4be6f266950", "0xa74632d13bbe2d64b51d7a9c3ae0a5a971c19f51cf7596a807cea053e6a0f3719700976d4e394b356c0329a2dced9aa2", "0xafef616d341a9bc94393b8dfba68ff0581436aa3a3adb7c26a1bbf2cf19fa877066191681f71f17f3cd6f9cf6bf70b5a", "0x8ce96d93ae217408acf7eb0f9cbb9563363e5c7002e19bbe1e80760bc9d449daee2118f3878b955163ed664516b97294", "0x8414f79b496176bc8b8e25f8e4cfee28f4f1c2ddab099d63d2aca1b6403d26a571152fc3edb97794767a7c4686ad557c", "0xb6c61d01fd8ce087ef9f079bf25bf10090db483dd4f88c4a786d31c1bdf52065651c1f5523f20c21e75cea17df69ab73", "0xa5790fd629be70545093631efadddc136661f63b65ec682609c38ef7d3d7fa4e56bdf94f06e263bc055b90cb1c6bcefe", "0xb515a767e95704fb7597bca9e46f1753abacdc0e56e867ee3c6f4cd382643c2a28e65312c05ad040eaa3a8cbe7217a65", "0x8135806a02ead6aa92e9adb6fefb91349837ab73105aaa7be488ef966aa8dfaafdfa64bbae30fcbfa55dd135a036a863", "0x8f22435702716d76b1369750694540742d909d5e72b54d0878245fab7c269953b1c6f2b29c66f08d5e0263ca3a731771", "0x8e0f8a8e8753e077dac95848212aeffd51c23d9b6d611df8b102f654089401954413ecbedc6367561ca599512ae5dda7", "0x815a9084e3e2345f24c5fa559deec21ee1352fb60f4025c0779be65057f2d528a3d91593bd30d3a185f5ec53a9950676", "0x967e6555ccba395b2cc1605f8484c5112c7b263f41ce8439a99fd1c71c5ed14ad02684d6f636364199ca48afbbde13be", "0x8cd0ccf17682950b34c796a41e2ea7dd5367aba5e80a907e01f4cdc611e4a411918215e5aebf4292f8b24765d73314a6", "0xa58bf1bbb377e4b3915df6f058a0f53b8fb8130fdec8c391f6bc82065694d0be59bb67ffb540e6c42cc8b380c6e36359", "0x92af3151d9e6bfb3383d85433e953c0160859f759b0988431ec5893542ba40288f65db43c78a904325ef8d324988f09d", "0x8011bbb05705167afb47d4425065630f54cb86cd462095e83b81dfebf348f846e4d8fbcf1c13208f5de1931f81da40b9", "0x81c743c104fc3cb047885c9fa0fb9705c3a83ee24f690f539f4985509c3dafd507af3f6a2128276f45d5939ef70c167f", "0xa2c9679b151c041aaf5efeac5a737a8f70d1631d931609fca16be1905682f35e291292874cb3b03f14994f98573c6f44", "0xa4949b86c4e5b1d5c82a337e5ce6b2718b1f7c215148c8bfb7e7c44ec86c5c9476048fc5c01f57cb0920876478c41ad6", "0x86c2495088bd1772152e527a1da0ef473f924ea9ab0e5b8077df859c28078f73c4e22e3a906b507fdf217c3c80808b5c", "0x892e0a910dcf162bcea379763c3e2349349e4cda9402949255ac4a78dd5a47e0bf42f5bd0913951576b1d206dc1e536a", "0xa7009b2c6b396138afe4754b7cc10dee557c51c7f1a357a11486b3253818531f781ea8107360c8d4c3b1cd96282353c0", "0x911763ef439c086065cc7b4e57484ed6d693ea44acee4b18c9fd998116da55fbe7dcb8d2a0f0f9b32132fca82d73dff6", "0xa722000b95a4a2d40bed81870793f15ba2af633f9892df507f2842e52452e02b5ea8dea6a043c2b2611d82376e33742a", "0x9387ac49477bd719c2f92240d0bdfcf9767aad247ca93dc51e56106463206bc343a8ec855eb803471629a66fffb565d6", "0x92819a1fa48ab4902939bb72a0a4e6143c058ea42b42f9bc6cea5df45f49724e2530daf3fc4f097cceefa2a8b9db0076", "0x98eac7b04537653bc0f4941aae732e4b1f84bd276c992c64a219b8715eb1fb829b5cbd997d57feb15c7694c468f95f70", "0xb275e7ba848ce21bf7996e12dbeb8dadb5d0e4f1cb5a0248a4f8f9c9fe6c74e3c93f4b61edbcb0a51af5a141e1c14bc7", "0x97243189285aba4d49c53770c242f2faf5fd3914451da4931472e3290164f7663c726cf86020f8f181e568c72fd172d1", "0x839b0b3c25dd412bee3dc24653b873cc65454f8f16186bb707bcd58259c0b6765fa4c195403209179192a4455c95f3b8", "0x8689d1a870514568a074a38232e2ceb4d7df30fabeb76cff0aed5b42bf7f02baea12c5fadf69f4713464dbd52aafa55f", "0x8958ae7b290f0b00d17c3e9fdb4dbf168432b457c7676829299dd428984aba892de1966fc106cfc58a772862ecce3976", "0xa422bc6bd68b8870cfa5bc4ce71781fd7f4368b564d7f1e0917f6013c8bbb5b240a257f89ecfdbecb40fe0f3aa31d310", "0xaa61f78130cebe09bc9a2c0a37f0dd57ed2d702962e37d38b1df7f17dc554b1d4b7a39a44182a452ce4c5eb31fa4cfcc", "0xb7918bd114f37869bf1a459023386825821bfadce545201929d13ac3256d92a431e34f690a55d944f77d0b652cefeffc", "0x819bba35fb6ace1510920d4dcff30aa682a3c9af9022e287751a6a6649b00c5402f14b6309f0aeef8fce312a0402915e", "0x8b7c9ad446c6f63c11e1c24e24014bd570862b65d53684e107ba9ad381e81a2eaa96731b4b33536efd55e0f055071274", "0x8fe79b53f06d33386c0ec7d6d521183c13199498594a46d44a8a716932c3ec480c60be398650bbfa044fa791c4e99b65", "0x9558e10fb81250b9844c99648cf38fa05ec1e65d0ccbb18aa17f2d1f503144baf59d802c25be8cc0879fff82ed5034ad", "0xb538a7b97fbd702ba84645ca0a63725be1e2891c784b1d599e54e3480e4670d0025526674ef5cf2f87dddf2290ba09f0", "0x92eafe2e869a3dd8519bbbceb630585c6eb21712b2f31e1b63067c0acb5f9bdbbcbdb612db4ea7f9cc4e7be83d31973f", "0xb40d21390bb813ab7b70a010dff64c57178418c62685761784e37d327ba3cb9ef62df87ecb84277c325a637fe3709732", "0xb349e6fbf778c4af35fbed33130bd8a7216ed3ba0a79163ebb556e8eb8e1a7dad3456ddd700dad9d08d202491c51b939", "0xa8fdaedecb251f892b66c669e34137f2650509ade5d38fbe8a05d9b9184bb3b2d416186a3640429bd1f3e4b903c159dd", "0xac6167ebfee1dbab338eff7642f5e785fc21ef0b4ddd6660333fe398068cbd6c42585f62e81e4edbb72161ce852a1a4f", "0x874b1fbf2ebe140c683bd7e4e0ab017afa5d4ad38055aaa83ee6bbef77dbc88a6ce8eb0dcc48f0155244af6f86f34c2d", "0x903c58e57ddd9c446afab8256a6bb6c911121e6ccfb4f9b4ed3e2ed922a0e500a5cb7fa379d5285bc16e11dac90d1fda", "0x8dae7a0cffa2fd166859cd1bf10ff82dd1932e488af377366b7efc0d5dec85f85fe5e8150ff86a79a39cefc29631733a", "0xaa047857a47cc4dfc08585f28640420fcf105b881fd59a6cf7890a36516af0644d143b73f3515ab48faaa621168f8c31", "0x864508f7077c266cc0cb3f7f001cb6e27125ebfe79ab57a123a8195f2e27d3799ff98413e8483c533b46a816a3557f1f", "0x8bcd45ab1f9cbab36937a27e724af819838f66dfeb15923f8113654ff877bd8667c54f6307aaf0c35027ca11b6229bfd", "0xb21aa34da9ab0a48fcfdd291df224697ce0c1ebc0e9b022fdee8750a1a4b5ba421c419541ed5c98b461eecf363047471", "0xa9a18a2ab2fae14542dc336269fe612e9c1af6cf0c9ac933679a2f2cb77d3c304114f4d219ca66fe288adde30716775b", "0xb5205989b92c58bdda71817f9a897e84100b5c4e708de1fced5c286f7a6f01ae96b1c8d845f3a320d77c8e2703c0e8b1", "0xa364059412bbcc17b8907d43ac8e5df90bc87fd1724b5f99832d0d24559fae6fa76a74cff1d1eac8cbac6ec80b44af20", "0xae709f2c339886b31450834cf29a38b26eb3b0779bd77c9ac269a8a925d1d78ea3837876c654b61a8fe834b3b6940808", "0x8802581bba66e1952ac4dab36af371f66778958f4612901d95e5cac17f59165e6064371d02de8fb6fccf89c6dc8bd118", "0xa313252df653e29c672cbcfd2d4f775089cb77be1077381cf4dc9533790e88af6cedc8a119158e7da5bf6806ad9b91a1", "0x992a065b4152c7ef11515cd54ba9d191fda44032a01aed954acff3443377ee16680c7248d530b746b8c6dee2d634e68c", "0xb627b683ee2b32c1ab4ccd27b9f6cce2fe097d96386fa0e5c182ad997c4c422ab8dfc03870cd830b8c774feb66537282", "0xb823cf8a9aee03dadd013eb9efe40a201b4b57ef67efaae9f99683005f5d1bf55e950bf4af0774f50859d743642d3fea", "0xb8a7449ffac0a3f206677097baf7ce00ca07a4d2bd9b5356fbcb83f3649b0fda07cfebad220c1066afba89e5a52abf4b", "0xb2dd1a2f986395bb4e3e960fbbe823dbb154f823284ebc9068502c19a7609790ec0073d08bfa63f71e30c7161b6ef966", "0x98e5236de4281245234f5d40a25b503505af140b503a035fc25a26159a9074ec81512b28f324c56ea2c9a5aa7ce90805", "0x89070847dc8bbf5bc4ed073aa2e2a1f699cf0c2ca226f185a0671cecc54e7d3e14cd475c7752314a7a8e7476829da4bc", "0xa9402dc9117fdb39c4734c0688254f23aed3dce94f5f53f5b7ef2b4bf1b71a67f85ab1a38ec224a59691f3bee050aeb3", "0x957288f9866a4bf56a4204218ccc583f717d7ce45c01ea27142a7e245ad04a07f289cc044f8cf1f21d35e67e39299e9c", "0xb2fb31ccb4e69113763d7247d0fc8edaae69b550c5c56aecacfd780c7217dc672f9fb7496edf4aba65dacf3361268e5b", "0xb44a4526b2f1d6eb2aa8dba23bfa385ff7634572ab2afddd0546c3beb630fbfe85a32f42dd287a7fec069041411537f7", "0x8db5a6660c3ac7fd7a093573940f068ee79a82bc17312af900b51c8c439336bc86ca646c6b7ab13aaaa008a24ca508ab", "0x8f9899a6d7e8eb4367beb5c060a1f8e94d8a21099033ae582118477265155ba9e72176a67f7f25d7bad75a152b56e21a", "0xa67de0e91ade8d69a0e00c9ff33ee2909b8a609357095fa12319e6158570c232e5b6f4647522efb7345ce0052aa9d489", "0x82eb2414898e9c3023d57907a2b17de8e7eea5269029d05a94bfd7bf5685ac4a799110fbb375eb5e0e2bd16acf6458ae", "0x94451fc7fea3c5a89ba701004a9693bab555cb622caf0896b678faba040409fdfd14a978979038b2a81e8f0abc4994d2", "0xac879a5bb433998e289809a4a966bd02b4bf6a9c1cc276454e39c886efcf4fc68baebed575826bde577ab5aa71d735a9", "0x880c0f8f49c875dfd62b4ddedde0f5c8b19f5687e693717f7e5c031bc580e58e13ab497d48b4874130a18743c59fdce3", "0xb582af8d8ff0bf76f0a3934775e0b54c0e8fed893245d7d89cae65b03c8125b7237edc29dc45b4fe1a3fe6db45d280ee", "0x89f337882ed3ae060aaee98efa20d79b6822bde9708c1c5fcee365d0ec9297f694cae37d38fd8e3d49717c1e86f078e7", "0x826d2c1faea54061848b484e288a5f4de0d221258178cf87f72e14baaa4acc21322f8c9eab5dde612ef497f2d2e1d60b", "0xa5333d4f227543e9cd741ccf3b81db79f2f03ca9e649e40d6a6e8ff9073e06da83683566d3b3c8d7b258c62970fb24d1", "0xa28f08c473db06aaf4c043a2fae82b3c8cfaa160bce793a4c208e4e168fb1c65115ff8139dea06453c5963d95e922b94", "0x8162546135cc5e124e9683bdfaa45833c18553ff06a0861c887dc84a5b12ae8cd4697f6794c7ef6230492c32faba7014", "0xb23f0d05b74c08d6a7df1760792be83a761b36e3f8ae360f3c363fb196e2a9dd2de2e492e49d36561366e14daa77155c", "0xb6f70d6c546722d3907c708d630dbe289771d2c8bf059c2e32b77f224696d750b4dda9b3a014debda38e7d02c9a77585", "0x83bf4c4a9f3ca022c631017e7a30ea205ba97f7f5927cba8fc8489a4646eac6712cb821c5668c9ffe94d69d524374a27", "0xb0371475425a8076d0dd5f733f55aabbe42d20a7c8ea7da352e736d4d35a327b2beb370dfcb05284e22cfd69c5f6c4cc", "0xa0031ba7522c79211416c2cca3aa5450f96f8fee711552a30889910970ba13608646538781a2c08b834b140aadd7166f", "0x99d273c80c7f2dc6045d4ed355d9fc6f74e93549d961f4a3b73cd38683f905934d359058cd1fc4da8083c7d75070487f", "0xb0e4b0efa3237793e9dcce86d75aafe9879c5fa23f0d628649aef2130454dcf72578f9bf227b9d2b9e05617468e82588", "0xa5ab076fa2e1c5c51f3ae101afdd596ad9d106bba7882b359c43d8548b64f528af19afa76cd6f40da1e6c5fca4def3fa", "0x8ce2299e570331d60f6a6eff1b271097cd5f1c0e1113fc69b89c6a0f685dabea3e5bc2ac6bd789aa492ab189f89be494", "0x91b829068874d911a310a5f9dee001021f97471307b5a3de9ec336870ec597413e1d92010ce320b619f38bed7c4f7910", "0xb14fe91f4b07bf33b046e9285b66cb07927f3a8da0af548ac2569b4c4fb1309d3ced76d733051a20814e90dd5b75ffd1", "0xabaab92ea6152d40f82940277c725aa768a631ee0b37f5961667f82fb990fc11e6d3a6a2752b0c6f94563ed9bb28265c", "0xb7fe28543eca2a716859a76ab9092f135337e28109544f6bd2727728d0a7650428af5713171ea60bfc273d1c821d992c", "0x8a4917b2ab749fc7343fc64bdf51b6c0698ff15d740cc7baf248c030475c097097d5a473bcc00d8c25817563fe0447b4", "0xaa96156d1379553256350a0a3250166add75948fb9cde62aa555a0a9dc0a9cb7f2f7b8428aff66097bf6bfedaf14bbe2", "0xae4ffeb9bdc76830d3eca2b705f30c1bdede6412fa064260a21562c8850c7fb611ec62bc68479fe48f692833e6f66d8d", "0xb96543caaba9d051600a14997765d49e4ab10b07c7a92cccf0c90b309e6da334fdd6d18c96806cbb67a7801024fbd3c7", "0x97b2b9ad76f19f500fcc94ca8e434176249f542ac66e5881a3dccd07354bdab6a2157018b19f8459437a68d8b86ba8e0", "0xa8d206f6c5a14c80005849474fde44b1e7bcf0b2d52068f5f97504c3c035b09e65e56d1cf4b5322791ae2c2fdbd61859", "0x936bad397ad577a70cf99bf9056584a61bd7f02d2d5a6cf219c05d770ae30a5cd902ba38366ce636067fc1dd10108d31", "0xa77e30195ee402b84f3882e2286bf5380c0ed374a112dbd11e16cef6b6b61ab209d4635e6f35cdaaa72c1a1981d5dabe", "0xa46ba4d3947188590a43c180757886a453a0503f79cc435322d92490446f37419c7b999fdf868a023601078070e03346", "0x80d8d4c5542f223d48240b445d4d8cf6a75d120b060bc08c45e99a13028b809d910b534d2ac47fb7068930c54efd8da9", "0x803be9c68c91b42b68e1f55e58917a477a9a6265e679ca44ee30d3eb92453f8c89c64eafc04c970d6831edd33d066902", "0xb14b2b3d0dfe2bb57cee4cd72765b60ac33c1056580950be005790176543826c1d4fbd737f6cfeada6c735543244ab57", "0xa9e480188bba1b8fb7105ff12215706665fd35bf1117bacfb6ab6985f4dbc181229873b82e5e18323c2b8f5de03258e0", "0xa66a0f0779436a9a3999996d1e6d3000f22c2cac8e0b29cddef9636393c7f1457fb188a293b6c875b05d68d138a7cc4a", "0x848397366300ab40c52d0dbbdafbafef6cd3dadf1503bb14b430f52bb9724188928ac26f6292a2412bc7d7aa620763c8", "0x95466cc1a78c9f33a9aaa3829a4c8a690af074916b56f43ae46a67a12bb537a5ac6dbe61590344a25b44e8512355a4a7", "0x8b5f7a959f818e3baf0887f140f4575cac093d0aece27e23b823cf421f34d6e4ff4bb8384426e33e8ec7b5eed51f6b5c", "0x8d5e1368ec7e3c65640d216bcc5d076f3d9845924c734a34f3558ac0f16e40597c1a775a25bf38b187213fbdba17c93b", "0xb4647c1b823516880f60d20c5cc38c7f80b363c19d191e8992226799718ee26b522a12ecb66556ed3d483aa4824f3326", "0xac3abaea9cd283eb347efda4ed9086ea3acf495043e08d0d19945876329e8675224b685612a6badf8fd72fb6274902b1", "0x8eae1ce292d317aaa71bcf6e77e654914edd5090e2e1ebab78b18bb41b9b1bc2e697439f54a44c0c8aa0d436ebe6e1a9", "0x94dc7d1aec2c28eb43d93b111fa59aaa0d77d5a09501220bd411768c3e52208806abf973c6a452fd8292ff6490e0c9e2", "0x8fd8967f8e506fef27d17b435d6b86b232ec71c1036351f12e6fb8a2e12daf01d0ee04451fb944d0f1bf7fd20e714d02", "0x824e6865be55d43032f0fec65b3480ea89b0a2bf860872237a19a54bc186a85d2f8f9989cc837fbb325b7c72d9babe2c", "0x8bd361f5adb27fd6f4e3f5de866e2befda6a8454efeb704aacc606f528c03f0faae888f60310e49440496abd84083ce2", "0xb098a3c49f2aaa28b6b3e85bc40ce6a9cdd02134ee522ae73771e667ad7629c8d82c393fba9f27f5416986af4c261438", "0xb385f5ca285ff2cfe64dcaa32dcde869c28996ed091542600a0b46f65f3f5a38428cca46029ede72b6cf43e12279e3d3", "0x8196b03d011e5be5288196ef7d47137d6f9237a635ab913acdf9c595fa521d9e2df722090ec7eb0203544ee88178fc5f", "0x8ed1270211ef928db18e502271b7edf24d0bbd11d97f2786aee772d70c2029e28095cf8f650b0328cc8a4c38d045316d", "0xa52ab60e28d69b333d597a445884d44fd2a7e1923dd60f763951e1e45f83e27a4dac745f3b9eff75977b3280e132c15d", "0x91e9fe78cdac578f4a4687f71b800b35da54b824b1886dafec073a3c977ce7a25038a2f3a5b1e35c2c8c9d1a7312417c", "0xa42832173f9d9491c7bd93b21497fbfa4121687cd4d2ab572e80753d7edcbb42cfa49f460026fbde52f420786751a138", "0x97b947126d84dcc70c97be3c04b3de3f239b1c4914342fa643b1a4bb8c4fe45c0fcb585700d13a7ed50784790c54bef9", "0x860e407d353eac070e2418ef6cb80b96fc5f6661d6333e634f6f306779651588037be4c2419562c89c61f9aa2c4947f5", "0xb2c9d93c3ba4e511b0560b55d3501bf28a510745fd666b3cb532db051e6a8617841ea2f071dda6c9f15619c7bfd2737f", "0x8596f4d239aeeac78311207904d1bd863ef68e769629cc379db60e019aaf05a9d5cd31dc8e630b31e106a3a93e47cbc5", "0x8b26e14e2e136b65c5e9e5c2022cee8c255834ea427552f780a6ca130a6446102f2a6f334c3f9a0308c53df09e3dba7e", "0xb54724354eb515a3c8bed0d0677ff1db94ac0a07043459b4358cb90e3e1aa38ac23f2caa3072cf9647275d7cd61d0e80", "0xb7ce9fe0e515e7a6b2d7ddcb92bc0196416ff04199326aea57996eef8c5b1548bd8569012210da317f7c0074691d01b7", "0xa1a13549c82c877253ddefa36a29ea6a23695ee401fdd48e65f6f61e5ebd956d5e0edeff99484e9075cb35071fec41e2", "0x838ba0c1e5bd1a6da05611ff1822b8622457ebd019cb065ece36a2d176bd2d889511328120b8a357e44569e7f640c1e6", "0xb916eccff2a95519400bbf76b5f576cbe53cf200410370a19d77734dc04c05b585cfe382e8864e67142d548cd3c4c2f4", "0xa610447cb7ca6eea53a6ff1f5fe562377dcb7f4aaa7300f755a4f5e8eba61e863c51dc2aa9a29b35525b550fbc32a0fe", "0x9620e8f0f0ee9a4719aa9685eeb1049c5c77659ba6149ec4c158f999cfd09514794b23388879931fe26fea03fa471fd3", "0xa9dcf8b679e276583cf5b9360702a185470d09aea463dc474ee9c8aee91ef089dacb073e334e47fbc78ec5417c90465c", "0x8c9adee8410bdd99e5b285744cee61e2593b6300ff31a8a83b0ec28da59475a5c6fb9346fe43aadea2e6c3dad2a8e30a", "0x97d5afe9b3897d7b8bb628b7220cf02d8ee4e9d0b78f5000d500aaf4c1df9251aaaabfd1601626519f9d66f00a821d4e", "0x8a382418157b601ce4c3501d3b8409ca98136a4ef6abcbf62885e16e215b76b035c94d149cc41ff92e42ccd7c43b9b3d", "0xb64b8d11fb3b01abb2646ac99fdb9c02b804ce15d98f9fe0fbf1c9df8440c71417487feb6cdf51e3e81d37104b19e012", "0x849d7d044f9d8f0aab346a9374f0b3a5d14a9d1faa83dbacccbdc629ad1ef903a990940255564770537f8567521d17f0", "0x829dbb0c76b996c2a91b4cbbe93ba455ca0d5729755e5f0c92aaee37dff7f36fcdc06f33aca41f1b609c784127b67d88", "0x85a7c0069047b978422d264d831ab816435f63938015d2e977222b6b5746066c0071b7f89267027f8a975206ed25c1b0", "0x84b9fbc1cfb302df1acdcf3dc5d66fd1edfe7839f7a3b2fb3a0d5548656249dd556104d7c32b73967bccf0f5bdcf9e3b", "0x972220ac5b807f53eac37dccfc2ad355d8b21ea6a9c9b011c09fe440ddcdf7513e0b43d7692c09ded80d7040e26aa28f", "0x855885ed0b21350baeca890811f344c553cf9c21024649c722453138ba29193c6b02c4b4994cd414035486f923472e28", "0x841874783ae6d9d0e59daea03e96a01cbbe4ecaced91ae4f2c8386e0d87b3128e6d893c98d17c59e4de1098e1ad519dd", "0x827e50fc9ce56f97a4c3f2f4cbaf0b22f1c3ce6f844ff0ef93a9c57a09b8bf91ebfbd2ba9c7f83c442920bffdaf288cc", "0xa441f9136c7aa4c08d5b3534921b730e41ee91ab506313e1ba5f7c6f19fd2d2e1594e88c219834e92e6fb95356385aa7", "0x97d75b144471bf580099dd6842b823ec0e6c1fb86dd0da0db195e65524129ea8b6fd4a7a9bbf37146269e938a6956596", "0xa4b6fa87f09d5a29252efb2b3aaab6b3b6ea9fab343132a651630206254a25378e3e9d6c96c3d14c150d01817d375a8e", "0xa31a671876d5d1e95fe2b8858dc69967231190880529d57d3cab7f9f4a2b9b458ac9ee5bdaa3289158141bf18f559efb", "0x90bee6fff4338ba825974021b3b2a84e36d617e53857321f13d2b3d4a28954e6de3b3c0e629d61823d18a9763313b3bf", "0x96b622a63153f393bb419bfcf88272ea8b3560dbd46b0aa07ada3a6223990d0abdd6c2adb356ef4be5641688c8d83941", "0x84c202adeaff9293698022bc0381adba2cd959f9a35a4e8472288fd68f96f6de8be9da314c526d88e291c96b1f3d6db9", "0x8ca01a143b8d13809e5a8024d03e6bc9492e22226073ef6e327edf1328ef4aff82d0bcccee92cb8e212831fa35fe1204", "0xb2f970dbad15bfbefb38903c9bcc043d1367055c55dc1100a850f5eb816a4252c8c194b3132c929105511e14ea10a67d", "0xa5e36556472a95ad57eb90c3b6623671b03eafd842238f01a081997ffc6e2401f76e781d049bb4aa94d899313577a9cf", "0x8d1057071051772f7c8bedce53a862af6fd530dd56ae6321eaf2b9fc6a68beff5ed745e1c429ad09d5a118650bfd420a", "0x8aadc4f70ace4fcb8d93a78610779748dcffc36182d45b932c226dc90e48238ea5daa91f137c65ed532352c4c4d57416", "0xa2ea05ae37e673b4343232ae685ee14e6b88b867aef6dfac35db3589cbcd76f99540fed5c2641d5bb5a4a9f808e9bf0d", "0x947f1abad982d65648ae4978e094332b4ecb90f482c9be5741d5d1cf5a28acf4680f1977bf6e49dd2174c37f11e01296", "0xa27b144f1565e4047ba0e3f4840ef19b5095d1e281eaa463c5358f932114cbd018aa6dcf97546465cf2946d014d8e6d6", "0x8574e1fc3acade47cd4539df578ce9205e745e161b91e59e4d088711a7ab5aa3b410d517d7304b92109924d9e2af8895", "0xa48ee6b86b88015d6f0d282c1ae01d2a5b9e8c7aa3d0c18b35943dceb1af580d08a65f54dc6903cde82fd0d73ce94722", "0x8875650cec543a7bf02ea4f2848a61d167a66c91ffaefe31a9e38dc8511c6a25bde431007eefe27a62af3655aca208dc", "0x999b0a6e040372e61937bf0d68374e230346b654b5a0f591a59d33a4f95bdb2f3581db7c7ccb420cd7699ed709c50713", "0x878c9e56c7100c5e47bbe77dc8da5c5fe706cec94d37fa729633bca63cace7c40102eee780fcdabb655f5fa47a99600e", "0x865006fb5b475ada5e935f27b96f9425fc2d5449a3c106aa366e55ebed3b4ee42adc3c3f0ac19fd129b40bc7d6bc4f63", "0xb7a7da847f1202e7bc1672553e68904715e84fd897d529243e3ecda59faa4e17ba99c649a802d53f6b8dfdd51f01fb74", "0x8b2fb4432c05653303d8c8436473682933a5cb604da10c118ecfcd2c8a0e3132e125afef562bdbcc3df936164e5ce4f2", "0x808d95762d33ddfa5d0ee3d7d9f327de21a994d681a5f372e2e3632963ea974da7f1f9e5bac8ccce24293509d1f54d27", "0x932946532e3c397990a1df0e94c90e1e45133e347a39b6714c695be21aeb2d309504cb6b1dde7228ff6f6353f73e1ca2", "0x9705e7c93f0cdfaa3fa96821f830fe53402ad0806036cd1b48adc2f022d8e781c1fbdab60215ce85c653203d98426da3", "0xaa180819531c3ec1feb829d789cb2092964c069974ae4faad60e04a6afcce5c3a59aec9f11291e6d110a788d22532bc6", "0x88f755097f7e25cb7dd3c449520c89b83ae9e119778efabb54fbd5c5714b6f37c5f9e0346c58c6ab09c1aef2483f895d", "0x99fc03ab7810e94104c494f7e40b900f475fde65bdec853e60807ffd3f531d74de43335c3b2646b5b8c26804a7448898", "0xaf2dea9683086bed1a179110efb227c9c00e76cd00a2015b089ccbcee46d1134aa18bda5d6cab6f82ae4c5cd2461ac21", "0xa500f87ba9744787fdbb8e750702a3fd229de6b8817594348dec9a723b3c4240ddfa066262d002844b9e38240ce55658", "0x924d0e45c780f5bc1c1f35d15dfc3da28036bdb59e4c5440606750ecc991b85be18bc9a240b6c983bc5430baa4c68287", "0x865b11e0157b8bf4c5f336024b016a0162fc093069d44ac494723f56648bc4ded13dfb3896e924959ea11c96321afefc", "0x93672d8607d4143a8f7894f1dcca83fb84906dc8d6dd7dd063bb0049cfc20c1efd933e06ca7bd03ea4cb5a5037990bfe", "0x826891efbdff0360446825a61cd1fa04326dd90dae8c33dfb1ed97b045e165766dd070bd7105560994d0b2044bdea418", "0x93c4a4a8bcbc8b190485cc3bc04175b7c0ed002c28c98a540919effd6ed908e540e6594f6db95cd65823017258fb3b1c", "0xaeb2a0af2d2239fda9aa6b8234b019708e8f792834ff0dd9c487fa09d29800ddceddd6d7929faa9a3edcb9e1b3aa0d6b", "0x87f11de7236d387863ec660d2b04db9ac08143a9a2c4dfff87727c95b4b1477e3bc473a91e5797313c58754905079643", "0x80dc1db20067a844fe8baceca77f80db171a5ca967acb24e2d480eae9ceb91a3343c31ad1c95b721f390829084f0eae6", "0x9825c31f1c18da0de3fa84399c8b40f8002c3cae211fb6a0623c76b097b4d39f5c50058f57a16362f7a575909d0a44a2", "0xa99fc8de0c38dbf7b9e946de83943a6b46a762167bafe2a603fb9b86f094da30d6de7ed55d639aafc91936923ee414b3", "0xad594678b407db5d6ea2e90528121f84f2b96a4113a252a30d359a721429857c204c1c1c4ff71d8bb5768c833f82e80e", "0xb33d985e847b54510b9b007e31053732c8a495e43be158bd2ffcea25c6765bcbc7ca815f7c60b36ad088b955dd6e9350", "0x815f8dfc6f90b3342ca3fbd968c67f324dae8f74245cbf8bc3bef10e9440c65d3a2151f951e8d18959ba01c1b50b0ec1", "0x94c608a362dd732a1abc56e338637c900d59013db8668e49398b3c7a0cae3f7e2f1d1bf94c0299eeafe6af7f76c88618", "0x8ebd8446b23e5adfcc393adc5c52fe172f030a73e63cd2d515245ca0dd02782ceed5bcdd9ccd9c1b4c5953dfac9c340c", "0x820437f3f6f9ad0f5d7502815b221b83755eb8dc56cd92c29e9535eb0b48fb8d08c9e4fcc26945f9c8cca60d89c44710", "0x8910e4e8a56bf4be9cc3bbf0bf6b1182a2f48837a2ed3c2aaec7099bfd7f0c83e14e608876b17893a98021ff4ab2f20d", "0x9633918fde348573eec15ce0ad53ac7e1823aac86429710a376ad661002ae6d049ded879383faaa139435122f64047c6", "0xa1f5e3fa558a9e89318ca87978492f0fb4f6e54a9735c1b8d2ecfb1d1c57194ded6e0dd82d077b2d54251f3bee1279e1", "0xb208e22d04896abfd515a95c429ff318e87ff81a5d534c8ac2c33c052d6ffb73ef1dccd39c0bbe0734b596c384014766", "0x986d5d7d2b5bde6d16336f378bd13d0e671ad23a8ec8a10b3fc09036faeeb069f60662138d7a6df3dfb8e0d36180f770", "0xa2d4e6c5f5569e9cef1cddb569515d4b6ace38c8aed594f06da7434ba6b24477392cc67ba867c2b079545ca0c625c457", "0xb5ac32b1d231957d91c8b7fc43115ce3c5c0d8c13ca633374402fa8000b6d9fb19499f9181844f0c10b47357f3f757ce", "0x96b8bf2504b4d28fa34a4ec378e0e0b684890c5f44b7a6bb6e19d7b3db2ab27b1e2686389d1de9fbd981962833a313ea", "0x953bfd7f6c3a0469ad432072b9679a25486f5f4828092401eff494cfb46656c958641a4e6d0d97d400bc59d92dba0030", "0x876ab3cea7484bbfd0db621ec085b9ac885d94ab55c4bb671168d82b92e609754b86aaf472c55df3d81421d768fd108a", "0x885ff4e67d9ece646d02dd425aa5a087e485c3f280c3471b77532b0db6145b69b0fbefb18aa2e3fa5b64928b43a94e57", "0xb91931d93f806d0b0e6cc62a53c718c099526140f50f45d94b8bbb57d71e78647e06ee7b42aa5714aed9a5c05ac8533f", "0xa0313eeadd39c720c9c27b3d671215331ab8d0a794e71e7e690f06bcd87722b531d6525060c358f35f5705dbb7109ccb", "0x874c0944b7fedc6701e53344100612ddcb495351e29305c00ec40a7276ea5455465ffb7bded898886c1853139dfb1fc7", "0x8dc31701a01ee8137059ca1874a015130d3024823c0576aa9243e6942ec99d377e7715ed1444cd9b750a64b85dcaa3e5", "0x836d2a757405e922ec9a2dfdcf489a58bd48b5f9683dd46bf6047688f778c8dee9bc456de806f70464df0b25f3f3d238", "0xb30b0a1e454a503ea3e2efdec7483eaf20b0a5c3cefc42069e891952b35d4b2c955cf615f3066285ed8fafd9fcfbb8f6", "0x8e6d4044b55ab747e83ec8762ea86845f1785cc7be0279c075dadf08aca3ccc5a096c015bb3c3f738f647a4eadea3ba5", "0xad7735d16ab03cbe09c029610aa625133a6daecfc990b297205b6da98eda8c136a7c50db90f426d35069708510d5ae9c", "0x8d62d858bbb59ec3c8cc9acda002e08addab4d3ad143b3812098f3d9087a1b4a1bb255dcb1635da2402487d8d0249161", "0x805beec33238b832e8530645a3254aeef957e8f7ea24bcfc1054f8b9c69421145ebb8f9d893237e8a001c857fedfc77e", "0xb1005644be4b085e3f5775aa9bd3e09a283e87ddada3082c04e7a62d303dcef3b8cf8f92944c200c7ae6bb6bdf63f832", "0xb4ba0e0790dc29063e577474ffe3b61f5ea2508169f5adc1e394934ebb473e356239413a17962bc3e5d3762d72cce8c2", "0xa157ba9169c9e3e6748d9f1dd67fbe08b9114ade4c5d8fc475f87a764fb7e6f1d21f66d7905cd730f28a1c2d8378682a", "0x913e52b5c93989b5d15e0d91aa0f19f78d592bc28bcfdfddc885a9980c732b1f4debb8166a7c4083c42aeda93a702898", "0x90fbfc1567e7cd4e096a38433704d3f96a2de2f6ed3371515ccc30bc4dd0721a704487d25a97f3c3d7e4344472702d8d", "0x89646043028ffee4b69d346907586fd12c2c0730f024acb1481abea478e61031966e72072ff1d5e65cb8c64a69ad4eb1", "0xb125a45e86117ee11d2fb42f680ab4a7894edd67ff927ae2c808920c66c3e55f6a9d4588eee906f33a05d592e5ec3c04", "0xaad47f5b41eae9be55fb4f67674ff1e4ae2482897676f964a4d2dcb6982252ee4ff56aac49578b23f72d1fced707525e", "0xb9ddff8986145e33851b4de54d3e81faa3352e8385895f357734085a1616ef61c692d925fe62a5ed3be8ca49f5d66306", "0xb3cb0963387ed28c0c0adf7fe645f02606e6e1780a24d6cecef5b7c642499109974c81a7c2a198b19862eedcea2c2d8c", "0xac9c53c885457aaf5cb36c717a6f4077af701e0098eebd7aa600f5e4b14e6c1067255b3a0bc40e4a552025231be7de60", "0x8e1a8d823c4603f6648ec21d064101094f2a762a4ed37dd2f0a2d9aa97b2d850ce1e76f4a4b8cae58819b058180f7031", "0xb268b73bf7a179b6d22bd37e5e8cb514e9f5f8968c78e14e4f6d5700ca0d0ca5081d0344bb73b028970eebde3cb4124e", "0xa7f57d71940f0edbd29ed8473d0149cae71d921dd15d1ff589774003e816b54b24de2620871108cec1ab9fa956ad6ce6", "0x8053e6416c8b120e2b999cc2fc420a6a55094c61ac7f2a6c6f0a2c108a320890e389af96cbe378936132363c0d551277", "0xb3823f4511125e5aa0f4269e991b435a0d6ceb523ebd91c04d7add5534e3df5fc951c504b4fd412a309fd3726b7f940b", "0xae6eb04674d04e982ca9a6add30370ab90e303c71486f43ed3efbe431af1b0e43e9d06c11c3412651f304c473e7dbf39", "0x96ab55e641ed2e677591f7379a3cd126449614181fce403e93e89b1645d82c4af524381ff986cae7f9cebe676878646d", "0xb52423b4a8c37d3c3e2eca8f0ddbf7abe0938855f33a0af50f117fab26415fb0a3da5405908ec5fdc22a2c1f2ca64892", "0x82a69ce1ee92a09cc709d0e3cd22116c9f69d28ea507fe5901f5676000b5179b9abe4c1875d052b0dd42d39925e186bb", "0xa84c8cb84b9d5cfb69a5414f0a5283a5f2e90739e9362a1e8c784b96381b59ac6c18723a4aa45988ee8ef5c1f45cc97d", "0xafd7efce6b36813082eb98257aae22a4c1ae97d51cac7ea9c852d4a66d05ef2732116137d8432e3f117119725a817d24", "0xa0f5fe25af3ce021b706fcff05f3d825384a272284d04735574ce5fb256bf27100fad0b1f1ba0e54ae9dcbb9570ecad3", "0x8751786cb80e2e1ff819fc7fa31c2833d25086534eb12b373d31f826382430acfd87023d2a688c65b5e983927e146336", "0x8cf5c4b17fa4f3d35c78ce41e1dc86988fd1135cd5e6b2bb0c108ee13538d0d09ae7102609c6070f39f937b439b31e33", "0xa9108967a2fedd7c322711eca8159c533dd561bedcb181b646de98bf5c3079449478eab579731bee8d215ae8852c7e21", "0xb54c5171704f42a6f0f4e70767cdb3d96ffc4888c842eece343a01557da405961d53ffdc34d2f902ea25d3e1ed867cad", "0xae8d4b764a7a25330ba205bf77e9f46182cd60f94a336bbd96773cf8064e3d39caf04c310680943dc89ed1fbad2c6e0d", "0xaa5150e911a8e1346868e1b71c5a01e2a4bb8632c195861fb6c3038a0e9b85f0e09b3822e9283654a4d7bb17db2fc5f4", "0x9685d3756ce9069bf8bb716cf7d5063ebfafe37e15b137fc8c3159633c4e006ff4887ddd0ae90360767a25c3f90cba7f", "0x82155fd70f107ab3c8e414eadf226c797e07b65911508c76c554445422325e71af8c9a8e77fd52d94412a6fc29417cd3", "0xabfae52f53a4b6e00760468d973a267f29321997c3dbb5aee36dc1f20619551229c0c45b9d9749f410e7f531b73378e8", "0x81a76d921f8ef88e774fd985e786a4a330d779b93fad7def718c014685ca0247379e2e2a007ad63ee7f729cd9ed6ce1b", "0x81947c84bc5e28e26e2e533af5ae8fe10407a7b77436dbf8f1d5b0bbe86fc659eae10f974659dc7c826c6dabd03e3a4b", "0x92b8c07050d635b8dd4fd09df9054efe4edae6b86a63c292e73cc819a12a21dd7d104ce51fa56af6539dedf6dbe6f7b6", "0xb44c579e3881f32b32d20c82c207307eca08e44995dd2aac3b2692d2c8eb2a325626c80ac81c26eeb38c4137ff95add5", "0x97efab8941c90c30860926dea69a841f2dcd02980bf5413b9fd78d85904588bf0c1021798dbc16c8bbb32cce66c82621", "0x913363012528b50698e904de0588bf55c8ec5cf6f0367cfd42095c4468fcc64954fbf784508073e542fee242d0743867", "0x8ed203cf215148296454012bd10fddaf119203db1919a7b3d2cdc9f80e66729464fdfae42f1f2fc5af1ed53a42b40024", "0xab84312db7b87d711e9a60824f4fe50e7a6190bf92e1628688dfcb38930fe87b2d53f9e14dd4de509b2216856d8d9188", "0x880726def069c160278b12d2258eac8fa63f729cd351a710d28b7e601c6712903c3ac1e7bbd0d21e4a15f13ca49db5aa", "0x980699cd51bac6283959765f5174e543ed1e5f5584b5127980cbc2ef18d984ecabba45042c6773b447b8e694db066028", "0xaeb019cb80dc4cb4207430d0f2cd24c9888998b6f21d9bf286cc638449668d2eec0018a4cf3fe6448673cd6729335e2b", "0xb29852f6aa6c60effdffe96ae88590c88abae732561d35cc19e82d3a51e26cb35ea00986193e07f90060756240f5346e", "0xa0fa855adc5ba469f35800c48414b8921455950a5c0a49945d1ef6e8f2a1881f2e2dfae47de6417270a6bf49deeb091d", "0xb6c7332e3b14813641e7272d4f69ecc7e09081df0037d6dab97ce13a9e58510f5c930d300633f208181d9205c5534001", "0x85a6c050f42fce560b5a8d54a11c3bbb8407abbadd859647a7b0c21c4b579ec65671098b74f10a16245dc779dff7838e", "0x8f3eb34bb68759d53c6677de4de78a6c24dd32c8962a7fb355ed362572ef8253733e6b52bc21c9f92ecd875020a9b8de", "0xa17dd44181e5dab4dbc128e1af93ec22624b57a448ca65d2d9e246797e4af7d079e09c6e0dfb62db3a9957ce92f098d5", "0xa56a1b854c3183082543a8685bb34cae1289f86cfa8123a579049dbd059e77982886bfeb61bf6e05b4b1fe4e620932e7", "0xaedae3033cb2fb7628cb4803435bdd7757370a86f808ae4cecb9a268ad0e875f308c048c80cbcac523de16b609683887", "0x9344905376aa3982b1179497fac5a1d74b14b7038fd15e3b002db4c11c8bfc7c39430db492cdaf58b9c47996c9901f28", "0xa3bfafdae011a19f030c749c3b071f83580dee97dd6f949e790366f95618ca9f828f1daaeabad6dcd664fcef81b6556d", "0x81c03d8429129e7e04434dee2c529194ddb01b414feda3adee2271eb680f6c85ec872a55c9fa9d2096f517e13ed5abcc", "0x98205ef3a72dff54c5a9c82d293c3e45d908946fa74bb749c3aabe1ab994ea93c269bcce1a266d2fe67a8f02133c5985", "0x85a70aeed09fda24412fadbafbbbf5ba1e00ac92885df329e147bfafa97b57629a3582115b780d8549d07d19b7867715", "0xb0fbe81c719f89a57d9ea3397705f898175808c5f75f8eb81c2193a0b555869ba7bd2e6bc54ee8a60cea11735e21c68c", "0xb03a0bd160495ee626ff3a5c7d95bc79d7da7e5a96f6d10116600c8fa20bedd1132f5170f25a22371a34a2d763f2d6d0", "0xa90ab04091fbca9f433b885e6c1d60ab45f6f1daf4b35ec22b09909d493a6aab65ce41a6f30c98239cbca27022f61a8b", "0xb66f92aa3bf2549f9b60b86f99a0bd19cbdd97036d4ae71ca4b83d669607f275260a497208f6476cde1931d9712c2402", "0xb08e1fdf20e6a9b0b4942f14fa339551c3175c1ffc5d0ab5b226b6e6a322e9eb0ba96adc5c8d59ca4259e2bdd04a7eb0", "0xa2812231e92c1ce74d4f5ac3ab6698520288db6a38398bb38a914ac9326519580af17ae3e27cde26607e698294022c81", "0xabfcbbcf1d3b9e84c02499003e490a1d5d9a2841a9e50c7babbef0b2dd20d7483371d4dc629ba07faf46db659459d296", "0xb0fe9f98c3da70927c23f2975a9dc4789194d81932d2ad0f3b00843dd9cbd7fb60747a1da8fe5a79f136a601becf279d", "0xb130a6dba7645165348cb90f023713bed0eefbd90a976b313521c60a36d34f02032e69a2bdcf5361e343ed46911297ec", "0x862f0cffe3020cea7a5fd4703353aa1eb1be335e3b712b29d079ff9f7090d1d8b12013011e1bdcbaa80c44641fd37c9f", "0x8c6f11123b26633e1abb9ed857e0bce845b2b3df91cc7b013b2fc77b477eee445da0285fc6fc793e29d5912977f40916", "0x91381846126ea819d40f84d3005e9fb233dc80071d1f9bb07f102bf015f813f61e5884ffffb4f5cd333c1b1e38a05a58", "0x8add7d908de6e1775adbd39c29a391f06692b936518db1f8fde74eb4f533fc510673a59afb86e3a9b52ade96e3004c57", "0x8780e086a244a092206edcde625cafb87c9ab1f89cc3e0d378bc9ee776313836160960a82ec397bc3800c0a0ec3da283", "0xa6cb4cd9481e22870fdd757fae0785edf4635e7aacb18072fe8dc5876d0bab53fb99ce40964a7d3e8bcfff6f0ab1332f", "0xaf30ff47ecc5b543efba1ba4706921066ca8bb625f40e530fb668aea0551c7647a9d126e8aba282fbcce168c3e7e0130", "0x91b0bcf408ce3c11555dcb80c4410b5bc2386d3c05caec0b653352377efdcb6bab4827f2018671fc8e4a0e90d772acc1", "0xa9430b975ef138b6b2944c7baded8fe102d31da4cfe3bd3d8778bda79189c99d38176a19c848a19e2d1ee0bddd9a13c1", "0xaa5a4eef849d7c9d2f4b018bd01271c1dd83f771de860c4261f385d3bdcc130218495860a1de298f14b703ec32fa235f", "0xb0ce79e7f9ae57abe4ff366146c3b9bfb38b0dee09c28c28f5981a5d234c6810ad4d582751948affb480d6ae1c8c31c4", "0xb75122748560f73d15c01a8907d36d06dc068e82ce22b84b322ac1f727034493572f7907dec34ebc3ddcc976f2f89ed7", "0xb0fc7836369a3e4411d34792d6bd5617c14f61d9bba023dda64e89dc5fb0f423244e9b48ee64869258931daa9753a56f", "0x8956d7455ae9009d70c6e4a0bcd7610e55f37494cf9897a8f9e1b904cc8febc3fd2d642ebd09025cfff4609ad7e3bc52", "0xad741efe9e472026aa49ae3d9914cb9c1a6f37a54f1a6fe6419bebd8c7d68dca105a751c7859f4389505ede40a0de786", "0xb52f418797d719f0d0d0ffb0846788b5cba5d0454a69a2925de4b0b80fa4dd7e8c445e5eac40afd92897ed28ca650566", "0xa0ab65fb9d42dd966cd93b1de01d7c822694669dd2b7a0c04d99cd0f3c3de795f387b9c92da11353412f33af5c950e9a", "0xa0052f44a31e5741a331f7cac515a08b3325666d388880162d9a7b97598fde8b61f9ff35ff220df224eb5c4e40ef0567", "0xa0101cfdc94e42b2b976c0d89612a720e55d145a5ef6ef6f1f78cf6de084a49973d9b5d45915349c34ce712512191e3c", "0xa0dd99fcf3f5cead5aaf08e82212df3a8bb543c407a4d6fab88dc5130c1769df3f147e934a46f291d6c1a55d92b86917", "0xa5939153f0d1931bbda5cf6bdf20562519ea55fbfa978d6dbc6828d298260c0da7a50c37c34f386e59431301a96c2232", "0x9568269f3f5257200f9ca44afe1174a5d3cf92950a7f553e50e279c239e156a9faaa2a67f288e3d5100b4142efe64856", "0xb746b0832866c23288e07f24991bbf687cad794e7b794d3d3b79367566ca617d38af586cdc8d6f4a85a34835be41d54f", "0xa871ce28e39ab467706e32fec1669fda5a4abba2f8c209c6745df9f7a0fa36bbf1919cf14cb89ea26fa214c4c907ae03", "0xa08dacdd758e523cb8484f6bd070642c0c20e184abdf8e2a601f61507e93952d5b8b0c723c34fcbdd70a8485eec29db2", "0x85bdb78d501382bb95f1166b8d032941005661aefd17a5ac32df9a3a18e9df2fc5dc2c1f07075f9641af10353cecc0c9", "0x98d730c28f6fa692a389e97e368b58f4d95382fad8f0baa58e71a3d7baaea1988ead47b13742ce587456f083636fa98e", "0xa557198c6f3d5382be9fb363feb02e2e243b0c3c61337b3f1801c4a0943f18e38ce1a1c36b5c289c8fa2aa9d58742bab", "0x89174f79201742220ac689c403fc7b243eed4f8e3f2f8aba0bf183e6f5d4907cb55ade3e238e3623d9885f03155c4d2b", "0xb891d600132a86709e06f3381158db300975f73ea4c1f7c100358e14e98c5fbe792a9af666b85c4e402707c3f2db321e", "0xb9e5b2529ef1043278c939373fc0dbafe446def52ddd0a8edecd3e4b736de87e63e187df853c54c28d865de18a358bb6", "0x8589b2e9770340c64679062c5badb7bbef68f55476289b19511a158a9a721f197da03ece3309e059fc4468b15ac33aa3", "0xaad8c6cd01d785a881b446f06f1e9cd71bca74ba98674c2dcddc8af01c40aa7a6d469037498b5602e76e9c91a58d3dbd", "0xabaccb1bd918a8465f1bf8dbe2c9ad4775c620b055550b949a399f30cf0d9eb909f3851f5b55e38f9e461e762f88f499", "0xae62339d26db46e85f157c0151bd29916d5cc619bd4b832814b3fd2f00af8f38e7f0f09932ffe5bba692005dab2d9a74", "0x93a6ff30a5c0edf8058c89aba8c3259e0f1b1be1b80e67682de651e5346f7e1b4b4ac3d87cbaebf198cf779524aff6bf", "0x8980a2b1d8f574af45b459193c952400b10a86122b71fca2acb75ee0dbd492e7e1ef5b959baf609a5172115e371f3177", "0x8c2f49f3666faee6940c75e8c7f6f8edc3f704cca7a858bbb7ee5e96bba3b0cf0993996f781ba6be3b0821ef4cb75039", "0xb14b9e348215b278696018330f63c38db100b0542cfc5be11dc33046e3bca6a13034c4ae40d9cef9ea8b34fef0910c4e", "0xb59bc3d0a30d66c16e6a411cb641f348cb1135186d5f69fda8b0a0934a5a2e7f6199095ba319ec87d3fe8f1ec4a06368", "0x8874aca2a3767aa198e4c3fec2d9c62d496bc41ff71ce242e9e082b7f38cdf356089295f80a301a3cf1182bde5308c97", "0xb1820ebd61376d91232423fc20bf008b2ba37e761199f4ef0648ea2bd70282766799b4de814846d2f4d516d525c8daa7", "0xa6b202e5dedc16a4073e04a11af3a8509b23dfe5a1952f899adeb240e75c3f5bde0c424f811a81ea48d343591faffe46", "0xa69becee9c93734805523b92150a59a62eed4934f66056b645728740d42223f2925a1ad38359ba644da24d9414f4cdda", "0xad72f0f1305e37c7e6b48c272323ee883320994cb2e0d850905d6655fafc9f361389bcb9c66b3ff8d2051dbb58c8aa96", "0xb563600bd56fad7c8853af21c6a02a16ed9d8a8bbeea2c31731d63b976d83cb05b9779372d898233e8fd597a75424797", "0xb0abb78ce465bf7051f563c62e8be9c57a2cc997f47c82819300f36e301fefd908894bb2053a9d27ce2d0f8c46d88b5b", "0xa071a85fb8274bac2202e0cb8e0e2028a5e138a82d6e0374d39ca1884a549c7c401312f00071b91f455c3a2afcfe0cda", "0xb931c271513a0f267b9f41444a5650b1918100b8f1a64959c552aff4e2193cc1b9927906c6fa7b8a8c68ef13d79aaa52", "0xa6a1bb9c7d32cb0ca44d8b75af7e40479fbce67d216b48a2bb680d3f3a772003a49d3cd675fc64e9e0f8fabeb86d6d61", "0xb98d609858671543e1c3b8564162ad828808bb50ded261a9f8690ded5b665ed8368c58f947365ed6e84e5a12e27b423d", "0xb3dca58cd69ec855e2701a1d66cad86717ff103ef862c490399c771ad28f675680f9500cb97be48de34bcdc1e4503ffd", "0xb34867c6735d3c49865e246ddf6c3b33baf8e6f164db3406a64ebce4768cb46b0309635e11be985fee09ab7a31d81402", "0xacb966c554188c5b266624208f31fab250b3aa197adbdd14aee5ab27d7fb886eb4350985c553b20fdf66d5d332bfd3fe", "0x943c36a18223d6c870d54c3b051ef08d802b85e9dd6de37a51c932f90191890656c06adfa883c87b906557ae32d09da0", "0x81bca7954d0b9b6c3d4528aadf83e4bc2ef9ea143d6209bc45ae9e7ae9787dbcd8333c41f12c0b6deee8dcb6805e826a", "0xaba176b92256efb68f574e543479e5cf0376889fb48e3db4ebfb7cba91e4d9bcf19dcfec444c6622d9398f06de29e2b9", "0xb9f743691448053216f6ece7cd699871fff4217a1409ceb8ab7bdf3312d11696d62c74b0664ba0a631b1e0237a8a0361", "0xa383c2b6276fa9af346b21609326b53fb14fdf6f61676683076e80f375b603645f2051985706d0401e6fbed7eb0666b6", "0xa9ef2f63ec6d9beb8f3d04e36807d84bda87bdd6b351a3e4a9bf7edcb5618c46c1f58cfbf89e64b40f550915c6988447", "0xa141b2d7a82f5005eaea7ae7d112c6788b9b95121e5b70b7168d971812f3381de8b0082ac1f0a82c7d365922ebd2d26a", "0xb1b76ef8120e66e1535c17038b75255a07849935d3128e3e99e56567b842fb1e8d56ef932d508d2fb18b82f7868fe1a9", "0x8e2e234684c81f21099f5c54f6bbe2dd01e3b172623836c77668a0c49ce1fe218786c3827e4d9ae2ea25c50a8924fb3c", "0xa5caf5ff948bfd3c4ca3ffbdfcd91eec83214a6c6017235f309a0bbf7061d3b0b466307c00b44a1009cf575163898b43", "0x986415a82ca16ebb107b4c50b0c023c28714281db0bcdab589f6cb13d80e473a3034b7081b3c358e725833f6d845cb14", "0xb94836bf406ac2cbacb10e6df5bcdfcc9d9124ae1062767ca4e322d287fd5e353fdcebd0e52407cb3cd68571258a8900", "0x83c6d70a640b33087454a4788dfd9ef3ed00272da084a8d36be817296f71c086b23b576f98178ab8ca6a74f04524b46b", "0xad4115182ad784cfe11bcfc5ce21fd56229cc2ce77ac82746e91a2f0aa53ca6593a22efd2dc4ed8d00f84542643d9c58", "0xab1434c5e5065da826d10c2a2dba0facccab0e52b506ce0ce42fbe47ced5a741797151d9ecc99dc7d6373cfa1779bbf6", "0x8a8b591d82358d55e6938f67ea87a89097ab5f5496f7260adb9f649abb289da12b498c5b2539c2f9614fb4e21b1f66b0", "0x964f355d603264bc1f44c64d6d64debca66f37dff39c971d9fc924f2bc68e6c187b48564a6dc82660a98b035f8addb5d", "0xb66235eaaf47456bc1dc4bde454a028e2ce494ece6b713a94cd6bf27cf18c717fd0c57a5681caaa2ad73a473593cdd7a", "0x9103e3bb74304186fa4e3e355a02da77da4aca9b7e702982fc2082af67127ebb23a455098313c88465bc9b7d26820dd5", "0xb6a42ff407c9dd132670cdb83cbad4b20871716e44133b59a932cd1c3f97c7ac8ff7f61acfaf8628372508d8dc8cad7c", "0x883a9c21c16a167a4171b0f084565c13b6f28ba7c4977a0de69f0a25911f64099e7bbb4da8858f2e93068f4155d04e18", "0x8dbb3220abc6a43220adf0331e3903d3bfd1d5213aadfbd8dfcdf4b2864ce2e96a71f35ecfb7a07c3bbabf0372b50271", "0xb4ad08aee48e176bda390b7d9acf2f8d5eb008f30d20994707b757dc6a3974b2902d29cd9b4d85e032810ad25ac49e97", "0x865bb0f33f7636ec501bb634e5b65751c8a230ae1fa807a961a8289bbf9c7fe8c59e01fbc4c04f8d59b7f539cf79ddd5", "0x86a54d4c12ad1e3605b9f93d4a37082fd26e888d2329847d89afa7802e815f33f38185c5b7292293d788ad7d7da1df97", "0xb26c8615c5e47691c9ff3deca3021714662d236c4d8401c5d27b50152ce7e566266b9d512d14eb63e65bc1d38a16f914", "0x827639d5ce7db43ba40152c8a0eaad443af21dc92636cc8cc2b35f10647da7d475a1e408901cd220552fddad79db74df", "0xa2b79a582191a85dbe22dc384c9ca3de345e69f6aa370aa6d3ff1e1c3de513e30b72df9555b15a46586bd27ea2854d9d", "0xae0d74644aba9a49521d3e9553813bcb9e18f0b43515e4c74366e503c52f47236be92dfbd99c7285b3248c267b1de5a0", "0x80fb0c116e0fd6822a04b9c25f456bdca704e2be7bdc5d141dbf5d1c5eeb0a2c4f5d80db583b03ef3e47517e4f9a1b10", "0xac3a1fa3b4a2f30ea7e0a114cdc479eb51773573804c2a158d603ad9902ae8e39ffe95df09c0d871725a5d7f9ba71a57", "0xb56b2b0d601cba7f817fa76102c68c2e518c6f20ff693aad3ff2e07d6c4c76203753f7f91686b1801e8c4659e4d45c48", "0x89d50c1fc56e656fb9d3915964ebce703cb723fe411ab3c9eaa88ccc5d2b155a9b2e515363d9c600d3c0cee782c43f41", "0xb24207e61462f6230f3cd8ccf6828357d03e725769f7d1de35099ef9ee4dca57dbce699bb49ed994462bee17059d25ce", "0xb886f17fcbcbfcd08ac07f04bb9543ef58510189decaccea4b4158c9174a067cb67d14b6be3c934e6e2a18c77efa9c9c", "0xb9c050ad9cafd41c6e2e192b70d080076eed59ed38ea19a12bd92fa17b5d8947d58d5546aaf5e8e27e1d3b5481a6ce51", "0xaaf7a34d3267e3b1ddbc54c641e3922e89303f7c86ebebc7347ebca4cffad5b76117dac0cbae1a133053492799cd936f", "0xa9ee604ada50adef82e29e893070649d2d4b7136cc24fa20e281ce1a07bd736bf0de7c420369676bcbcecff26fb6e900", "0x9855315a12a4b4cf80ab90b8bd13003223ba25206e52fd4fe6a409232fbed938f30120a3db23eab9c53f308bd8b9db81", "0x8cd488dd7a24f548a3cf03c54dec7ff61d0685cb0f6e5c46c2d728e3500d8c7bd6bba0156f4bf600466fda53e5b20444", "0x890ad4942ebac8f5b16c777701ab80c68f56fa542002b0786f8fea0fb073154369920ac3dbfc07ea598b82f4985b8ced", "0x8de0cf9ddc84c9b92c59b9b044387597799246b30b9f4d7626fc12c51f6e423e08ee4cbfe9289984983c1f9521c3e19d", "0xb474dfb5b5f4231d7775b3c3a8744956b3f0c7a871d835d7e4fd9cc895222c7b868d6c6ce250de568a65851151fac860", "0x86433b6135d9ed9b5ee8cb7a6c40e5c9d30a68774cec04988117302b8a02a11a71a1e03fd8e0264ef6611d219f103007", "0x80b9ed4adbe9538fb1ef69dd44ec0ec5b57cbfea820054d8d445b4261962624b4c70ac330480594bc5168184378379c3", "0x8b2e83562ccd23b7ad2d17f55b1ab7ef5fbef64b3a284e6725b800f3222b8bdf49937f4a873917ada9c4ddfb090938c2", "0xabe78cebc0f5a45d754140d1f685e387489acbfa46d297a8592aaa0d676a470654f417a4f7d666fc0b2508fab37d908e", "0xa9c5f8ff1f8568e252b06d10e1558326db9901840e6b3c26bbd0cd5e850cb5fb3af3f117dbb0f282740276f6fd84126f", "0x975f8dc4fb55032a5df3b42b96c8c0ffecb75456f01d4aef66f973cb7270d4eff32c71520ceefc1adcf38d77b6b80c67", "0xb043306ed2c3d8a5b9a056565afd8b5e354c8c4569fda66b0d797a50a3ce2c08cffbae9bbe292da69f39e89d5dc7911e", "0x8d2afc36b1e44386ba350c14a6c1bb31ff6ea77128a0c5287584ac3584282d18516901ce402b4644a53db1ed8e7fa581", "0x8c294058bed53d7290325c363fe243f6ec4f4ea2343692f4bac8f0cb86f115c069ccb8334b53d2e42c067691ad110dba", "0xb92157b926751aaf7ef82c1aa8c654907dccab6376187ee8b3e8c0c82811eae01242832de953faa13ebaff7da8698b3e", "0xa780c4bdd9e4ba57254b09d745075cecab87feda78c88ffee489625c5a3cf96aa6b3c9503a374a37927d9b78de9bd22b", "0x811f548ef3a2e6a654f7dcb28ac9378de9515ed61e5a428515d9594a83e80b35c60f96a5cf743e6fab0d3cb526149f49", "0x85a4dccf6d90ee8e094731eec53bd00b3887aec6bd81a0740efddf812fd35e3e4fe4f983afb49a8588691c202dabf942", "0xb152c2da6f2e01c8913079ae2b40a09b1f361a80f5408a0237a8131b429677c3157295e11b365b1b1841924b9efb922e", "0x849b9efee8742502ffd981c4517c88ed33e4dd518a330802caff168abae3cd09956a5ee5eda15900243bc2e829016b74", "0x955a933f3c18ec0f1c0e38fa931e4427a5372c46a3906ebe95082bcf878c35246523c23f0266644ace1fa590ffa6d119", "0x911989e9f43e580c886656377c6f856cdd4ff1bd001b6db3bbd86e590a821d34a5c6688a29b8d90f28680e9fdf03ba69", "0xb73b8b4f1fd6049fb68d47cd96a18fcba3f716e0a1061aa5a2596302795354e0c39dea04d91d232aec86b0bf2ba10522", "0x90f87456d9156e6a1f029a833bf3c7dbed98ca2f2f147a8564922c25ae197a55f7ea9b2ee1f81bf7383197c4bad2e20c", "0x903cba8b1e088574cb04a05ca1899ab00d8960580c884bd3c8a4c98d680c2ad11410f2b75739d6050f91d7208cac33a5", "0x9329987d42529c261bd15ecedd360be0ea8966e7838f32896522c965adfc4febf187db392bd441fb43bbd10c38fdf68b", "0x8178ee93acf5353baa349285067b20e9bb41aa32d77b5aeb7384fe5220c1fe64a2461bd7a83142694fe673e8bbf61b7c", "0xa06a8e53abcff271b1394bcc647440f81fb1c1a5f29c27a226e08f961c3353f4891620f2d59b9d1902bf2f5cc07a4553", "0xaaf5fe493b337810889e777980e6bbea6cac39ac66bc0875c680c4208807ac866e9fda9b5952aa1d04539b9f4a4bec57", "0xaa058abb1953eceac14ccfa7c0cc482a146e1232905dcecc86dd27f75575285f06bbae16a8c9fe8e35d8713717f5f19f", "0x8f15dd732799c879ca46d2763453b359ff483ca33adb1d0e0a57262352e0476c235987dc3a8a243c74bc768f93d3014c", "0xa61cc8263e9bc03cce985f1663b8a72928a607121005a301b28a278e9654727fd1b22bc8a949af73929c56d9d3d4a273", "0x98d6dc78502d19eb9f921225475a6ebcc7b44f01a2df6f55ccf6908d65b27af1891be2a37735f0315b6e0f1576c1f8d8", "0x8bd258b883f3b3793ec5be9472ad1ff3dc4b51bc5a58e9f944acfb927349ead8231a523cc2175c1f98e7e1e2b9f363b8", "0xaeacc2ecb6e807ad09bedd99654b097a6f39840e932873ace02eabd64ccfbb475abdcb62939a698abf17572d2034c51e", "0xb8ccf78c08ccd8df59fd6eda2e01de328bc6d8a65824d6f1fc0537654e9bc6bf6f89c422dd3a295cce628749da85c864", "0x8f91fd8cb253ba2e71cc6f13da5e05f62c2c3b485c24f5d68397d04665673167fce1fc1aec6085c69e87e66ec555d3fd", "0xa254baa10cb26d04136886073bb4c159af8a8532e3fd36b1e9c3a2e41b5b2b6a86c4ebc14dbe624ee07b7ccdaf59f9ab", "0x94e3286fe5cd68c4c7b9a7d33ae3d714a7f265cf77cd0e9bc19fc51015b1d1c34ad7e3a5221c459e89f5a043ee84e3a9", "0xa279da8878af8d449a9539bec4b17cea94f0242911f66fab275b5143ab040825f78c89cb32a793930609415cfa3a1078", "0xac846ceb89c9e5d43a2991c8443079dc32298cd63e370e64149cec98cf48a6351c09c856f2632fd2f2b3d685a18bbf8b", "0xa847b27995c8a2e2454aaeb983879fb5d3a23105c33175839f7300b7e1e8ec3efd6450e9fa3f10323609dee7b98c6fd5", "0xa2f432d147d904d185ff4b2de8c6b82fbea278a2956bc406855b44c18041854c4f0ecccd472d1d0dff1d8aa8e281cb1d", "0x94a48ad40326f95bd63dff4755f863a1b79e1df771a1173b17937f9baba57b39e651e7695be9f66a472f098b339364fc", "0xa12a0ccd8f96e96e1bc6494341f7ebce959899341b3a084aa1aa87d1c0d489ac908552b7770b887bb47e7b8cbc3d8e66", "0x81a1f1681bda923bd274bfe0fbb9181d6d164fe738e54e25e8d4849193d311e2c4253614ed673c98af2c798f19a93468", "0xabf71106a05d501e84cc54610d349d7d5eae21a70bd0250f1bebbf412a130414d1c8dbe673ffdb80208fd72f1defa4d4", "0x96266dc2e0df18d8136d79f5b59e489978eee0e6b04926687fe389d4293c14f36f055c550657a8e27be4118b64254901", "0x8df5dcbefbfb4810ae3a413ca6b4bf08619ca53cd50eb1dde2a1c035efffc7b7ac7dff18d403253fd80104bd83dc029e", "0x9610b87ff02e391a43324a7122736876d5b3af2a137d749c52f75d07b17f19900b151b7f439d564f4529e77aa057ad12", "0xa90a5572198b40fe2fcf47c422274ff36c9624df7db7a89c0eb47eb48a73a03c985f4ac5016161c76ca317f64339bce1", "0x98e5e61a6ab6462ba692124dba7794b6c6bde4249ab4fcc98c9edd631592d5bc2fb5e38466691a0970a38e48d87c2e43", "0x918cefb8f292f78d4db81462c633daf73b395e772f47b3a7d2cea598025b1d8c3ec0cbff46cdb23597e74929981cde40", "0xa98918a5dc7cf610fe55f725e4fd24ce581d594cb957bb9b4e888672e9c0137003e1041f83e3f1d7b9caab06462c87d4", "0xb92b74ac015262ca66c33f2d950221e19d940ba3bf4cf17845f961dc1729ae227aa9e1f2017829f2135b489064565c29", "0xa053ee339f359665feb178b4e7ee30a85df37debd17cacc5a27d6b3369d170b0114e67ad1712ed26d828f1df641bcd99", "0x8c3c8bad510b35da5ce5bd84b35c958797fbea024ad1c97091d2ff71d9b962e9222f65a9b776e5b3cc29c36e1063d2ee", "0xaf99dc7330fe7c37e850283eb47cc3257888e7c197cb0d102edf94439e1e02267b6a56306d246c326c4c79f9dc8c6986", "0xafecb2dc34d57a725efbd7eb93d61eb29dbe8409b668ab9ea040791f5b796d9be6d4fc10d7f627bf693452f330cf0435", "0x93334fedf19a3727a81a6b6f2459db859186227b96fe7a391263f69f1a0884e4235de64d29edebc7b99c44d19e7c7d7a", "0x89579c51ac405ad7e9df13c904061670ce4b38372492764170e4d3d667ed52e5d15c7cd5c5991bbfa3a5e4e3fa16363e", "0x9778f3e8639030f7ef1c344014f124e375acb8045bd13d8e97a92c5265c52de9d1ffebaa5bc3e1ad2719da0083222991", "0x88f77f34ee92b3d36791bdf3326532524a67d544297dcf1a47ff00b47c1b8219ff11e34034eab7d23b507caa2fd3c6b9", "0xa699c1e654e7c484431d81d90657892efeb4adcf72c43618e71ca7bd7c7a7ebbb1db7e06e75b75dc4c74efd306b5df3f", "0x81d13153baebb2ef672b5bdb069d3cd669ce0be96b742c94e04038f689ff92a61376341366b286eee6bf3ae85156f694", "0x81efb17de94400fdacc1deec2550cbe3eecb27c7af99d8207e2f9be397e26be24a40446d2a09536bb5172c28959318d9", "0x989b21ebe9ceab02488992673dc071d4d5edec24bff0e17a4306c8cb4b3c83df53a2063d1827edd8ed16d6e837f0d222", "0x8d6005d6536825661b13c5fdce177cb37c04e8b109b7eb2b6d82ea1cb70efecf6a0022b64f84d753d165edc2bba784a3", "0xa32607360a71d5e34af2271211652d73d7756d393161f4cf0da000c2d66a84c6826e09e759bd787d4fd0305e2439d342", "0xaaad8d6f6e260db45d51b2da723be6fa832e76f5fbcb77a9a31e7f090dd38446d3b631b96230d78208cae408c288ac4e", "0xabcfe425255fd3c5cffd3a818af7650190c957b6b07b632443f9e33e970a8a4c3bf79ac9b71f4d45f238a04d1c049857", "0xaeabf026d4c783adc4414b5923dbd0be4b039cc7201219f7260d321f55e9a5b166d7b5875af6129c034d0108fdc5d666", "0xaf49e740c752d7b6f17048014851f437ffd17413c59797e5078eaaa36f73f0017c3e7da020310cfe7d3c85f94a99f203", "0x8854ca600d842566e3090040cd66bb0b3c46dae6962a13946f0024c4a8aca447e2ccf6f240045f1ceee799a88cb9210c", "0xb6c03b93b1ab1b88ded8edfa1b487a1ed8bdce8535244dddb558ffb78f89b1c74058f80f4db2320ad060d0c2a9c351cc", "0xb5bd7d17372faff4898a7517009b61a7c8f6f0e7ed4192c555db264618e3f6e57fb30a472d169fea01bf2bf0362a19a8", "0x96eb1d38319dc74afe7e7eb076fcd230d19983f645abd14a71e6103545c01301b31c47ae931e025f3ecc01fb3d2f31fa", "0xb55a8d30d4403067def9b65e16f867299f8f64c9b391d0846d4780bc196569622e7e5b64ce799b5aefac8f965b2a7a7b", "0x8356d199a991e5cbbff608752b6291731b6b6771aed292f8948b1f41c6543e4ab1bedc82dd26d10206c907c03508df06", "0x97f4137445c2d98b0d1d478049de952610ad698c91c9d0f0e7227d2aae690e9935e914ec4a2ea1fbf3fc1dddfeeacebb", "0xaf5621707e0938320b15ddfc87584ab325fbdfd85c30efea36f8f9bd0707d7ec12c344eff3ec21761189518d192df035", "0x8ac7817e71ea0825b292687928e349da7140285d035e1e1abff0c3704fa8453faaae343a441b7143a74ec56539687cc4", "0x8a5e0a9e4758449489df10f3386029ada828d1762e4fb0a8ffe6b79e5b6d5d713cb64ed95960e126398b0cdb89002bc9", "0x81324be4a71208bbb9bca74b77177f8f1abb9d3d5d9db195d1854651f2cf333cd618d35400da0f060f3e1b025124e4b2", "0x849971d9d095ae067525b3cbc4a7dfae81f739537ade6d6cec1b42fb692d923176197a8770907c58069754b8882822d6", "0x89f830825416802477cc81fdf11084885865ee6607aa15aa4eb28e351c569c49b8a1b9b5e95ddc04fa0ebafe20071313", "0x9240aeeaff37a91af55f860b9badd466e8243af9e8c96a7aa8cf348cd270685ab6301bc135b246dca9eda696f8b0e350", "0xacf74db78cc33138273127599eba35b0fb4e7b9a69fe02dae18fc6692d748ca332bd00b22afa8e654ed587aab11833f3", "0xb091e6d37b157b50d76bd297ad752220cd5c9390fac16dc838f8557aed6d9833fc920b61519df21265406216315e883f", "0xa6446c429ebf1c7793c622250e23594c836b2fbcaf6c5b3d0995e1595a37f50ea643f3e549b0be8bbdadd69044d72ab9", "0x93e675353bd60e996bf1c914d5267eeaa8a52fc3077987ccc796710ef9becc6b7a00e3d82671a6bdfb8145ee3c80245a", "0xa2f731e43251d04ed3364aa2f072d05355f299626f2d71a8a38b6f76cf08c544133f7d72dd0ab4162814b674b9fc7fa6", "0x97a8b791a5a8f6e1d0de192d78615d73d0c38f1e557e4e15d15adc663d649e655bc8da3bcc499ef70112eafe7fb45c7a", "0x98cd624cbbd6c53a94469be4643c13130916b91143425bcb7d7028adbbfede38eff7a21092af43b12d4fab703c116359", "0x995783ce38fd5f6f9433027f122d4cf1e1ff3caf2d196ce591877f4a544ce9113ead60de2de1827eaff4dd31a20d79a8", "0x8cf251d6f5229183b7f3fe2f607a90b4e4b6f020fb4ba2459d28eb8872426e7be8761a93d5413640a661d73e34a5b81f", "0xb9232d99620652a3aa7880cad0876f153ff881c4ed4c0c2e7b4ea81d5d42b70daf1a56b869d752c3743c6d4c947e6641", "0x849716f938f9d37250cccb1bf77f5f9fde53096cdfc6f2a25536a6187029a8f1331cdbed08909184b201f8d9f04b792f", "0x80c7c4de098cbf9c6d17b14eba1805e433b5bc905f6096f8f63d34b94734f2e4ebf4bce8a177efd1186842a61204a062", "0xb790f410cf06b9b8daadceeb4fd5ff40a2deda820c8df2537e0a7554613ae3948e149504e3e79aa84889df50c8678eeb", "0x813aab8bd000299cd37485b73cd7cba06e205f8efb87f1efc0bae8b70f6db2bc7702eb39510ad734854fb65515fe9d0f", "0x94f0ab7388ac71cdb67f6b85dfd5945748afb2e5abb622f0b5ad104be1d4d0062b651f134ba22385c9e32c2dfdcccce1", "0xab6223dca8bd6a4f969e21ccd9f8106fc5251d321f9e90cc42cea2424b3a9c4e5060a47eeef6b23c7976109b548498e8", "0x859c56b71343fce4d5c5b87814c47bf55d581c50fd1871a17e77b5e1742f5af639d0e94d19d909ec7dfe27919e954e0c", "0xaae0d632b6191b8ad71b027791735f1578e1b89890b6c22e37de0e4a6074886126988fe8319ae228ac9ef3b3bcccb730", "0x8ca9f32a27a024c3d595ecfaf96b0461de57befa3b331ab71dc110ec3be5824fed783d9516597537683e77a11d334338", "0xa061df379fb3f4b24816c9f6cd8a94ecb89b4c6dc6cd81e4b8096fa9784b7f97ab3540259d1de9c02eb91d9945af4823", "0x998603102ac63001d63eb7347a4bb2bf4cf33b28079bb48a169076a65c20d511ccd3ef696d159e54cc8e772fb5d65d50", "0x94444d96d39450872ac69e44088c252c71f46be8333a608a475147752dbb99db0e36acfc5198f158509401959c12b709", "0xac1b51b6c09fe055c1d7c9176eea9adc33f710818c83a1fbfa073c8dc3a7eb3513cbdd3f5960b7845e31e3e83181e6ba", "0x803d530523fc9e1e0f11040d2412d02baef3f07eeb9b177fa9bfa396af42eea898a4276d56e1db998dc96ae47b644cb2", "0x85a3c9fc7638f5bf2c3e15ba8c2fa1ae87eb1ceb44c6598c67a2948667a9dfa41e61f66d535b4e7fda62f013a5a8b885", "0xa961cf5654c46a1a22c29baf7a4e77837a26b7f138f410e9d1883480ed5fa42411d522aba32040b577046c11f007388e", "0xad1154142344f494e3061ef45a34fab1aaacf5fdf7d1b26adbb5fbc3d795655fa743444e39d9a4119b4a4f82a6f30441", "0xb1d6c30771130c77806e7ab893b73d4deb590b2ff8f2f8b5e54c2040c1f3e060e2bd99afc668cf706a2df666a508bbf6", "0xa00361fd440f9decabd98d96c575cd251dc94c60611025095d1201ef2dedde51cb4de7c2ece47732e5ed9b3526c2012c", "0xa85c5ab4d17d328bda5e6d839a9a6adcc92ff844ec25f84981e4f44a0e8419247c081530f8d9aa629c7eb4ca21affba6", "0xa4ddd3eab4527a2672cf9463db38bc29f61460e2a162f426b7852b7a7645fbd62084fd39a8e4d60e1958cce436dd8f57", "0x811648140080fe55b8618f4cf17f3c5a250adb0cd53d885f2ddba835d2b4433188e41fc0661faac88e4ff910b16278c0", "0xb85c7f1cfb0ed29addccf7546023a79249e8f15ac2d14a20accbfef4dd9dc11355d599815fa09d2b6b4e966e6ea8cff1", "0xa10b5d8c260b159043b020d5dd62b3467df2671afea6d480ca9087b7e60ed170c82b121819d088315902842d66c8fb45", "0x917e191df1bcf3f5715419c1e2191da6b8680543b1ba41fe84ed07ef570376e072c081beb67b375fca3565a2565bcabb", "0x881fd967407390bfd7badc9ab494e8a287559a01eb07861f527207c127eadea626e9bcc5aa9cca2c5112fbac3b3f0e9c", "0x959fd71149af82cc733619e0e5bf71760ca2650448c82984b3db74030d0e10f8ab1ce1609a6de6f470fe8b5bd90df5b3", "0xa3370898a1c5f33d15adb4238df9a6c945f18b9ada4ce2624fc32a844f9ece4c916a64e9442225b6592afa06d2e015f2", "0x817efb8a791435e4236f7d7b278181a5fa34587578c629dbc14fbf9a5c26772290611395eecd20222a4c58649fc256d8", "0xa04c9876acf2cfdc8ef96de4879742709270fa1d03fe4c8511fbef2d59eb0aaf0336fa2c7dfe41a651157377fa217813", "0x81e15875d7ea7f123e418edf14099f2e109d4f3a6ce0eb65f67fe9fb10d2f809a864a29f60ad3fc949f89e2596b21783", "0xb49f529975c09e436e6bc202fdc16e3fdcbe056db45178016ad6fdece9faad4446343e83aed096209690b21a6910724f", "0x879e8eda589e1a279f7f49f6dd0580788c040d973748ec4942dbe51ea8fbd05983cc919b78f0c6b92ef3292ae29db875", "0x81a2b74b2118923f34139a102f3d95e7eee11c4c2929c2576dee200a5abfd364606158535a6c9e4178a6a83dbb65f3c4", "0x8913f281d8927f2b45fc815d0f7104631cb7f5f7278a316f1327d670d15868daadd2a64e3eb98e1f53fe7e300338cc80", "0xa6f815fba7ef9af7fbf45f93bc952e8b351f5de6568a27c7c47a00cb39a254c6b31753794f67940fc7d2e9cc581529f4", "0xb3722a15c66a0014ce4d082de118def8d39190c15678a472b846225585f3a83756ae1b255b2e3f86a26168878e4773b2", "0x817ae61ab3d0dd5b6e24846b5a5364b1a7dc2e77432d9fed587727520ae2f307264ea0948c91ad29f0aea3a11ff38624", "0xb3db467464415fcad36dc1de2d6ba7686772a577cc2619242ac040d6734881a45d3b40ed4588db124e4289cfeec4bbf6", "0xad66a14f5a54ac69603b16e5f1529851183da77d3cc60867f10aea41339dd5e06a5257982e9e90a352cdd32750f42ee4", "0xadafa3681ef45d685555601a25a55cf23358319a17f61e2179e704f63df83a73bdd298d12cf6cef86db89bd17119e11d", "0xa379dc44cb6dd3b9d378c07b2ec654fec7ca2f272de6ba895e3d00d20c9e4c5550498a843c8ac67e4221db2115bedc1c", "0xb7bf81c267a78efc6b9e5a904574445a6487678d7ef70054e3e93ea6a23f966c2b68787f9164918e3b16d2175459ed92", "0xb41d66a13a4afafd5760062b77f79de7e6ab8ccacde9c6c5116a6d886912fb491dc027af435b1b44aacc6af7b3c887f2", "0x9904d23a7c1c1d2e4bab85d69f283eb0a8e26d46e8b7b30224438015c936729b2f0af7c7c54c03509bb0500acb42d8a4", "0xae30d65e9e20c3bfd603994ae2b175ff691d51f3e24b2d058b3b8556d12ca4c75087809062dddd4aaac81c94d15d8a17", "0x9245162fab42ac01527424f6013310c3eb462982518debef6c127f46ba8a06c705d7dc9f0a41e796ba8d35d60ae6cc64", "0x87fab853638d7a29a20f3ba2b1a7919d023e9415bfa78ebb27973d8cbc7626f584dc5665d2e7ad71f1d760eba9700d88", "0x85aac46ecd330608e5272430970e6081ff02a571e8ea444f1e11785ea798769634a22a142d0237f67b75369d3c484a8a", "0x938c85ab14894cc5dfce3d80456f189a2e98eddbc8828f4ff6b1df1dcb7b42b17ca2ff40226a8a1390a95d63dca698dd", "0xa18ce1f846e3e3c4d846822f60271eecf0f5d7d9f986385ac53c5ace9589dc7c0188910448c19b91341a1ef556652fa9", "0x8611608a9d844f0e9d7584ad6ccf62a5087a64f764caf108db648a776b5390feb51e5120f0ef0e9e11301af3987dd7dc", "0x8106333ba4b4de8d1ae43bc9735d3fea047392e88efd6a2fa6f7b924a18a7a265ca6123c3edc0f36307dd7fb7fe89257", "0xa91426fa500951ff1b051a248c050b7139ca30dde8768690432d597d2b3c4357b11a577be6b455a1c5d145264dcf81fc", "0xb7f9f90e0e450f37b081297f7f651bad0496a8b9afd2a4cf4120a2671aaaa8536dce1af301258bfbfdb122afa44c5048", "0x84126da6435699b0c09fa4032dec73d1fca21d2d19f5214e8b0bea43267e9a8dd1fc44f8132d8315e734c8e2e04d7291", "0xaff064708103884cb4f1a3c1718b3fc40a238d35cf0a7dc24bdf9823693b407c70da50df585bf5bc4e9c07d1c2d203e8", "0xa8b40fc6533752983a5329c31d376c7a5c13ce6879cc7faee648200075d9cd273537001fb4c86e8576350eaac6ba60c2", "0xa02db682bdc117a84dcb9312eb28fcbde12d49f4ce915cc92c610bb6965ec3cc38290f8c5b5ec70afe153956692cda95", "0x86decd22b25d300508472c9ce75d3e465b737e7ce13bc0fcce32835e54646fe12322ba5bc457be18bfd926a1a6ca4a38", "0xa18666ef65b8c2904fd598791f5627207165315a85ee01d5fb0e6b2e10bdd9b00babc447da5bd63445e3337de33b9b89", "0x89bb0c06effadefdaf34ffe4b123e1678a90d4451ee856c863df1e752eef41fd984689ded8f0f878bf8916d5dd8e8024", "0x97cfcba08ebec05d0073992a66b1d7d6fb9d95871f2cdc36db301f78bf8069294d1c259efef5c93d20dc937eedae3a1a", "0xac2643b14ece79dcb2e289c96776a47e2bebd40dd6dc74fd035df5bb727b5596f40e3dd2d2202141e69b0993717ede09", "0xa5e6fd88a2f9174d9bd4c6a55d9c30974be414992f22aa852f552c7648f722ed8077acf5aba030abd47939bb451b2c60", "0x8ad40a612824a7994487731a40b311b7349038c841145865539c6ada75c56de6ac547a1c23df190e0caaafecddd80ccc", "0x953a7cea1d857e09202c438c6108060961f195f88c32f0e012236d7a4b39d840c61b162ec86436e8c38567328bea0246", "0x80d8b47a46dae1868a7b8ccfe7029445bbe1009dad4a6c31f9ef081be32e8e1ac1178c3c8fb68d3e536c84990cc035b1", "0x81ecd99f22b3766ce0aca08a0a9191793f68c754fdec78b82a4c3bdc2db122bbb9ebfd02fc2dcc6e1567a7d42d0cc16a", "0xb1dd0446bccc25846fb95d08c1c9cc52fb51c72c4c5d169ffde56ecfe800f108dc1106d65d5c5bd1087c656de3940b63", "0xb87547f0931e164e96de5c550ca5aa81273648fe34f6e193cd9d69cf729cb432e17aa02e25b1c27a8a0d20a3b795e94e", "0x820a94e69a927e077082aae66f6b292cfbe4589d932edf9e68e268c9bd3d71ef76cf7d169dd445b93967c25db11f58f1", "0xb0d07ddf2595270c39adfa0c8cf2ab1322979b0546aa4d918f641be53cd97f36c879bb75d205e457c011aca3bbd9f731", "0x8700b876b35b4b10a8a9372c5230acecd39539c1bb87515640293ad4464a9e02929d7d6a6a11112e8a29564815ac0de4", "0xa61a601c5bb27dcb97e37c8e2b9ce479c6b192a5e04d9ed5e065833c5a1017ee5f237b77d1a17be5d48f8e7cc0bcacf6", "0x92fb88fe774c1ba1d4a08cae3c0e05467ad610e7a3f1d2423fd47751759235fe0a3036db4095bd6404716aa03820f484", "0xb274f140d77a3ce0796f5e09094b516537ccaf27ae1907099bff172e6368ba85e7c3ef8ea2a07457cac48ae334da95b3", "0xb2292d9181f16581a9a9142490b2bdcdfb218ca6315d1effc8592100d792eb89d5356996c890441f04f2b4a95763503e", "0x8897e73f576d86bc354baa3bd96e553107c48cf5889dcc23c5ba68ab8bcd4e81f27767be2233fdfa13d39f885087e668", "0xa29eac6f0829791c728d71abc49569df95a4446ecbfc534b39f24f56c88fe70301838dfc1c19751e7f3c5c1b8c6af6a0", "0x9346dc3720adc5df500a8df27fd9c75ef38dc5c8f4e8ed66983304750e66d502c3c59b8e955be781b670a0afc70a2167", "0x9566d534e0e30a5c5f1428665590617e95fd05d45f573715f58157854ad596ece3a3cfec61356aee342308d623e029d5", "0xa464fb8bffe6bd65f71938c1715c6e296cc6d0311a83858e4e7eb5873b7f2cf0c584d2101e3407b85b64ca78b2ac93ce", "0xb54088f7217987c87e9498a747569ac5b2f8afd5348f9c45bf3fd9fbf713a20f495f49c8572d087efe778ac7313ad6d3", "0x91fa9f5f8000fe050f5b224d90b59fcce13c77e903cbf98ded752e5b3db16adb2bc1f8c94be48b69f65f1f1ad81d6264", "0x92d04a5b0ac5d8c8e313709b432c9434ecd3e73231f01e9b4e7952b87df60cbfa97b5dedd2200bd033b4b9ea8ba45cc1", "0xa94b90ad3c3d6c4bbe169f8661a790c40645b40f0a9d1c7220f01cf7fc176e04d80bab0ced9323fcafb93643f12b2760", "0x94d86149b9c8443b46196f7e5a3738206dd6f3be7762df488bcbb9f9ee285a64c997ed875b7b16b26604fa59020a8199", "0x82efe4ae2c50a2d7645240c173a047f238536598c04a2c0b69c96e96bd18e075a99110f1206bc213f39edca42ba00cc1", "0xab8667685f831bc14d4610f84a5da27b4ea5b133b4d991741a9e64dceb22cb64a3ce8f1b6e101d52af6296df7127c9ad", "0x83ba433661c05dcc5d562f4a9a261c8110dac44b8d833ae1514b1fc60d8b4ee395b18804baea04cb10adb428faf713c3", "0xb5748f6f660cc5277f1211d2b8649493ed8a11085b871cd33a5aea630abd960a740f08c08be5f9c21574600ac9bf5737", "0xa5c8dd12af48fb710642ad65ebb97ca489e8206741807f7acfc334f8035d3c80593b1ff2090c9bb7bd138f0c48714ca8", "0xa2b382fd5744e3babf454b1d806cc8783efeb4761bc42b6914ea48a46a2eae835efbe0a18262b6bc034379e03cf1262b", "0xb3145ffaf603f69f15a64936d32e3219eea5ed49fdfd2f5bf40ea0dfd974b36fb6ff12164d4c2282d892db4cf3ff3ce1", "0x87a316fb213f4c5e30c5e3face049db66be4f28821bd96034714ec23d3e97849d7b301930f90a4323c7ccf53de23050c", "0xb9de09a919455070fed6220fc179c8b7a4c753062bcd27acf28f5b9947a659c0b364298daf7c85c4ca6fca7f945add1f", "0x806fbd98d411b76979464c40ad88bc07a151628a27fcc1012ba1dfbaf5b5cc9d962fb9b3386008978a12515edce934bc", "0xa15268877fae0d21610ae6a31061ed7c20814723385955fac09fdc9693a94c33dea11db98bb89fdfe68f933490f5c381", "0x8d633fb0c4da86b2e0b37d8fad5972d62bff2ac663c5ec815d095cd4b7e1fe66ebef2a2590995b57eaf941983c7ad7a4", "0x8139e5dd9cf405e8ef65f11164f0440827d98389ce1b418b0c9628be983a9ddd6cf4863036ccb1483b40b8a527acd9ed", "0x88b15fa94a08eac291d2b94a2b30eb851ff24addf2cc30b678e72e32cfcb3424cf4b33aa395d741803f3e578ddf524de", "0xb5eaf0c8506e101f1646bcf049ee38d99ea1c60169730da893fd6020fd00a289eb2f415947e44677af49e43454a7b1be", "0x8489822ad0647a7e06aa2aa5595960811858ddd4542acca419dd2308a8c5477648f4dd969a6740bb78aa26db9bfcc555", "0xb1e9a7b9f3423c220330d45f69e45fa03d7671897cf077f913c252e3e99c7b1b1cf6d30caad65e4228d5d7b80eb86e5e", "0xb28fe9629592b9e6a55a1406903be76250b1c50c65296c10c5e48c64b539fb08fe11f68cf462a6edcbba71b0cee3feb2", "0xa41acf96a02c96cd8744ff6577c244fc923810d17ade133587e4c223beb7b4d99fa56eae311a500d7151979267d0895c", "0x880798938fe4ba70721be90e666dfb62fcab4f3556fdb7b0dc8ec5bc34f6b4513df965eae78527136eb391889fe2caf9", "0x98d4d89d358e0fb7e212498c73447d94a83c1b66e98fc81427ab13acddb17a20f52308983f3a5a8e0aaacec432359604", "0x81430b6d2998fc78ba937a1639c6020199c52da499f68109da227882dc26d005b73d54c5bdcac1a04e8356a8ca0f7017", "0xa8d906a4786455eb74613aba4ce1c963c60095ffb8658d368df9266fdd01e30269ce10bf984e7465f34b4fd83beba26a", "0xaf54167ac1f954d10131d44a8e0045df00d581dd9e93596a28d157543fbe5fb25d213806ed7fb3cba6b8f5b5423562db", "0x8511e373a978a12d81266b9afbd55035d7bc736835cfa921903a92969eeba3624437d1346b55382e61415726ab84a448", "0x8cf43eea93508ae586fa9a0f1354a1e16af659782479c2040874a46317f9e8d572a23238efa318fdfb87cc63932602b7", "0xb0bdd3bacff077173d302e3a9678d1d37936188c7ecc34950185af6b462b7c679815176f3cce5db19aac8b282f2d60ad", "0xa355e9b87f2f2672052f5d4d65b8c1c827d24d89b0d8594641fccfb69aef1b94009105f3242058bb31c8bf51caae5a41", "0xb8baa9e4b950b72ff6b88a6509e8ed1304bc6fd955748b2e59a523a1e0c5e99f52aec3da7fa9ff407a7adf259652466c", "0x840bc3dbb300ea6f27d1d6dd861f15680bd098be5174f45d6b75b094d0635aced539fa03ddbccb453879de77fb5d1fe9", "0xb4bc7e7e30686303856472bae07e581a0c0bfc815657c479f9f5931cff208d5c12930d2fd1ff413ebd8424bcd7a9b571", "0x89b5d514155d7999408334a50822508b9d689add55d44a240ff2bdde2eee419d117031f85e924e2a2c1ca77db9b91eea", "0xa8604b6196f87a04e1350302e8aa745bba8dc162115d22657b37a1d1a98cb14876ddf7f65840b5dbd77e80cd22b4256c", "0x83cb7acdb9e03247515bb2ce0227486ccf803426717a14510f0d59d45e998b245797d356f10abca94f7a14e1a2f0d552", "0xaeb3266a9f16649210ab2df0e1908ac259f34ce1f01162c22b56cf1019096ee4ea5854c36e30bb2feb06c21a71e8a45c", "0x89e72e86edf2aa032a0fc9acf4d876a40865fbb2c8f87cb7e4d88856295c4ac14583e874142fd0c314a49aba68c0aa3c", "0x8c3576eba0583c2a7884976b4ed11fe1fda4f6c32f6385d96c47b0e776afa287503b397fa516a455b4b8c3afeedc76db", "0xa31e5b633bda9ffa174654fee98b5d5930a691c3c42fcf55673d927dbc8d91c58c4e42e615353145431baa646e8bbb30", "0x89f2f3f7a8da1544f24682f41c68114a8f78c86bd36b066e27da13acb70f18d9f548773a16bd8e24789420e17183f137", "0xada27fa4e90a086240c9164544d2528621a415a5497badb79f8019dc3dce4d12eb6b599597e47ec6ac39c81efda43520", "0x90dc1eb21bf21c0187f359566fc4bf5386abea52799306a0e5a1151c0817c5f5bc60c86e76b1929c092c0f3ff48cedd2", "0xb702a53ebcc17ae35d2e735a347d2c700e9cbef8eadbece33cac83df483b2054c126593e1f462cfc00a3ce9d737e2af5", "0x9891b06455ec925a6f8eafffba05af6a38cc5e193acaaf74ffbf199df912c5197106c5e06d72942bbb032ce277b6417f", "0x8c0ee71eb01197b019275bcf96cae94e81d2cdc3115dbf2d8e3080074260318bc9303597e8f72b18f965ad601d31ec43", "0x8aaf580aaf75c1b7a5f99ccf60503506e62058ef43b28b02f79b8536a96be3f019c9f71caf327b4e6730134730d1bef5", "0xae6f9fc21dd7dfa672b25a87eb0a41644f7609fab5026d5cedb6e43a06dbbfd6d6e30322a2598c8dedde88c52eaed626", "0x8159b953ffece5693edadb2e906ebf76ff080ee1ad22698950d2d3bfc36ac5ea78f58284b2ca180664452d55bd54716c", "0xab7647c32ca5e9856ac283a2f86768d68de75ceeba9e58b74c5324f8298319e52183739aba4340be901699d66ac9eb3f", "0xa4d85a5701d89bcfaf1572db83258d86a1a0717603d6f24ac2963ffcf80f1265e5ab376a4529ca504f4396498791253c", "0x816080c0cdbfe61b4d726c305747a9eb58ac26d9a35f501dd32ba43c098082d20faf3ccd41aad24600aa73bfa453dfac", "0x84f3afac024f576b0fd9acc6f2349c2fcefc3f77dbe5a2d4964d14b861b88e9b1810334b908cf3427d9b67a8aee74b18", "0x94b390655557b1a09110018e9b5a14490681ade275bdc83510b6465a1218465260d9a7e2a6e4ec700f58c31dc3659962", "0xa8c66826b1c04a2dd4c682543242e7a57acae37278bd09888a3d17747c5b5fec43548101e6f46d703638337e2fd3277b", "0x86e6f4608a00007fa533c36a5b054c5768ccafe41ad52521d772dcae4c8a4bcaff8f7609be30d8fab62c5988cbbb6830", "0x837da4cf09ae8aa0bceb16f8b3bfcc3b3367aecac9eed6b4b56d7b65f55981ef066490764fb4c108792623ecf8cad383", "0x941ff3011462f9b5bf97d8cbdb0b6f5d37a1b1295b622f5485b7d69f2cb2bcabc83630dae427f0259d0d9539a77d8424", "0xb99e5d6d82aa9cf7d5970e7f710f4039ac32c2077530e4c2779250c6b9b373bc380adb0a03b892b652f649720672fc8c", "0xa791c78464b2d65a15440b699e1e30ebd08501d6f2720adbc8255d989a82fcded2f79819b5f8f201bed84a255211b141", "0x84af7ad4a0e31fcbb3276ab1ad6171429cf39adcf78dc03750dc5deaa46536d15591e26d53e953dfb31e1622bc0743ab", "0xa833e62fe97e1086fae1d4917fbaf09c345feb6bf1975b5cb863d8b66e8d621c7989ab3dbecda36bc9eaffc5eaa6fa66", "0xb4ef79a46a2126f53e2ebe62770feb57fd94600be29459d70a77c5e9cc260fa892be06cd60f886bf48459e48eb50d063", "0xb43b8f61919ea380bf151c294e54d3a3ff98e20d1ee5efbfe38aa2b66fafbc6a49739793bd5cb1c809f8b30466277c3a", "0xab37735af2412d2550e62df9d8b3b5e6f467f20de3890bf56faf1abf2bf3bd1d98dc3fa0ad5e7ab3fce0fa20409eb392", "0x82416b74b1551d484250d85bb151fabb67e29cce93d516125533df585bc80779ab057ea6992801a3d7d5c6dcff87a018", "0x8145d0787f0e3b5325190ae10c1d6bee713e6765fb6a0e9214132c6f78f4582bb2771aaeae40d3dad4bafb56bf7e36d8", "0xb6935886349ecbdd5774e12196f4275c97ec8279fdf28ccf940f6a022ebb6de8e97d6d2173c3fe402cbe9643bed3883b", "0x87ef9b4d3dc71ac86369f8ed17e0dd3b91d16d14ae694bc21a35b5ae37211b043d0e36d8ff07dcc513fb9e6481a1f37f", "0xae1d0ded32f7e6f1dc8fef495879c1d9e01826f449f903c1e5034aeeabc5479a9e323b162b688317d46d35a42d570d86", "0xa40d16497004db4104c6794e2f4428d75bdf70352685944f3fbe17526df333e46a4ca6de55a4a48c02ecf0bde8ba03c0", "0x8d45121efba8cc308a498e8ee39ea6fa5cae9fb2e4aab1c2ff9d448aa8494ccbec9a078f978a86fcd97b5d5e7be7522a", "0xa8173865c64634ba4ac2fa432740f5c05056a9deaf6427cb9b4b8da94ca5ddbc8c0c5d3185a89b8b28878194de9cdfcd", "0xb6ec06a74d690f6545f0f0efba236e63d1fdfba54639ca2617408e185177ece28901c457d02b849fd00f1a53ae319d0a", "0xb69a12df293c014a40070e3e760169b6f3c627caf9e50b35a93f11ecf8df98b2bc481b410eecb7ab210bf213bbe944de", "0x97e7dc121795a533d4224803e591eef3e9008bab16f12472210b73aaf77890cf6e3877e0139403a0d3003c12c8f45636", "0xacdfa6fdd4a5acb7738cc8768f7cba84dbb95c639399b291ae8e4e63df37d2d4096900a84d2f0606bf534a9ccaa4993f", "0x86ee253f3a9446a33e4d1169719b7d513c6b50730988415382faaf751988c10a421020609f7bcdef91be136704b906e2", "0xaac9438382a856caf84c5a8a234282f71b5fc5f65219103b147e7e6cf565522285fbfd7417b513bdad8277a00f652ca1", "0x83f3799d8e5772527930f5dc071a2e0a65471618993ec8990a96ccdeee65270e490bda9d26bb877612475268711ffd80", "0x93f28a81ac8c0ec9450b9d762fae9c7f8feaace87a6ee6bd141ef1d2d0697ef1bbd159fe6e1de640dbdab2b0361fca8a", "0xa0825c95ba69999b90eac3a31a3fd830ea4f4b2b7409bde5f202b61d741d6326852ce790f41de5cb0eccec7af4db30c1", "0x83924b0e66233edd603c3b813d698daa05751fc34367120e3cf384ea7432e256ccee4d4daf13858950549d75a377107d", "0x956fd9fa58345277e06ba2ec72f49ed230b8d3d4ff658555c52d6cddeb84dd4e36f1a614f5242d5ca0192e8daf0543c2", "0x944869912476baae0b114cced4ff65c0e4c90136f73ece5656460626599051b78802df67d7201c55d52725a97f5f29fe", "0x865cb25b64b4531fb6fe4814d7c8cd26b017a6c6b72232ff53defc18a80fe3b39511b23f9e4c6c7249d06e03b2282ed2", "0x81e09ff55214960775e1e7f2758b9a6c4e4cd39edf7ec1adfaad51c52141182b79fe2176b23ddc7df9fd153e5f82d668", "0xb31006896f02bc90641121083f43c3172b1039334501fbaf1672f7bf5d174ddd185f945adf1a9c6cf77be34c5501483d", "0x88b92f6f42ae45e9f05b16e52852826e933efd0c68b0f2418ac90957fd018df661bc47c8d43c2a7d7bfcf669dab98c3c", "0x92fc68f595853ee8683930751789b799f397135d002eda244fe63ecef2754e15849edde3ba2f0cc8b865c9777230b712", "0x99ca06a49c5cd0bb097c447793fcdd809869b216a34c66c78c7e41e8c22f05d09168d46b8b1f3390db9452d91bc96dea", "0xb48b9490a5d65296802431852d548d81047bbefc74fa7dc1d4e2a2878faacdfcb365ae59209cb0ade01901a283cbd15d", "0xaff0fdbef7c188b120a02bc9085d7b808e88f73973773fef54707bf2cd772cd066740b1b6f4127b5c349f657bd97e738", "0x966fd4463b4f43dd8ccba7ad50baa42292f9f8b2e70da23bb6780e14155d9346e275ef03ddaf79e47020dcf43f3738bd", "0x9330c3e1fadd9e08ac85f4839121ae20bbeb0a5103d84fa5aadbd1213805bdcda67bf2fb75fc301349cbc851b5559d20", "0x993bb99867bd9041a71a55ad5d397755cfa7ab6a4618fc526179bfc10b7dc8b26e4372fe9a9b4a15d64f2b63c1052dda", "0xa29b59bcfab51f9b3c490a3b96f0bf1934265c315349b236012adbd64a56d7f6941b2c8cc272b412044bc7731f71e1dc", "0xa65c9cefe1fc35d089fe8580c2e7671ebefdb43014ac291528ff4deefd4883fd4df274af83711dad610dad0d615f9d65", "0x944c78c56fb227ae632805d448ca3884cd3d2a89181cead3d2b7835e63297e6d740aa79a112edb1d4727824991636df5", "0xa73d782da1db7e4e65d7b26717a76e16dd9fab4df65063310b8e917dc0bc24e0d6755df5546c58504d04d9e68c3b474a", "0xaf80f0b87811ae3124f68108b4ca1937009403f87928bbc53480e7c5408d072053ace5eeaf5a5aba814dab8a45502085", "0x88aaf1acfc6e2e19b8387c97da707cb171c69812fefdd4650468e9b2c627bd5ccfb459f4d8e56bdfd84b09ddf87e128f", "0x92c97276ff6f72bab6e9423d02ad6dc127962dbce15a0dd1e4a393b4510c555df6aa27be0f697c0d847033a9ca8b8dfd", "0xa0e07d43d96e2d85b6276b3c60aadb48f0aedf2de8c415756dc597249ea64d2093731d8735231dadc961e5682ac59479", "0xadc9e6718a8f9298957d1da3842a7751c5399bbdf56f8de6c1c4bc39428f4aee6f1ba6613d37bf46b9403345e9d6fc81", "0x951da434da4b20d949b509ceeba02e24da7ed2da964c2fcdf426ec787779c696b385822c7dbea4df3e4a35921f1e912c", "0xa04cbce0d2b2e87bbf038c798a12ec828423ca6aca08dc8d481cf6466e3c9c73d4d4a7fa47df9a7e2e15aae9e9f67208", "0x8f855cca2e440d248121c0469de1f94c2a71b8ee2682bbad3a78243a9e03da31d1925e6760dbc48a1957e040fae9abe8", "0xb642e5b17c1df4a4e101772d73851180b3a92e9e8b26c918050f51e6dd3592f102d20b0a1e96f0e25752c292f4c903ff", "0xa92454c300781f8ae1766dbbb50a96192da7d48ef4cbdd72dd8cbb44c6eb5913c112cc38e9144615fdc03684deb99420", "0x8b74f7e6c2304f8e780df4649ef8221795dfe85fdbdaa477a1542d135b75c8be45bf89adbbb6f3ddf54ca40f02e733e9", "0x85cf66292cbb30cec5fd835ab10c9fcb3aea95e093aebf123e9a83c26f322d76ebc89c4e914524f6c5f6ee7d74fc917d", "0xae0bfe0cdc97c09542a7431820015f2d16067b30dca56288013876025e81daa8c519e5e347268e19aa1a85fa1dc28793", "0x921322fc6a47dc091afa0ad6df18ed14cde38e48c6e71550aa513918b056044983aee402de21051235eecf4ce8040fbe", "0x96c030381e97050a45a318d307dcb3c8377b79b4dd5daf6337cded114de26eb725c14171b9b8e1b3c08fe1f5ea6b49e0", "0x90c23b86b6111818c8baaf53a13eaee1c89203b50e7f9a994bf0edf851919b48edbac7ceef14ac9414cf70c486174a77", "0x8bf6c301240d2d1c8d84c71d33a6dfc6d9e8f1cfae66d4d0f7a256d98ae12b0bcebfa94a667735ee89f810bcd7170cff", "0xa41a4ffbbea0e36874d65c009ee4c3feffff322f6fc0e30d26ee4dbc1f46040d05e25d9d0ecb378cef0d24a7c2c4b850", "0xa8d4cdd423986bb392a0a92c12a8bd4da3437eec6ef6af34cf5310944899287452a2eb92eb5386086d5063381189d10e", "0xa81dd26ec057c4032a4ed7ad54d926165273ed51d09a1267b2e477535cf6966835a257c209e4e92d165d74fa75695fa3", "0x8d7f708c3ee8449515d94fc26b547303b53d8dd55f177bc3b25d3da2768accd9bc8e9f09546090ebb7f15c66e6c9c723", "0x839ba65cffcd24cfffa7ab3b21faabe3c66d4c06324f07b2729c92f15cad34e474b0f0ddb16cd652870b26a756b731d3", "0x87f1a3968afec354d92d77e2726b702847c6afcabb8438634f9c6f7766de4c1504317dc4fa9a4a735acdbf985e119564", "0x91a8a7fd6542f3e0673f07f510d850864b34ac087eb7eef8845a1d14b2b1b651cbdc27fa4049bdbf3fea54221c5c8549", "0xaef3cf5f5e3a2385ead115728d7059e622146c3457d266c612e778324b6e06fbfb8f98e076624d2f3ce1035d65389a07", "0x819915d6232e95ccd7693fdd78d00492299b1983bc8f96a08dcb50f9c0a813ed93ae53c0238345d5bea0beda2855a913", "0x8e9ba68ded0e94935131b392b28218315a185f63bf5e3c1a9a9dd470944509ca0ba8f6122265f8da851b5cc2abce68f1", "0xb28468e9b04ee9d69003399a3cf4457c9bf9d59f36ab6ceeb8e964672433d06b58beeea198fedc7edbaa1948577e9fa2", "0xa633005e2c9f2fd94c8bce2dd5bb708fe946b25f1ec561ae65e54e15cdd88dc339f1a083e01f0d39610c8fe24151aaf0", "0x841d0031e22723f9328dd993805abd13e0c99b0f59435d2426246996b08d00ce73ab906f66c4eab423473b409e972ce0", "0x85758d1b084263992070ec8943f33073a2d9b86a8606672550c17545507a5b3c88d87382b41916a87ee96ff55a7aa535", "0x8581b06b0fc41466ef94a76a1d9fb8ae0edca6d018063acf6a8ca5f4b02d76021902feba58972415691b4bdbc33ae3b4", "0x83539597ff5e327357ee62bc6bf8c0bcaec2f227c55c7c385a4806f0d37fb461f1690bad5066b8a5370950af32fafbef", "0xaee3557290d2dc10827e4791d00e0259006911f3f3fce4179ed3c514b779160613eca70f720bff7804752715a1266ffa", "0xb48d2f0c4e90fc307d5995464e3f611a9b0ef5fe426a289071f4168ed5cc4f8770c9332960c2ca5c8c427f40e6bb389f", "0x847af8973b4e300bb06be69b71b96183fd1a0b9d51b91701bef6fcfde465068f1eb2b1503b07afda380f18d69de5c9e1", "0xa70a6a80ce407f07804c0051ac21dc24d794b387be94eb24e1db94b58a78e1bcfb48cd0006db8fc1f9bedaece7a44fbe", "0xb40e942b8fa5336910ff0098347df716bff9d1fa236a1950c16eeb966b3bc1a50b8f7b0980469d42e75ae13ced53cead", "0xb208fabaa742d7db3148515330eb7a3577487845abdb7bd9ed169d0e081db0a5816595c33d375e56aeac5b51e60e49d3", "0xb7c8194b30d3d6ef5ab66ec88ad7ebbc732a3b8a41731b153e6f63759a93f3f4a537eab9ad369705bd730184bdbbdc34", "0x9280096445fe7394d04aa1bc4620c8f9296e991cc4d6c131bd703cb1cc317510e6e5855ac763f4d958c5edfe7eebeed7", "0xabc2aa4616a521400af1a12440dc544e3c821313d0ab936c86af28468ef8bbe534837e364598396a81cf8d06274ed5a6", "0xb18ca8a3325adb0c8c18a666d4859535397a1c3fe08f95eebfac916a7a99bbd40b3c37b919e8a8ae91da38bc00fa56c0", "0x8a40c33109ecea2a8b3558565877082f79121a432c45ec2c5a5e0ec4d1c203a6788e6b69cb37f1fd5b8c9a661bc5476d", "0x88c47301dd30998e903c84e0b0f2c9af2e1ce6b9f187dab03528d44f834dc991e4c86d0c474a2c63468cf4020a1e24a0", "0x920c832853e6ab4c851eecfa9c11d3acc7da37c823be7aa1ab15e14dfd8beb5d0b91d62a30cec94763bd8e4594b66600", "0x98e1addbe2a6b8edc7f12ecb9be81c3250aeeca54a1c6a7225772ca66549827c15f3950d01b8eb44aecb56fe0fff901a", "0x8cfb0fa1068be0ec088402f5950c4679a2eb9218c729da67050b0d1b2d7079f3ddf4bf0f57d95fe2a8db04bc6bcdb20c", "0xb70f381aafe336b024120453813aeab70baac85b9c4c0f86918797b6aee206e6ed93244a49950f3d8ec9f81f4ac15808", "0xa4c8edf4aa33b709a91e1062939512419711c1757084e46f8f4b7ed64f8e682f4e78b7135920c12f0eb0422fe9f87a6a", "0xb4817e85fd0752d7ebb662d3a51a03367a84bac74ebddfba0e5af5e636a979500f72b148052d333b3dedf9edd2b4031b", "0xa87430169c6195f5d3e314ff2d1c2f050e766fd5d2de88f5207d72dba4a7745bb86d0baca6e9ae156582d0d89e5838c7", "0x991b00f8b104566b63a12af4826b61ce7aa40f4e5b8fff3085e7a99815bdb4471b6214da1e480214fac83f86a0b93cc5", "0xb39966e3076482079de0678477df98578377a094054960ee518ef99504d6851f8bcd3203e8da5e1d4f6f96776e1fe6eb", "0xa448846d9dc2ab7a0995fa44b8527e27f6b3b74c6e03e95edb64e6baa4f1b866103f0addb97c84bef1d72487b2e21796", "0x894bec21a453ae84b592286e696c35bc30e820e9c2fd3e63dd4fbe629e07df16439c891056070faa490155f255bf7187", "0xa9ec652a491b11f6a692064e955f3f3287e7d2764527e58938571469a1e29b5225b9415bd602a45074dfbfe9c131d6ca", "0xb39d37822e6cbe28244b5f42ce467c65a23765bd16eb6447c5b3e942278069793763483dafd8c4dd864f8917aad357fe", "0x88dba51133f2019cb266641c56101e3e5987d3b77647a2e608b5ff9113dfc5f85e2b7c365118723131fbc0c9ca833c9c", "0xb566579d904b54ecf798018efcb824dccbebfc6753a0fd2128ac3b4bd3b038c2284a7c782b5ca6f310eb7ea4d26a3f0a", "0xa97a55c0a492e53c047e7d6f9d5f3e86fb96f3dddc68389c0561515343b66b4bc02a9c0d5722dff1e3445308240b27f7", "0xa044028ab4bcb9e1a2b9b4ca4efbf04c5da9e4bf2fff0e8bd57aa1fc12a71e897999c25d9117413faf2f45395dee0f13", "0xa78dc461decbeaeed8ebd0909369b491a5e764d6a5645a7dac61d3140d7dc0062526f777b0eb866bff27608429ebbdde", "0xb2c2a8991f94c39ca35fea59f01a92cb3393e0eccb2476dfbf57261d406a68bd34a6cff33ed80209991688c183609ef4", "0x84189eefb521aff730a4fd3fd5b10ddfd29f0d365664caef63bb015d07e689989e54c33c2141dd64427805d37a7e546e", "0x85ac80bd734a52235da288ff042dea9a62e085928954e8eacd2c751013f61904ed110e5b3afe1ab770a7e6485efb7b5e", "0x9183a560393dcb22d0d5063e71182020d0fbabb39e32493eeffeb808df084aa243eb397027f150b55a247d1ed0c8513e", "0x81c940944df7ecc58d3c43c34996852c3c7915ed185d7654627f7af62abae7e0048dd444a6c09961756455000bd96d09", "0xaa8c34e164019743fd8284b84f06c3b449aae7996e892f419ee55d82ad548cb300fd651de329da0384243954c0ef6a60", "0x89a7b7bdfc7e300d06a14d463e573d6296d8e66197491900cc9ae49504c4809ff6e61b758579e9091c61085ba1237b83", "0x878d21809ba540f50bd11f4c4d9590fb6f3ab9de5692606e6e2ef4ed9d18520119e385be5e1f4b3f2e2b09c319f0e8fc", "0x8eb248390193189cf0355365e630b782cd15751e672dc478b39d75dc681234dcd9309df0d11f4610dbb249c1e6be7ef9", "0xa1d7fb3aecb896df3a52d6bd0943838b13f1bd039c936d76d03de2044c371d48865694b6f532393b27fd10a4cf642061", "0xa34bca58a24979be442238cbb5ece5bee51ae8c0794dd3efb3983d4db713bc6f28a96e976ac3bd9a551d3ed9ba6b3e22", "0x817c608fc8cacdd178665320b5a7587ca21df8bdd761833c3018b967575d25e3951cf3d498a63619a3cd2ad4406f5f28", "0x86c95707db0495689afd0c2e39e97f445f7ca0edffad5c8b4cacd1421f2f3cc55049dfd504f728f91534e20383955582", "0x99c3b0bb15942c301137765d4e19502f65806f3b126dc01a5b7820c87e8979bce6a37289a8f6a4c1e4637227ad5bf3bf", "0x8aa1518a80ea8b074505a9b3f96829f5d4afa55a30efe7b4de4e5dbf666897fdd2cf31728ca45921e21a78a80f0e0f10", "0x8d74f46361c79e15128ac399e958a91067ef4cec8983408775a87eca1eed5b7dcbf0ddf30e66f51780457413496c7f07", "0xa41cde4a786b55387458a1db95171aca4fd146507b81c4da1e6d6e495527c3ec83fc42fad1dfe3d92744084a664fd431", "0x8c352852c906fae99413a84ad11701f93f292fbf7bd14738814f4c4ceab32db02feb5eb70bc73898b0bc724a39d5d017", "0xa5993046e8f23b71ba87b7caa7ace2d9023fb48ce4c51838813174880d918e9b4d2b0dc21a2b9c6f612338c31a289df8", "0x83576d3324bf2d8afbfb6eaecdc5d767c8e22e7d25160414924f0645491df60541948a05e1f4202e612368e78675de8a", "0xb43749b8df4b15bc9a3697e0f1c518e6b04114171739ef1a0c9c65185d8ec18e40e6954d125cbc14ebc652cf41ad3109", "0xb4eebd5d80a7327a040cafb9ccdb12b2dfe1aa86e6bc6d3ac8a57fadfb95a5b1a7332c66318ff72ba459f525668af056", "0x9198be7f1d413c5029b0e1c617bcbc082d21abe2c60ec8ce9b54ca1a85d3dba637b72fda39dae0c0ae40d047eab9f55a", "0x8d96a0232832e24d45092653e781e7a9c9520766c3989e67bbe86b3a820c4bf621ea911e7cd5270a4bfea78b618411f6", "0x8d7160d0ea98161a2d14d46ef01dff72d566c330cd4fabd27654d300e1bc7644c68dc8eabf2a20a59bfe7ba276545f9b", "0xabb60fce29dec7ba37e3056e412e0ec3e05538a1fc0e2c68877378c867605966108bc5742585ab6a405ce0c962b285b6", "0x8fabffa3ed792f05e414f5839386f6449fd9f7b41a47595c5d71074bd1bb3784cc7a1a7e1ad6b041b455035957e5b2dc", "0x90ff017b4804c2d0533b72461436b10603ab13a55f86fd4ec11b06a70ef8166f958c110519ca1b4cc7beba440729fe2d", "0xb340cfd120f6a4623e3a74cf8c32bfd7cd61a280b59dfd17b15ca8fae4d82f64a6f15fbde4c02f424debc72b7db5fe67", "0x871311c9c7220c932e738d59f0ecc67a34356d1429fe570ca503d340c9996cb5ee2cd188fad0e3bd16e4c468ec1dbebd", "0xa772470262186e7b94239ba921b29f2412c148d6f97c4412e96d21e55f3be73f992f1ad53c71008f0558ec3f84e2b5a7", "0xb2a897dcb7ffd6257f3f2947ec966f2077d57d5191a88840b1d4f67effebe8c436641be85524d0a21be734c63ab5965d", "0xa044f6eacc48a4a061fa149500d96b48cbf14853469aa4d045faf3dca973be1bd4b4ce01646d83e2f24f7c486d03205d", "0x981af5dc2daa73f7fa9eae35a93d81eb6edba4a7f673b55d41f6ecd87a37685d31bb40ef4f1c469b3d72f2f18b925a17", "0x912d2597a07864de9020ac77083eff2f15ceb07600f15755aba61251e8ce3c905a758453b417f04d9c38db040954eb65", "0x9642b7f6f09394ba5e0805734ef6702c3eddf9eea187ba98c676d5bbaec0e360e3e51dc58433aaa1e2da6060c8659cb7", "0x8ab3836e0a8ac492d5e707d056310c4c8e0489ca85eb771bff35ba1d658360084e836a6f51bb990f9e3d2d9aeb18fbb5", "0x879e058e72b73bb1f4642c21ffdb90544b846868139c6511f299aafe59c2d0f0b944dffc7990491b7c4edcd6a9889250", "0xb9e60b737023f61479a4a8fd253ed0d2a944ea6ba0439bbc0a0d3abf09b0ad1f18d75555e4a50405470ae4990626f390", "0xb9c2535d362796dcd673640a9fa2ebdaec274e6f8b850b023153b0a7a30fffc87f96e0b72696f647ebe7ab63099a6963", "0x94aeff145386a087b0e91e68a84a5ede01f978f9dd9fe7bebca78941938469495dc30a96bba9508c0d017873aeea9610", "0x98b179f8a3d9f0d0a983c30682dd425a2ddc7803be59bd626c623c8951a5179117d1d2a68254c95c9952989877d0ee55", "0x889ecf5f0ee56938273f74eb3e9ecfb5617f04fb58e83fe4c0e4aef51615cf345bc56f3f61b17f6eed3249d4afd54451", "0xa0f2b2c39bcea4b50883e2587d16559e246248a66ecb4a4b7d9ab3b51fb39fe98d83765e087eee37a0f86b0ba4144c02", "0xb2a61e247ed595e8a3830f7973b07079cbda510f28ad8c78c220b26cb6acde4fbb5ee90c14a665f329168ee951b08cf0", "0x95bd0fcfb42f0d6d8a8e73d7458498a85bcddd2fb132fd7989265648d82ac2707d6d203fac045504977af4f0a2aca4b7", "0x843e5a537c298666e6cf50fcc044f13506499ef83c802e719ff2c90e85003c132024e04711be7234c04d4b0125512d5d", "0xa46d1797c5959dcd3a5cfc857488f4d96f74277c3d13b98b133620192f79944abcb3a361d939a100187f1b0856eae875", "0xa1c7786736d6707a48515c38660615fcec67eb8a2598f46657855215f804fd72ab122d17f94fcffad8893f3be658dca7", "0xb23dc9e610abc7d8bd21d147e22509a0fa49db5be6ea7057b51aae38e31654b3aa044df05b94b718153361371ba2f622", "0xb00cc8f257d659c22d30e6d641f79166b1e752ea8606f558e4cad6fc01532e8319ea4ee12265ba4140ac45aa4613c004", "0xac7019af65221b0cc736287b32d7f1a3561405715ba9a6a122342e04e51637ba911c41573de53e4781f2230fdcb2475f", "0x81a630bc41b3da8b3eb4bf56cba10cd9f93153c3667f009dc332287baeb707d505fb537e6233c8e53d299ec0f013290c", "0xa6b7aea5c545bb76df0f230548539db92bc26642572cb7dd3d5a30edca2b4c386f44fc8466f056b42de2a452b81aff5b", "0x8271624ff736b7b238e43943c81de80a1612207d32036d820c11fc830c737972ccc9c60d3c2359922b06652311e3c994", "0x8a684106458cb6f4db478170b9ad595d4b54c18bf63b9058f095a2fa1b928c15101472c70c648873d5887880059ed402", "0xa5cc3c35228122f410184e4326cf61a37637206e589fcd245cb5d0cec91031f8f7586b80503070840fdfd8ce75d3c88b", "0x9443fc631aed8866a7ed220890911057a1f56b0afe0ba15f0a0e295ab97f604b134b1ed9a4245e46ee5f9a93aa74f731", "0x984b6f7d79835dffde9558c6bb912d992ca1180a2361757bdba4a7b69dc74b056e303adc69fe67414495dd9c2dd91e64", "0xb15a5c8cba5de080224c274d31c68ed72d2a7126d347796569aef0c4e97ed084afe3da4d4b590b9dda1a07f0c2ff3dfb", "0x991708fe9650a1f9a4e43938b91d45dc68c230e05ee999c95dbff3bf79b1c1b2bb0e7977de454237c355a73b8438b1d9", "0xb4f7edc7468b176a4a7c0273700c444fa95c726af6697028bed4f77eee887e3400f9c42ee15b782c0ca861c4c3b8c98a", "0x8c60dcc16c51087eb477c13e837031d6c6a3dc2b8bf8cb43c23f48006bc7173151807e866ead2234b460c2de93b31956", "0x83ad63e9c910d1fc44bc114accfb0d4d333b7ebe032f73f62d25d3e172c029d5e34a1c9d547273bf6c0fead5c8801007", "0x85de73213cc236f00777560756bdbf2b16841ba4b55902cf2cad9742ecaf5d28209b012ceb41f337456dfeca93010cd7", "0xa7561f8827ccd75b6686ba5398bb8fc3083351c55a589b18984e186820af7e275af04bcd4c28e1dc11be1e8617a0610b", "0x88c0a4febd4068850557f497ea888035c7fc9f404f6cc7794e7cc8722f048ad2f249e7dc62743e7a339eb7473ad3b0cd", "0x932b22b1d3e6d5a6409c34980d176feb85ada1bf94332ef5c9fc4d42b907dabea608ceef9b5595ef3feee195151f18d8", "0xa2867bb3f5ab88fbdae3a16c9143ab8a8f4f476a2643c505bb9f37e5b1fd34d216cab2204c9a017a5a67b7ad2dda10e8", "0xb573d5f38e4e9e8a3a6fd82f0880dc049efa492a946d00283019bf1d5e5516464cf87039e80aef667cb86fdea5075904", "0xb948f1b5ab755f3f5f36af27d94f503b070696d793b1240c1bdfd2e8e56890d69e6904688b5f8ff5a4bdf5a6abfe195f", "0x917eae95ebc4109a2e99ddd8fec7881d2f7aaa0e25fda44dec7ce37458c2ee832f1829db7d2dcfa4ca0f06381c7fe91d", "0x95751d17ed00a3030bce909333799bb7f4ab641acf585807f355b51d6976dceee410798026a1a004ef4dcdff7ec0f5b8", "0xb9b7bd266f449a79bbfe075e429613e76c5a42ac61f01c8f0bbbd34669650682efe01ff9dbbc400a1e995616af6aa278", "0xac1722d097ce9cd7617161f8ec8c23d68f1fb1c9ca533e2a8b4f78516c2fd8fb38f23f834e2b9a03bb06a9d655693ca9", "0xa7ad9e96ffd98db2ecdb6340c5d592614f3c159abfd832fe27ee9293519d213a578e6246aae51672ee353e3296858873", "0x989b8814d5de7937c4acafd000eec2b4cd58ba395d7b25f98cafd021e8efa37029b29ad8303a1f6867923f5852a220eb", "0xa5bfe6282c771bc9e453e964042d44eff4098decacb89aecd3be662ea5b74506e1357ab26f3527110ba377711f3c9f41", "0x8900a7470b656639721d2abbb7b06af0ac4222ab85a1976386e2a62eb4b88bfb5b72cf7921ddb3cf3a395d7eeb192a2e", "0x95a71b55cd1f35a438cf5e75f8ff11c5ec6a2ebf2e4dba172f50bfad7d6d5dca5de1b1afc541662c81c858f7604c1163", "0x82b5d62fea8db8d85c5bc3a76d68dedd25794cf14d4a7bc368938ffca9e09f7e598fdad2a5aac614e0e52f8112ae62b9", "0x997173f07c729202afcde3028fa7f52cefc90fda2d0c8ac2b58154a5073140683e54c49ed1f254481070d119ce0ce02a", "0xaeffb91ccc7a72bbd6ffe0f9b99c9e66e67d59cec2e02440465e9636a613ab3017278cfa72ea8bc4aba9a8dc728cb367", "0x952743b06e8645894aeb6440fc7a5f62dd3acf96dab70a51e20176762c9751ea5f2ba0b9497ccf0114dc4892dc606031", "0x874c63baeddc56fbbca2ff6031f8634b745f6e34ea6791d7c439201aee8f08ef5ee75f7778700a647f3b21068513fce6", "0x85128fec9c750c1071edfb15586435cc2f317e3e9a175bb8a9697bcda1eb9375478cf25d01e7fed113483b28f625122d", "0x85522c9576fd9763e32af8495ae3928ed7116fb70d4378448926bc9790e8a8d08f98cf47648d7da1b6e40d6a210c7924", "0x97d0f37a13cfb723b848099ca1c14d83e9aaf2f7aeb71829180e664b7968632a08f6a85f557d74b55afe6242f2a36e7c", "0xabaa472d6ad61a5fccd1a57c01aa1bc081253f95abbcba7f73923f1f11c4e79b904263890eeb66926de3e2652f5d1c70", "0xb3c04945ba727a141e5e8aec2bf9aa3772b64d8fd0e2a2b07f3a91106a95cbcb249adcd074cbe498caf76fffac20d4ef", "0x82c46781a3d730d9931bcabd7434a9171372dde57171b6180e5516d4e68db8b23495c8ac3ab96994c17ddb1cf249b9fb", "0xa202d8b65613c42d01738ccd68ed8c2dbc021631f602d53f751966e04182743ebc8e0747d600b8a8676b1da9ae7f11ab", "0xae73e7256e9459db04667a899e0d3ea5255211fb486d084e6550b6dd64ca44af6c6b2d59d7aa152de9f96ce9b58d940d", "0xb67d87b176a9722945ec7593777ee461809861c6cfd1b945dde9ee4ff009ca4f19cf88f4bbb5c80c9cbab2fe25b23ac8", "0x8f0b7a317a076758b0dac79959ee4a06c08b07d0f10538a4b53d3da2eda16e2af26922feb32c090330dc4d969cf69bd3", "0x90b36bf56adbd8c4b6cb32febc3a8d5f714370c2ac3305c10fa6d168dffb2a026804517215f9a2d4ec8310cdb6bb459b", "0xaa80c19b0682ead69934bf18cf476291a0beddd8ef4ed75975d0a472e2ab5c70f119722a8574ae4973aceb733d312e57", "0xa3fc9abb12574e5c28dcb51750b4339b794b8e558675eef7d26126edf1de920c35e992333bcbffcbf6a5f5c0d383ce62", "0xa1573ff23ab972acdcd08818853b111fc757fdd35aa070186d3e11e56b172fb49d840bf297ac0dd222e072fc09f26a81", "0x98306f2be4caa92c2b4392212d0cbf430b409b19ff7d5b899986613bd0e762c909fc01999aa94be3bd529d67f0113d7f", "0x8c1fc42482a0819074241746d17dc89c0304a2acdae8ed91b5009e9e3e70ff725ba063b4a3e68fdce05b74f5180c545e", "0xa6c6113ebf72d8cf3163b2b8d7f3fa24303b13f55752522c660a98cd834d85d8c79214d900fa649499365e2e7641f77a", "0xab95eea424f8a2cfd9fb1c78bb724e5b1d71a0d0d1e4217c5d0f98b0d8bbd3f8400a2002abc0a0e4576d1f93f46fefad", "0x823c5a4fd8cf4a75fdc71d5f2dd511b6c0f189b82affeacd2b7cfcad8ad1a5551227dcc9bfdb2e34b2097eaa00efbb51", "0xb97314dfff36d80c46b53d87a61b0e124dc94018a0bb680c32765b9a2d457f833a7c42bbc90b3b1520c33a182580398d", "0xb17566ee3dcc6bb3b004afe4c0136dfe7dd27df9045ae896dca49fb36987501ae069eb745af81ba3fc19ff037e7b1406", "0xb0bdc0f55cfd98d331e3a0c4fbb776a131936c3c47c6bffdc3aaf7d8c9fa6803fbc122c2fefbb532e634228687d52174", "0xaa5d9e60cc9f0598559c28bb9bdd52aa46605ab4ffe3d192ba982398e72cec9a2a44c0d0d938ce69935693cabc0887ea", "0x802b6459d2354fa1d56c592ac1346c428dadea6b6c0a87bf7d309bab55c94e1cf31dd98a7a86bd92a840dd51f218b91b", "0xa526914efdc190381bf1a73dd33f392ecf01350b9d3f4ae96b1b1c3d1d064721c7d6eec5788162c933245a3943f5ee51", "0xb3b8fcf637d8d6628620a1a99dbe619eabb3e5c7ce930d6efd2197e261bf394b74d4e5c26b96c4b8009c7e523ccfd082", "0x8f7510c732502a93e095aba744535f3928f893f188adc5b16008385fb9e80f695d0435bfc5b91cdad4537e87e9d2551c", "0x97b90beaa56aa936c3ca45698f79273a68dd3ccd0076eab48d2a4db01782665e63f33c25751c1f2e070f4d1a8525bf96", "0xb9fb798324b1d1283fdc3e48288e3861a5449b2ab5e884b34ebb8f740225324af86e4711da6b5cc8361c1db15466602f", "0xb6d52b53cea98f1d1d4c9a759c25bf9d8a50b604b144e4912acbdbdc32aab8b9dbb10d64a29aa33a4f502121a6fb481c", "0x9174ffff0f2930fc228f0e539f5cfd82c9368d26b074467f39c07a774367ff6cccb5039ac63f107677d77706cd431680", "0xa33b6250d4ac9e66ec51c063d1a6a31f253eb29bbaed12a0d67e2eccfffb0f3a52750fbf52a1c2aaba8c7692346426e7", "0xa97025fd5cbcebe8ef865afc39cd3ea707b89d4e765ec817fd021d6438e02fa51e3544b1fd45470c58007a08efac6edd", "0xb32a78480edd9ff6ba2f1eec4088db5d6ceb2d62d7e59e904ecaef7bb4a2e983a4588e51692b3be76e6ffbc0b5f911a5", "0xb5ab590ef0bb77191f00495b33d11c53c65a819f7d0c1f9dc4a2caa147a69c77a4fff7366a602d743ee1f395ce934c1e", "0xb3fb0842f9441fb1d0ee0293b6efbc70a8f58d12d6f769b12872db726b19e16f0f65efbc891cf27a28a248b0ef9c7e75", "0x9372ad12856fefb928ccb0d34e198df99e2f8973b07e9d417a3134d5f69e12e79ff572c4e03ccd65415d70639bc7c73e", "0xaa8d6e83d09ce216bfe2009a6b07d0110d98cf305364d5529c170a23e693aabb768b2016befb5ada8dabdd92b4d012bb", "0xa954a75791eeb0ce41c85200c3763a508ed8214b5945a42c79bfdcfb1ec4f86ad1dd7b2862474a368d4ac31911a2b718", "0x8e2081cfd1d062fe3ab4dab01f68062bac802795545fede9a188f6c9f802cb5f884e60dbe866710baadbf55dc77c11a4", "0xa2f06003b9713e7dd5929501ed485436b49d43de80ea5b15170763fd6346badf8da6de8261828913ee0dacd8ff23c0e1", "0x98eecc34b838e6ffd1931ca65eec27bcdb2fdcb61f33e7e5673a93028c5865e0d1bf6d3bec040c5e96f9bd08089a53a4", "0x88cc16019741b341060b95498747db4377100d2a5bf0a5f516f7dec71b62bcb6e779de2c269c946d39040e03b3ae12b7", "0xad1135ccbc3019d5b2faf59a688eef2500697642be8cfbdf211a1ab59abcc1f24483e50d653b55ff1834675ac7b4978f", "0xa946f05ed9972f71dfde0020bbb086020fa35b482cce8a4cc36dd94355b2d10497d7f2580541bb3e81b71ac8bba3c49f", "0xa83aeed488f9a19d8cfd743aa9aa1982ab3723560b1cd337fc2f91ad82f07afa412b3993afb845f68d47e91ba4869840", "0x95eebe006bfc316810cb71da919e5d62c2cebb4ac99d8e8ef67be420302320465f8b69873470982de13a7c2e23516be9", "0xa55f8961295a11e91d1e5deadc0c06c15dacbfc67f04ccba1d069cba89d72aa3b3d64045579c3ea8991b150ac29366ae", "0xb321991d12f6ac07a5de3c492841d1a27b0d3446082fbce93e7e1f9e8d8fe3b45d41253556261c21b70f5e189e1a7a6f", "0xa0b0822f15f652ce7962a4f130104b97bf9529797c13d6bd8e24701c213cc37f18157bd07f3d0f3eae6b7cd1cb40401f", "0x96e2fa4da378aa782cc2d5e6e465fc9e49b5c805ed01d560e9b98abb5c0de8b74a2e7bec3aa5e2887d25cccb12c66f0c", "0x97e4ab610d414f9210ed6f35300285eb3ccff5b0b6a95ed33425100d7725e159708ea78704497624ca0a2dcabce3a2f9", "0x960a375b17bdb325761e01e88a3ea57026b2393e1d887b34b8fa5d2532928079ce88dc9fd06a728b26d2bb41b12b9032", "0x8328a1647398e832aadc05bd717487a2b6fcdaa0d4850d2c4da230c6a2ed44c3e78ec4837b6094f3813f1ee99414713f", "0xaa283834ebd18e6c99229ce4b401eda83f01d904f250fedd4e24f1006f8fa0712a6a89a7296a9bf2ce8de30e28d1408e", "0xb29e097f2caadae3e0f0ae3473c072b0cd0206cf6d2e9b22c1a5ad3e07d433e32bd09ed1f4e4276a2da4268633357b7f", "0x9539c5cbba14538b2fe077ecf67694ef240da5249950baaabea0340718b882a966f66d97f08556b08a4320ceb2cc2629", "0xb4529f25e9b42ae8cf8338d2eface6ba5cd4b4d8da73af502d081388135c654c0b3afb3aa779ffc80b8c4c8f4425dd2b", "0x95be0739c4330619fbe7ee2249c133c91d6c07eab846c18c5d6c85fc21ac5528c5d56dcb0145af68ed0c6a79f68f2ccd", "0xac0c83ea802227bfc23814a24655c9ff13f729619bcffdb487ccbbf029b8eaee709f8bddb98232ef33cd70e30e45ca47", "0xb503becb90acc93b1901e939059f93e671900ca52c6f64ae701d11ac891d3a050b505d89324ce267bc43ab8275da6ffe", "0x98e3811b55b1bacb70aa409100abb1b870f67e6d059475d9f278c751b6e1e2e2d6f2e586c81a9fb6597fda06e7923274", "0xb0b0f61a44053fa6c715dbb0731e35d48dba257d134f851ee1b81fd49a5c51a90ebf5459ec6e489fce25da4f184fbdb1", "0xb1d2117fe811720bb997c7c93fe9e4260dc50fca8881b245b5e34f724aaf37ed970cdad4e8fcb68e05ac8cf55a274a53", "0xa10f502051968f14b02895393271776dee7a06db9de14effa0b3471825ba94c3f805302bdddac4d397d08456f620999d", "0xa3dbad2ef060ae0bb7b02eaa4a13594f3f900450faa1854fc09620b01ac94ab896321dfb1157cf2374c27e5718e8026a", "0xb550fdec503195ecb9e079dcdf0cad559d64d3c30818ef369b4907e813e689da316a74ad2422e391b4a8c2a2bef25fc0", "0xa25ba865e2ac8f28186cea497294c8649a201732ecb4620c4e77b8e887403119910423df061117e5f03fc5ba39042db1", "0xb3f88174e03fdb443dd6addd01303cf88a4369352520187c739fc5ae6b22fa99629c63c985b4383219dab6acc5f6f532", "0x97a7503248e31e81b10eb621ba8f5210c537ad11b539c96dfb7cf72b846c7fe81bd7532c5136095652a9618000b7f8d3", "0xa8bcdc1ce5aa8bfa683a2fc65c1e79de8ff5446695dcb8620f7350c26d2972a23da22889f9e2b1cacb3f688c6a2953dc", "0x8458c111df2a37f5dd91a9bee6c6f4b79f4f161c93fe78075b24a35f9817da8dde71763218d627917a9f1f0c4709c1ed", "0xac5f061a0541152b876cbc10640f26f1cc923c9d4ae1b6621e4bb3bf2cec59bbf87363a4eb72fb0e5b6d4e1c269b52d5", "0xa9a25ca87006e8a9203cbb78a93f50a36694aa4aad468b8d80d3feff9194455ca559fcc63838128a0ab75ad78c07c13a", "0xa450b85f5dfffa8b34dfd8bc985f921318efacf8857cf7948f93884ba09fb831482ee90a44224b1a41e859e19b74962f", "0x8ed91e7f92f5c6d7a71708b6132f157ac226ecaf8662af7d7468a4fa25627302efe31e4620ad28719318923e3a59bf82", "0xab524165fd4c71b1fd395467a14272bd2b568592deafa039d8492e9ef36c6d3f96927c95c72d410a768dc0b6d1fbbc9b", "0xb662144505aa8432c75ffb8d10318526b6d5777ac7af9ebfad87d9b0866c364f7905a6352743bd8fd79ffd9d5dd4f3e6", "0xa48f1677550a5cd40663bb3ba8f84caaf8454f332d0ceb1d94dbea52d0412fe69c94997f7749929712fd3995298572f7", "0x8391cd6e2f6b0c242de1117a612be99776c3dc95cb800b187685ea5bf7e2722275eddb79fd7dfc8be8e389c4524cdf70", "0x875d3acb9af47833b72900bc0a2448999d638f153c5e97e8a14ec02d0c76f6264353a7e275e1f1a5855daced523d243b", "0x91f1823657d30b59b2f627880a9a9cb530f5aca28a9fd217fe6f2f5133690dfe7ad5a897872e400512db2e788b3f7628", "0xad3564332aa56cea84123fc7ca79ea70bb4fef2009fa131cb44e4b15e8613bd11ca1d83b9d9bf456e4b7fee9f2e8b017", "0x8c530b84001936d5ab366c84c0b105241a26d1fb163669f17c8f2e94776895c2870edf3e1bc8ccd04d5e65531471f695", "0x932d01fa174fdb0c366f1230cffde2571cc47485f37f23ba5a1825532190cc3b722aeb1f15aed62cf83ccae9403ba713", "0x88b28c20585aca50d10752e84b901b5c2d58efef5131479fbbe53de7bce2029e1423a494c0298e1497669bd55be97a5d", "0xb914148ca717721144ebb3d3bf3fcea2cd44c30c5f7051b89d8001502f3856fef30ec167174d5b76265b55d70f8716b5", "0x81d0173821c6ddd2a068d70766d9103d1ee961c475156e0cbd67d54e668a796310474ef698c7ab55abe6f2cf76c14679", "0x8f28e8d78e2fe7fa66340c53718e0db4b84823c8cfb159c76eac032a62fb53da0a5d7e24ca656cf9d2a890cb2a216542", "0x8a26360335c73d1ab51cec3166c3cf23b9ea51e44a0ad631b0b0329ef55aaae555420348a544e18d5760969281759b61", "0x94f326a32ed287545b0515be9e08149eb0a565025074796d72387cc3a237e87979776410d78339e23ef3172ca43b2544", "0xa785d2961a2fa5e70bffa137858a92c48fe749fee91b02599a252b0cd50d311991a08efd7fa5e96b78d07e6e66ffe746", "0x94af9030b5ac792dd1ce517eaadcec1482206848bea4e09e55cc7f40fd64d4c2b3e9197027c5636b70d6122c51d2235d", "0x9722869f7d1a3992850fe7be405ec93aa17dc4d35e9e257d2e469f46d2c5a59dbd504056c85ab83d541ad8c13e8bcd54", "0xb13c4088b61a06e2c03ac9813a75ff1f68ffdfee9df6a8f65095179a475e29cc49119cad2ce05862c3b1ac217f3aace9", "0x8c64d51774753623666b10ca1b0fe63ae42f82ed6aa26b81dc1d48c86937c5772eb1402624c52a154b86031854e1fb9f", "0xb47e4df18002b7dac3fee945bf9c0503159e1b8aafcce2138818e140753011b6d09ef1b20894e08ba3006b093559061b", "0x93cb5970076522c5a0483693f6a35ffd4ea2aa7aaf3730c4eccd6af6d1bebfc1122fc4c67d53898ae13eb6db647be7e2", "0xa68873ef80986795ea5ed1a597d1cd99ed978ec25e0abb57fdcc96e89ef0f50aeb779ff46e3dce21dc83ada3157a8498", "0x8cab67f50949cc8eee6710e27358aea373aae3c92849f8f0b5531c080a6300cdf2c2094fe6fecfef6148de0d28446919", "0x993e932bcb616dbaa7ad18a4439e0565211d31071ef1b85a0627db74a05d978c60d507695eaeea5c7bd9868a21d06923", "0xacdadff26e3132d9478a818ef770e9fa0d2b56c6f5f48bd3bd674436ccce9bdfc34db884a73a30c04c5f5e9764cb2218", "0xa0d3e64c9c71f84c0eef9d7a9cb4fa184224b969db5514d678e93e00f98b41595588ca802643ea225512a4a272f5f534", "0x91c9140c9e1ba6e330cb08f6b2ce4809cd0d5a0f0516f70032bf30e912b0ed684d07b413b326ab531ee7e5b4668c799b", "0x87bc2ee7a0c21ba8334cd098e35cb703f9af57f35e091b8151b9b63c3a5b0f89bd7701dbd44f644ea475901fa6d9ef08", "0x9325ccbf64bf5d71b303e31ee85d486298f9802c5e55b2c3d75427097bf8f60fa2ab4fcaffa9b60bf922c3e24fbd4b19", "0x95d0506e898318f3dc8d28d16dfd9f0038b54798838b3c9be2a2ae3c2bf204eb496166353fc042220b0bd4f6673b9285", "0x811de529416331fe9c416726d45df9434c29dcd7e949045eb15740f47e97dde8f31489242200e19922cac2a8b7c6fd1f", "0xade632d04a4c8bbab6ca7df370b2213cb9225023e7973f0e29f4f5e52e8aeaabc65171306bbdd12a67b195dfbb96d48f", "0x88b7f029e079b6ae956042c0ea75d53088c5d0efd750dd018adaeacf46be21bf990897c58578c491f41afd3978d08073", "0x91f477802de507ffd2be3f4319903119225b277ad24f74eb50f28b66c14d32fae53c7edb8c7590704741af7f7f3e3654", "0x809838b32bb4f4d0237e98108320d4b079ee16ed80c567e7548bd37e4d7915b1192880f4812ac0e00476d246aec1dbc8", "0x84183b5fc4a7997a8ae5afedb4d21dce69c480d5966b5cbdafd6dd10d29a9a6377f3b90ce44da0eb8b176ac3af0253bb", "0x8508abbf6d3739a16b9165caf0f95afb3b3ac1b8c38d6d374cf0c91296e2c1809a99772492b539cda184510bce8a0271", "0x8722054e59bab2062e6419a6e45fc803af77fde912ef2cd23055ad0484963de65a816a2debe1693d93c18218d2b8e81a", "0x8e895f80e485a7c4f56827bf53d34b956281cdc74856c21eb3b51f6288c01cc3d08565a11cc6f3e2604775885490e8c5", "0xafc92714771b7aa6e60f3aee12efd9c2595e9659797452f0c1e99519f67c8bc3ac567119c1ddfe82a3e961ee9defea9a", "0x818ff0fd9cefd32db87b259e5fa32967201016fc02ef44116cdca3c63ce5e637756f60477a408709928444a8ad69c471", "0x8251e29af4c61ae806fc5d032347fb332a94d472038149225298389495139ce5678fae739d02dfe53a231598a992e728", "0xa0ea39574b26643f6f1f48f99f276a8a64b5481989cfb2936f9432a3f8ef5075abfe5c067dc5512143ce8bf933984097", "0xaf67a73911b372bf04e57e21f289fc6c3dfac366c6a01409b6e76fea4769bdb07a6940e52e8d7d3078f235c6d2f632c6", "0xb5291484ef336024dd2b9b4cf4d3a6b751133a40656d0a0825bcc6d41c21b1c79cb50b0e8f4693f90c29c8f4358641f9", "0x8bc0d9754d70f2cb9c63f991902165a87c6535a763d5eece43143b5064ae0bcdce7c7a8f398f2c1c29167b2d5a3e6867", "0x8d7faff53579ec8f6c92f661c399614cc35276971752ce0623270f88be937c414eddcb0997e14724a783905a026c8883", "0x9310b5f6e675fdf60796f814dbaa5a6e7e9029a61c395761e330d9348a7efab992e4e115c8be3a43d08e90d21290c892", "0xb5eb4f3eb646038ad2a020f0a42202532d4932e766da82b2c1002bf9c9c2e5336b54c8c0ffcc0e02d19dde2e6a35b6cc", "0x91dabfd30a66710f1f37a891136c9be1e23af4abf8cb751f512a40c022a35f8e0a4fb05b17ec36d4208de02d56f0d53a", "0xb3ded14e82d62ac7a5a036122a62f00ff8308498f3feae57d861babaff5a6628d43f0a0c5fc903f10936bcf4e2758ceb", "0xa88e8348fed2b26acca6784d19ef27c75963450d99651d11a950ea81d4b93acd2c43e0ecce100eaf7e78508263d5baf3", "0xb1f5bbf7c4756877b87bb42163ac570e08c6667c4528bf68b5976680e19beeff7c5effd17009b0718797077e2955457a", "0xad2e7b516243f915d4d1415326e98b1a7390ae88897d0b03b66c2d9bd8c3fba283d7e8fe44ed3333296a736454cef6d8", "0x8f82eae096d5b11f995de6724a9af895f5e1c58d593845ad16ce8fcae8507e0d8e2b2348a0f50a1f66a17fd6fac51a5c", "0x890e4404d0657c6c1ee14e1aac132ecf7a568bb3e04137b85ac0f84f1d333bd94993e8750f88eee033a33fb00f85dcc7", "0x82ac7d3385e035115f1d39a99fc73e5919de44f5e6424579776d118d711c8120b8e5916372c6f27bed4cc64cac170b6c", "0x85ee16d8901c272cfbbe966e724b7a891c1bd5e68efd5d863043ad8520fc409080af61fd726adc680b3f1186fe0ac8b8", "0x86dc564c9b545567483b43a38f24c41c6551a49cabeebb58ce86404662a12dbfafd0778d30d26e1c93ce222e547e3898", "0xa29f5b4522db26d88f5f95f18d459f8feefab02e380c2edb65aa0617a82a3c1a89474727a951cef5f15050bcf7b380fb", "0xa1ce039c8f6cac53352899edb0e3a72c76da143564ad1a44858bd7ee88552e2fe6858d1593bbd74aeee5a6f8034b9b9d", "0x97f10d77983f088286bd7ef3e7fdd8fa275a56bec19919adf33cf939a90c8f2967d2b1b6fc51195cb45ad561202a3ed7", "0xa25e2772e8c911aaf8712bdac1dd40ee061c84d3d224c466cfaae8e5c99604053f940cde259bd1c3b8b69595781dbfec", "0xb31bb95a0388595149409c48781174c340960d59032ab2b47689911d03c68f77a2273576fbe0c2bf4553e330656058c7", "0xb8b2e9287ad803fb185a13f0d7456b397d4e3c8ad5078f57f49e8beb2e85f661356a3392dbd7bcf6a900baa5582b86a1", "0xa3d0893923455eb6e96cc414341cac33d2dbc88fba821ac672708cce131761d85a0e08286663a32828244febfcae6451", "0x82310cb42f647d99a136014a9f881eb0b9791efd2e01fc1841907ad3fc8a9654d3d1dab6689c3607214b4dc2aca01cee", "0x874022d99c16f60c22de1b094532a0bc6d4de700ad01a31798fac1d5088b9a42ad02bef8a7339af7ed9c0d4f16b186ee", "0x94981369e120265aed40910eebc37eded481e90f4596b8d57c3bec790ab7f929784bd33ddd05b7870aad6c02e869603b", "0xa4f1f50e1e2a73f07095e0dd31cb45154f24968dae967e38962341c1241bcd473102fff1ff668b20c6547e9732d11701", "0xae2328f3b0ad79fcda807e69a1b5278145225083f150f67511dafc97e079f860c3392675f1752ae7e864c056e592205b", "0x875d8c971e593ca79552c43d55c8c73b17cd20c81ff2c2fed1eb19b1b91e4a3a83d32df150dbfd5db1092d0aebde1e1f", "0xadd2e80aa46aae95da73a11f130f4bda339db028e24c9b11e5316e75ba5e63bc991d2a1da172c7c8e8fee038baae3433", "0xb46dbe1cb3424002aa7de51e82f600852248e251465c440695d52538d3f36828ff46c90ed77fc1d11534fe3c487df8ef", "0xa5e5045d28b4e83d0055863c30c056628c58d4657e6176fd0536f5933f723d60e851bb726d5bf3c546b8ce4ac4a57ef8", "0x91fec01e86dd1537e498fff7536ea3ca012058b145f29d9ada49370cd7b7193ac380e116989515df1b94b74a55c45df3", "0xa7428176d6918cd916a310bdc75483c72de660df48cac4e6e7478eef03205f1827ea55afc0df5d5fa7567d14bbea7fc9", "0x851d89bef45d9761fe5fdb62972209335193610015e16a675149519f9911373bac0919add226ef118d9f3669cfdf4734", "0xb74acf5c149d0042021cb2422ea022be4c4f72a77855f42393e71ffd12ebb3eec16bdf16f812159b67b79a9706e7156d", "0x99f35dce64ec99aa595e7894b55ce7b5a435851b396e79036ffb249c28206087db4c85379df666c4d95857db02e21ff9", "0xb6b9a384f70db9e298415b8ab394ee625dafff04be2886476e59df8d052ca832d11ac68a9b93fba7ab055b7bc36948a4", "0x898ee4aefa923ffec9e79f2219c7389663eb11eb5b49014e04ed4a336399f6ea1691051d86991f4c46ca65bcd4fdf359", "0xb0f948217b0d65df7599a0ba4654a5e43c84db477936276e6f11c8981efc6eaf14c90d3650107ed4c09af4cc8ec11137", "0xaa6286e27ac54f73e63dbf6f41865dd94d24bc0cf732262fcaff67319d162bb43af909f6f8ee27b1971939cfbba08141", "0x8bca7cdf730cf56c7b2c8a2c4879d61361a6e1dba5a3681a1a16c17a56e168ace0e99cf0d15826a1f5e67e6b8a8a049a", "0xa746d876e8b1ce225fcafca603b099b36504846961526589af977a88c60d31ba2cc56e66a3dec8a77b3f3531bf7524c9", "0xa11e2e1927e6704cdb8874c75e4f1842cef84d7d43d7a38e339e61dc8ba90e61bbb20dd3c12e0b11d2471d58eed245be", "0xa36395e22bc1d1ba8b0459a235203177737397da5643ce54ded3459d0869ff6d8d89f50c73cb62394bf66a959cde9b90", "0x8b49f12ba2fdf9aca7e5f81d45c07d47f9302a2655610e7634d1e4bd16048381a45ef2c95a8dd5b0715e4b7cf42273af", "0x91cffa2a17e64eb7f76bccbe4e87280ee1dd244e04a3c9eac12e15d2d04845d876eb24fe2ec6d6d266cce9efb281077f", "0xa6b8afabf65f2dee01788114e33a2f3ce25376fb47a50b74da7c3c25ff1fdc8aa9f41307534abbf48acb6f7466068f69", "0x8d13db896ccfea403bd6441191995c1a65365cab7d0b97fbe9526da3f45a877bd1f4ef2edef160e8a56838cd1586330e", "0x98c717de9e01bef8842c162a5e757fe8552d53269c84862f4d451e7c656ae6f2ae473767b04290b134773f63be6fdb9d", "0x8c2036ace1920bd13cf018e82848c49eb511fad65fd0ff51f4e4b50cf3bfc294afb63cba682c16f52fb595a98fa84970", "0xa3520fdff05dbad9e12551b0896922e375f9e5589368bcb2cc303bde252743b74460cb5caf99629325d3620f13adc796", "0x8d4f83a5bfec05caf5910e0ce538ee9816ee18d0bd44c1d0da2a87715a23cd2733ad4d47552c6dc0eb397687d611dd19", "0xa7b39a0a6a02823452d376533f39d35029867b3c9a6ad6bca181f18c54132d675613a700f9db2440fb1b4fa13c8bf18a", "0x80bcb114b2544b80f404a200fc36860ed5e1ad31fe551acd4661d09730c452831751baa9b19d7d311600d267086a70bc", "0x90dcce03c6f88fc2b08f2b42771eedde90cc5330fe0336e46c1a7d1b5a6c1641e5fcc4e7b3d5db00bd8afca9ec66ed81", "0xaec15f40805065c98e2965b1ae12a6c9020cfdb094c2d0549acfc7ea2401a5fb48d3ea7d41133cf37c4e096e7ff53eb9", "0x80e129b735dba49fa627a615d6c273119acec8e219b2f2c4373a332b5f98d66cbbdd688dfbe72a8f8bfefaccc02c50c1", "0xa9b596da3bdfe23e6799ece5f7975bf7a1979a75f4f546deeaf8b34dfe3e0d623217cb4cf4ccd504cfa3625b88cd53f1", "0xabcbbb70b16f6e517c0ab4363ab76b46e4ff58576b5f8340e5c0e8cc0e02621b6e23d742d73b015822a238b17cfd7665", "0xa046937cc6ea6a2e1adae543353a9fe929c1ae4ad655be1cc051378482cf88b041e28b1e9a577e6ccff2d3570f55e200", "0x831279437282f315e65a60184ef158f0a3dddc15a648dc552bdc88b3e6fe8288d3cfe9f0031846d81350f5e7874b4b33", "0x993d7916fa213c6d66e7c4cafafc1eaec9a2a86981f91c31eb8a69c5df076c789cbf498a24c84e0ee77af95b42145026", "0x823907a3b6719f8d49b3a4b7c181bd9bb29fcf842d7c70660c4f351852a1e197ca46cf5e879b47fa55f616fa2b87ce5e", "0x8d228244e26132b234930ee14c75d88df0943cdb9c276a8faf167d259b7efc1beec2a87c112a6c608ad1600a239e9aae", "0xab6e55766e5bfb0cf0764ed909a8473ab5047d3388b4f46faeba2d1425c4754c55c6daf6ad4751e634c618b53e549529", "0xab0cab6860e55a84c5ad2948a7e0989e2b4b1fd637605634b118361497332df32d9549cb854b2327ca54f2bcb85eed8f", "0xb086b349ae03ef34f4b25a57bcaa5d1b29bd94f9ebf87e22be475adfe475c51a1230c1ebe13506cb72c4186192451658", "0x8a0b49d8a254ca6d91500f449cbbfbb69bb516c6948ac06808c65595e46773e346f97a5ce0ef7e5a5e0de278af22709c", "0xac49de11edaaf04302c73c578cc0824bdd165c0d6321be1c421c1950e68e4f3589aa3995448c9699e93c6ebae8803e27", "0x884f02d841cb5d8f4c60d1402469216b114ab4e93550b5bc1431756e365c4f870a9853449285384a6fa49e12ce6dc654", "0xb75f3a28fa2cc8d36b49130cb7448a23d73a7311d0185ba803ad55c8219741d451c110f48b786e96c728bc525903a54f", "0x80ae04dbd41f4a35e33f9de413b6ad518af0919e5a30cb0fa1b061b260420780bb674f828d37fd3b52b5a31673cbd803", "0xb9a8011eb5fcea766907029bf743b45262db3e49d24f84503687e838651ed11cb64c66281e20a0ae9f6aa51acc552263", "0x90bfdd75e2dc9cf013e22a5d55d2d2b8a754c96103a17524488e01206e67f8b6d52b1be8c4e3d5307d4fe06d0e51f54c", "0xb4af353a19b06203a815ec43e79a88578cc678c46f5a954b85bc5c53b84059dddba731f3d463c23bfd5273885c7c56a4", "0xaa125e96d4553b64f7140e5453ff5d2330318b69d74d37d283e84c26ad672fa00e3f71e530eb7e28be1e94afb9c4612e", "0xa18e060aee3d49cde2389b10888696436bb7949a79ca7d728be6456a356ea5541b55492b2138da90108bd1ce0e6f5524", "0x93e55f92bdbccc2de655d14b1526836ea2e52dba65eb3f87823dd458a4cb5079bf22ce6ef625cb6d6bfdd0995ab9a874", "0x89f5a683526b90c1c3ceebbb8dc824b21cff851ce3531b164f6626e326d98b27d3e1d50982e507d84a99b1e04e86a915", "0x83d1c38800361633a3f742b1cb2bfc528129496e80232611682ddbe403e92c2ac5373aea0bca93ecb5128b0b2b7a719e", "0x8ecba560ac94905e19ce8d9c7af217bf0a145d8c8bd38e2db82f5e94cc3f2f26f55819176376b51f154b4aab22056059", "0xa7e2a4a002b60291924850642e703232994acb4cfb90f07c94d1e0ecd2257bb583443283c20fc6017c37e6bfe85b7366", "0x93ed7316fa50b528f1636fc6507683a672f4f4403e55e94663f91221cc198199595bd02eef43d609f451acc9d9b36a24", "0xa1220a8ebc5c50ceed76a74bc3b7e0aa77f6884c71b64b67c4310ac29ce5526cb8992d6abc13ef6c8413ce62486a6795", "0xb2f6eac5c869ad7f4a25161d3347093e2f70e66cd925032747e901189355022fab3038bca4d610d2f68feb7e719c110b", "0xb703fa11a4d511ca01c7462979a94acb40b5d933759199af42670eb48f83df202fa0c943f6ab3b4e1cc54673ea3aab1e", "0xb5422912afbfcb901f84791b04f1ddb3c3fbdc76d961ee2a00c5c320e06d3cc5b5909c3bb805df66c5f10c47a292b13d", "0xad0934368da823302e1ac08e3ede74b05dfdbfffca203e97ffb0282c226814b65c142e6e15ec1e754518f221f01b30f7", "0xa1dd302a02e37df15bf2f1147efe0e3c06933a5a767d2d030e1132f5c3ce6b98e216b6145eb39e1e2f74e76a83165b8d", "0xa346aab07564432f802ae44738049a36f7ca4056df2d8f110dbe7fef4a3e047684dea609b2d03dc6bf917c9c2a47608f", "0xb96c5f682a5f5d02123568e50f5d0d186e4b2c4c9b956ec7aabac1b3e4a766d78d19bd111adb5176b898e916e49be2aa", "0x8a96676d56876fc85538db2e806e1cba20fd01aeb9fa3cb43ca6ca94a2c102639f65660db330e5d74a029bb72d6a0b39", "0xab0048336bd5c3def1a4064eadd49e66480c1f2abb4df46e03afbd8a3342c2c9d74ee35d79f08f4768c1646681440984", "0x888427bdf76caec90814c57ee1c3210a97d107dd88f7256f14f883ad0f392334b82be11e36dd8bfec2b37935177c7831", "0xb622b282becf0094a1916fa658429a5292ba30fb48a4c8066ce1ddcefb71037948262a01c95bab6929ed3a76ba5db9fe", "0xb5b9e005c1f456b6a368a3097634fb455723abe95433a186e8278dceb79d4ca2fbe21f8002e80027b3c531e5bf494629", "0xa3c6707117a1e48697ed41062897f55d8119403eea6c2ee88f60180f6526f45172664bfee96bf61d6ec0b7fbae6aa058", "0xb02a9567386a4fbbdb772d8a27057b0be210447348efe6feb935ceec81f361ed2c0c211e54787dc617cdffed6b4a6652", "0xa9b8364e40ef15c3b5902e5534998997b8493064fa2bea99600def58279bb0f64574c09ba11e9f6f669a8354dd79dc85", "0x9998a2e553a9aa9a206518fae2bc8b90329ee59ab23005b10972712389f2ec0ee746033c733092ffe43d73d33abbb8ef", "0x843a4b34d9039bf79df96d79f2d15e8d755affb4d83d61872daf540b68c0a3888cf8fc00d5b8b247b38524bcb3b5a856", "0x84f7128920c1b0bb40eee95701d30e6fc3a83b7bb3709f16d97e72acbb6057004ee7ac8e8f575936ca9dcb7866ab45f7", "0x918d3e2222e10e05edb34728162a899ad5ada0aaa491aeb7c81572a9c0d506e31d5390e1803a91ff3bd8e2bb15d47f31", "0x9442d18e2489613a7d47bb1cb803c8d6f3259d088cd079460976d87f7905ee07dea8f371b2537f6e1d792d36d7e42723", "0xb491976970fe091995b2ed86d629126523ccf3e9daf8145302faca71b5a71a5da92e0e05b62d7139d3efac5c4e367584", "0xaa628006235dc77c14cef4c04a308d66b07ac92d377df3de1a2e6ecfe3144f2219ad6d7795e671e1cb37a3641910b940", "0x99d386adaea5d4981d7306feecac9a555b74ffdc218c907c5aa7ac04abaead0ec2a8237300d42a3fbc464673e417ceed", "0x8f78e8b1556f9d739648ea3cab9606f8328b52877fe72f9305545a73b74d49884044ba9c1f1c6db7d9b7c7b7c661caba", "0x8fb357ae49932d0babdf74fc7aa7464a65d3b6a2b3acf4f550b99601d3c0215900cfd67f2b6651ef94cfc323bac79fae", "0x9906f2fa25c0290775aa001fb6198113d53804262454ae8b83ef371b5271bde189c0460a645829cb6c59f9ee3a55ce4d", "0x8f4379b3ebb50e052325b27655ca6a82e6f00b87bf0d2b680d205dd2c7afdc9ff32a9047ae71a1cdf0d0ce6b9474d878", "0xa85534e88c2bd43c043792eaa75e50914b21741a566635e0e107ae857aed0412035f7576cf04488ade16fd3f35fdbb87", "0xb4ce93199966d3c23251ca7f28ec5af7efea1763d376b0385352ffb2e0a462ef95c69940950278cf0e3dafd638b7bd36", "0xb10cb3d0317dd570aa73129f4acf63c256816f007607c19b423fb42f65133ce21f2f517e0afb41a5378cccf893ae14d0", "0xa9b231c9f739f7f914e5d943ed9bff7eba9e2c333fbd7c34eb1648a362ee01a01af6e2f7c35c9fe962b11152cddf35de", "0x99ff6a899e156732937fb81c0cced80ae13d2d44c40ba99ac183aa246103b31ec084594b1b7feb96da58f4be2dd5c0ed", "0x8748d15d18b75ff2596f50d6a9c4ce82f61ecbcee123a6ceae0e43cab3012a29b6f83cf67b48c22f6f9d757c6caf76b2", "0xb88ab05e4248b7fb634cf640a4e6a945d13e331237410f7217d3d17e3e384ddd48897e7a91e4516f1b9cbd30f35f238b", "0x8d826deaeeb84a3b2d2c04c2300ca592501f992810582d6ae993e0d52f6283a839dba66c6c72278cff5871802b71173b", "0xb36fed027c2f05a5ef625ca00b0364b930901e9e4420975b111858d0941f60e205546474bb25d6bfa6928d37305ae95f", "0xaf2fcfc6b87967567e8b8a13a4ed914478185705724e56ce68fb2df6d1576a0cf34a61e880997a0d35dc2c3276ff7501", "0xac351b919cd1fbf106feb8af2c67692bfcddc84762d18cea681cfa7470a5644839caace27efee5f38c87d3df306f4211", "0x8d6665fb1d4d8d1fa23bd9b8a86e043b8555663519caac214d1e3e3effbc6bee7f2bcf21e645f77de0ced279d69a8a8b", "0xa9fc1c2061756b2a1a169c1b149f212ff7f0d2488acd1c5a0197eba793cffa593fc6d1d1b40718aa75ca3ec77eff10e1", "0xaff64f0fa009c7a6cf0b8d7a22ddb2c8170c3cb3eec082e60d5aadb00b0040443be8936d728d99581e33c22178c41c87", "0x82e0b181adc5e3b1c87ff8598447260e839d53debfae941ebea38265575546c3a74a14b4325a030833a62ff6c52d9365", "0xb7ad43cbb22f6f892c2a1548a41dc120ab1f4e1b8dea0cb6272dd9cb02054c542ecabc582f7e16de709d48f5166cae86", "0x985e0c61094281532c4afb788ecb2dfcba998e974b5d4257a22040a161883908cdd068fe80f8eb49b8953cfd11acf43a", "0xae46895c6d67ea6d469b6c9c07b9e5d295d9ae73b22e30da4ba2c973ba83a130d7eef39717ec9d0f36e81d56bf742671", "0x8600177ea1f7e7ef90514b38b219a37dedfc39cb83297e4c7a5b479817ef56479d48cf6314820960c751183f6edf8b0e", "0xb9208ec1c1d7a1e99b59c62d3e4e61dfb706b0e940d09d3abfc3454c19749083260614d89cfd7e822596c3cdbcc6bb95", "0xa1e94042c796c2b48bc724352d2e9f3a22291d9a34705993357ddb6adabd76da6fc25dac200a8cb0b5bbd99ecddb7af6", "0xb29c3adedd0bcad8a930625bc4dfdc3552a9afd5ca6dd9c0d758f978068c7982b50b711aa0eb5b97f2b84ee784637835", "0xaf0632a238bb1f413c7ea8e9b4c3d68f2827bd2e38cd56024391fba6446ac5d19a780d0cfd4a78fe497d537b766a591a", "0xaaf6e7f7d54f8ef5e2e45dd59774ecbeecf8683aa70483b2a75be6a6071b5981bbaf1627512a65d212817acdfab2e428", "0x8c751496065da2e927cf492aa5ca9013b24f861d5e6c24b30bbf52ec5aaf1905f40f9a28175faef283dd4ed4f2182a09", "0x8952377d8e80a85cf67d6b45499f3bad5fd452ea7bcd99efc1b066c4720d8e5bff1214cea90fd1f972a7f0baac3d29be", "0xa1946ee543d1a6e21f380453be4d446e4130950c5fc3d075794eb8260f6f52d0a795c1ff91d028a648dc1ce7d9ab6b47", "0x89f3fefe37af31e0c17533d2ca1ce0884cc1dc97c15cbfab9c331b8debd94781c9396abef4bb2f163d09277a08d6adf0", "0xa2753f1e6e1a154fb117100a5bd9052137add85961f8158830ac20541ab12227d83887d10acf7fd36dcaf7c2596d8d23", "0x814955b4198933ee11c3883863b06ff98c7eceb21fc3e09df5f916107827ccf3323141983e74b025f46ae00284c9513b", "0x8cc5c6bb429073bfef47cae7b3bfccb0ffa076514d91a1862c6bda4d581e0df87db53cc6c130bf8a7826304960f5a34e", "0x909f22c1f1cdc87f7be7439c831a73484a49acbf8f23d47087d7cf867c64ef61da3bde85dc57d705682b4c3fc710d36e", "0x8048fee7f276fcd504aed91284f28e73693615e0eb3858fa44bcf79d7285a9001c373b3ef71d9a3054817ba293ebe28c", "0x94400e5cf5d2700ca608c5fe35ce14623f71cc24959f2bc27ca3684092850f76b67fb1f07ca9e5b2ca3062cf8ad17bd4", "0x81c2ae7d4d1b17f8b6de6a0430acc0d58260993980fe48dc2129c4948269cdc74f9dbfbf9c26b19360823fd913083d48", "0x8c41fe765128e63f6889d6a979f6a4342300327c8b245a8cfe3ecfbcac1e09c3da30e2a1045b24b78efc6d6d50c8c6ac", "0xa5dd4ae51ae48c8be4b218c312ade226cffce671cf121cb77810f6c0990768d6dd767badecb5c69921d5574d5e8433d3", "0xb7642e325f4ba97ae2a39c1c9d97b35aafd49d53dba36aed3f3cb0ca816480b3394079f46a48252d46596559c90f4d58", "0xae87375b40f35519e7bd4b1b2f73cd0b329b0c2cb9d616629342a71c6c304338445eda069b78ea0fbe44087f3de91e09", "0xb08918cb6f736855e11d3daca1ddfbdd61c9589b203b5493143227bf48e2c77c2e8c94b0d1aa2fab2226e0eae83f2681", "0xac36b84a4ac2ebd4d6591923a449c564e3be8a664c46092c09e875c2998eba16b5d32bfd0882fd3851762868e669f0b1", "0xa44800a3bb192066fa17a3f29029a23697240467053b5aa49b9839fb9b9b8b12bcdcbfc557f024b61f4f51a9aacdefcb", "0x9064c688fec23441a274cdf2075e5a449caf5c7363cc5e8a5dc9747183d2e00a0c69f2e6b3f6a7057079c46014c93b3b", "0xaa367b021469af9f5b764a79bb3afbe2d87fe1e51862221672d1a66f954b165778b7c27a705e0f93841fab4c8468344d", "0xa1a8bfc593d4ab71f91640bc824de5c1380ab2591cfdafcbc78a14b32de3c0e15f9d1b461d85c504baa3d4232c16bb53", "0x97df48da1799430f528184d30b6baa90c2a2f88f34cdfb342d715339c5ebd6d019aa693cea7c4993daafc9849063a3aa", "0xabd923831fbb427e06e0dd335253178a9e5791395c84d0ab1433c07c53c1209161097e9582fb8736f8a60bde62d8693e", "0x84cd1a43f1a438b43dc60ffc775f646937c4f6871438163905a3cebf1115f814ccd38a6ccb134130bff226306e412f32", "0x91426065996b0743c5f689eb3ca68a9f7b9e4d01f6c5a2652b57fa9a03d8dc7cd4bdbdab0ca5a891fee1e97a7f00cf02", "0xa4bee50249db3df7fd75162b28f04e57c678ba142ce4d3def2bc17bcb29e4670284a45f218dad3969af466c62a903757", "0x83141ebcc94d4681404e8b67a12a46374fded6df92b506aff3490d875919631408b369823a08b271d006d5b93136f317", "0xa0ea1c8883d58d5a784da3d8c8a880061adea796d7505c1f903d07c287c5467f71e4563fc0faafbc15b5a5538b0a7559", "0x89d9d480574f201a87269d26fb114278ed2c446328df431dc3556e3500e80e4cd01fcac196a2459d8646361ebda840df", "0x8bf302978973632dd464bec819bdb91304712a3ec859be071e662040620422c6e75eba6f864f764cffa2799272efec39", "0x922f666bc0fd58b6d7d815c0ae4f66d193d32fc8382c631037f59eeaeae9a8ca6c72d08e72944cf9e800b8d639094e77", "0x81ad8714f491cdff7fe4399f2eb20e32650cff2999dd45b9b3d996d54a4aba24cc6c451212e78c9e5550368a1a38fb3f", "0xb58fcf4659d73edb73175bd9139d18254e94c3e32031b5d4b026f2ed37aa19dca17ec2eb54c14340231615277a9d347e", "0xb365ac9c2bfe409b710928c646ea2fb15b28557e0f089d39878e365589b9d1c34baf5566d20bb28b33bb60fa133f6eff", "0x8fcae1d75b53ab470be805f39630d204853ca1629a14158bac2f52632277d77458dec204ff84b7b2d77e641c2045be65", "0xa03efa6bebe84f4f958a56e2d76b5ba4f95dd9ed7eb479edc7cc5e646c8d4792e5b0dfc66cc86aa4b4afe2f7a4850760", "0xaf1c823930a3638975fb0cc5c59651771b2719119c3cd08404fbd4ce77a74d708cefbe3c56ea08c48f5f10e6907f338f", "0x8260c8299b17898032c761c325ac9cabb4c5b7e735de81eacf244f647a45fb385012f4f8df743128888c29aefcaaad16", "0xab2f37a573c82e96a8d46198691cd694dfa860615625f477e41f91b879bc58a745784fccd8ffa13065834ffd150d881d", "0x986c746c9b4249352d8e5c629e8d7d05e716b3c7aab5e529ca969dd1e984a14b5be41528baef4c85d2369a42d7209216", "0xb25e32da1a8adddf2a6080725818b75bc67240728ad1853d90738485d8924ea1e202df0a3034a60ffae6f965ec55cf63", "0xa266e627afcebcefea6b6b44cbc50f5c508f7187e87d047b0450871c2a030042c9e376f3ede0afcf9d1952f089582f71", "0x86c3bbca4c0300606071c0a80dbdec21ce1dd4d8d4309648151c420854032dff1241a1677d1cd5de4e4de4385efda986", "0xb9a21a1fe2d1f3273a8e4a9185abf2ff86448cc98bfa435e3d68306a2b8b4a6a3ea33a155be3cb62a2170a86f77679a5", "0xb117b1ea381adce87d8b342cba3a15d492ff2d644afa28f22424cb9cbc820d4f7693dfc1a4d1b3697046c300e1c9b4c8", "0x9004c425a2e68870d6c69b658c344e3aa3a86a8914ee08d72b2f95c2e2d8a4c7bb0c6e7e271460c0e637cec11117bf8e", "0x86a18aa4783b9ebd9131580c8b17994825f27f4ac427b0929a1e0236907732a1c8139e98112c605488ee95f48bbefbfc", "0x84042243b955286482ab6f0b5df4c2d73571ada00716d2f737ca05a0d2e88c6349e8ee9e67934cfee4a1775dbf7f4800", "0x92c2153a4733a62e4e1d5b60369f3c26777c7d01cd3c8679212660d572bd3bac9b8a8a64e1f10f7dbf5eaa7579c4e423", "0x918454b6bb8e44a2afa144695ba8d48ae08d0cdfef4ad078f67709eddf3bb31191e8b006f04e82ea45a54715ef4d5817", "0xacf0b54f6bf34cf6ed6c2b39cf43194a40d68de6bcf1e4b82c34c15a1343e9ac3737885e1a30b78d01fa3a5125463db8", "0xa7d60dbe4b6a7b054f7afe9ee5cbbfeca0d05dc619e6041fa2296b549322529faddb8a11e949562309aecefb842ac380", "0x91ffb53e6d7e5f11159eaf13e783d6dbdfdb1698ed1e6dbf3413c6ea23492bbb9e0932230a9e2caac8fe899a17682795", "0xb6e8d7be5076ee3565d5765a710c5ecf17921dd3cf555c375d01e958a365ae087d4a88da492a5fb81838b7b92bf01143", "0xa8c6b763de2d4b2ed42102ef64eccfef31e2fb2a8a2776241c82912fa50fc9f77f175b6d109a97ede331307c016a4b1a", "0x99839f86cb700c297c58bc33e28d46b92931961548deac29ba8df91d3e11721b10ea956c8e16984f9e4acf1298a79b37", "0x8c2e2c338f25ea5c25756b7131cde0d9a2b35abf5d90781180a00fe4b8e64e62590dc63fe10a57fba3a31c76d784eb01", "0x9687d7df2f41319ca5469d91978fed0565a5f11f829ebadaa83db92b221755f76c6eacd7700735e75c91e257087512e3", "0x8795fdfb7ff8439c58b9bf58ed53873d2780d3939b902b9ddaaa4c99447224ced9206c3039a23c2c44bcc461e2bb637f", "0xa803697b744d2d087f4e2307218d48fa88620cf25529db9ce71e2e3bbcc65bac5e8bb9be04777ef7bfb5ed1a5b8e6170", "0x80f3d3efbbb9346ddd413f0a8e36b269eb5d7ff6809d5525ff9a47c4bcab2c01b70018b117f6fe05253775612ff70c6b", "0x9050e0e45bcc83930d4c505af35e5e4d7ca01cd8681cba92eb55821aececcebe32bb692ebe1a4daac4e7472975671067", "0x8d206812aac42742dbaf233e0c080b3d1b30943b54b60283515da005de05ea5caa90f91fedcfcba72e922f64d7040189", "0xa2d44faaeb2eff7915c83f32b13ca6f31a6847b1c1ce114ea240bac3595eded89f09b2313b7915ad882292e2b586d5b4", "0x961776c8576030c39f214ea6e0a3e8b3d32f023d2600958c098c95c8a4e374deeb2b9dc522adfbd6bda5949bdc09e2a2", "0x993fa7d8447407af0fbcd9e6d77f815fa5233ab00674efbcf74a1f51c37481445ae291cc7b76db7c178f9cb0e570e0fc", "0xabd5b1c78e05f9d7c8cc99bdaef8b0b6a57f2daf0f02bf492bec48ea4a27a8f1e38b5854da96efff11973326ff980f92", "0x8f15af4764bc275e6ccb892b3a4362cacb4e175b1526a9a99944e692fe6ccb1b4fc19abf312bb2a089cb1f344d91a779", "0xa09b27ccd71855512aba1d0c30a79ffbe7f6707a55978f3ced50e674b511a79a446dbc6d7946add421ce111135a460af", "0x94b2f98ce86a9271fbd4153e1fc37de48421fe3490fb3840c00f2d5a4d0ba8810c6a32880b002f6374b59e0a7952518b", "0x8650ac644f93bbcb88a6a0f49fee2663297fd4bc6fd47b6a89b9d8038d32370438ab3a4775ec9b58cb10aea8a95ef7b6", "0x95e5c2f2e84eed88c6980bbba5a1c0bb375d5a628bff006f7516d45bb7d723da676add4fdd45956f312e7bab0f052644", "0xb3278a3fa377ac93af7cfc9453f8cb594aae04269bbc99d2e0e45472ff4b6a2f97a26c4c57bf675b9d86f5e77a5d55d1", "0xb4bcbe6eb666a206e2ea2f877912c1d3b5bdbd08a989fc4490eb06013e1a69ad1ba08bcdac048bf29192312be399077b", "0xa76d70b78c99fffcbf9bb9886eab40f1ea4f99a309710b660b64cbf86057cbcb644d243f6e341711bb7ef0fedf0435a7", "0xb2093c1ee945dca7ac76ad5aed08eae23af31dd5a77c903fd7b6f051f4ab84425d33a03c3d45bf2907bc93c02d1f3ad8", "0x904b1f7534e053a265b22d20be859912b9c9ccb303af9a8d6f1d8f6ccdc5c53eb4a45a1762b880d8444d9be0cd55e7f9", "0x8f664a965d65bc730c9ef1ec7467be984d4b8eb46bd9b0d64e38e48f94e6e55dda19aeac82cbcf4e1473440e64c4ca18", "0x8bcee65c4cc7a7799353d07b114c718a2aae0cd10a3f22b7eead5185d159dafd64852cb63924bf87627d176228878bce", "0x8c78f2e3675096fef7ebaa898d2615cd50d39ca3d8f02b9bdfb07e67da648ae4be3da64838dffc5935fd72962c4b96c7", "0x8c40afd3701629421fec1df1aac4e849384ef2e80472c0e28d36cb1327acdf2826f99b357f3d7afdbc58a6347fc40b3c", "0xa197813b1c65a8ea5754ef782522a57d63433ef752215ecda1e7da76b0412ee619f58d904abd2e07e0c097048b6ae1dd", "0xa670542629e4333884ad7410f9ea3bd6f988df4a8f8a424ca74b9add2312586900cf9ae8bd50411f9146e82626b4af56", "0xa19875cc07ab84e569d98b8b67fb1dbbdfb59093c7b748fae008c8904a6fd931a63ca8d03ab5fea9bc8d263568125a9b", "0xb57e7f68e4eb1bd04aafa917b1db1bdab759a02aa8a9cdb1cba34ba8852b5890f655645c9b4e15d5f19bf37e9f2ffe9f", "0x8abe4e2a4f6462b6c64b3f10e45db2a53c2b0d3c5d5443d3f00a453e193df771eda635b098b6c8604ace3557514027af", "0x8459e4fb378189b22b870a6ef20183deb816cefbf66eca1dc7e86d36a2e011537db893729f500dc154f14ce24633ba47", "0x930851df4bc7913c0d8c0f7bd3b071a83668987ed7c397d3d042fdc0d9765945a39a3bae83da9c88cb6b686ed8aeeb26", "0x8078c9e5cd05e1a8c932f8a1d835f61a248b6e7133fcbb3de406bf4ffc0e584f6f9f95062740ba6008d98348886cf76b", "0xaddff62bb29430983fe578e3709b0949cdc0d47a13a29bc3f50371a2cb5c822ce53e2448cfaa01bcb6e0aa850d5a380e", "0x9433add687b5a1e12066721789b1db2edf9b6558c3bdc0f452ba33b1da67426abe326e9a34d207bfb1c491c18811bde1", "0x822beda3389963428cccc4a2918fa9a8a51cf0919640350293af70821967108cded5997adae86b33cb917780b097f1ca", "0xa7a9f52bda45e4148ed56dd176df7bd672e9b5ed18888ccdb405f47920fdb0844355f8565cefb17010b38324edd8315f", "0xb35c3a872e18e607b2555c51f9696a17fa18da1f924d503b163b4ec9fe22ed0c110925275cb6c93ce2d013e88f173d6a", "0xadf34b002b2b26ab84fc1bf94e05bd8616a1d06664799ab149363c56a6e0c807fdc473327d25632416e952ea327fcd95", "0xae4a6b9d22a4a3183fac29e2551e1124a8ce4a561a9a2afa9b23032b58d444e6155bb2b48f85c7b6d70393274e230db7", "0xa2ea3be4fc17e9b7ce3110284038d46a09e88a247b6971167a7878d9dcf36925d613c382b400cfa4f37a3ebea3699897", "0x8e5863786b641ce3140fbfe37124d7ad3925472e924f814ebfc45959aaf3f61dc554a597610b5defaecc85b59a99b50f", "0xaefde3193d0f700d0f515ab2aaa43e2ef1d7831c4f7859f48e52693d57f97fa9e520090f3ed700e1c966f4b76048e57f", "0x841a50f772956622798e5cd208dc7534d4e39eddee30d8ce133383d66e5f267e389254a0cdae01b770ecd0a9ca421929", "0x8fbc2bfd28238c7d47d4c03b1b910946c0d94274a199575e5b23242619b1de3497784e646a92aa03e3e24123ae4fcaba", "0x926999579c8eec1cc47d7330112586bdca20b4149c8b2d066f527c8b9f609e61ce27feb69db67eea382649c6905efcf9", "0xb09f31f305efcc65589adf5d3690a76cf339efd67cd43a4e3ced7b839507466e4be72dd91f04e89e4bbef629d46e68c0", "0xb917361f6b95f759642638e0b1d2b3a29c3bdef0b94faa30de562e6078c7e2d25976159df3edbacbf43614635c2640b4", "0x8e7e8a1253bbda0e134d62bfe003a2669d471b47bd2b5cde0ff60d385d8e62279d54022f5ac12053b1e2d3aaa6910b4c", "0xb69671a3c64e0a99d90b0ed108ce1912ff8ed983e4bddd75a370e9babde25ee1f5efb59ec707edddd46793207a8b1fe7", "0x910b2f4ebd37b7ae94108922b233d0920b4aba0bd94202c70f1314418b548d11d8e9caa91f2cd95aff51b9432d122b7f", "0x82f645c90dfb52d195c1020346287c43a80233d3538954548604d09fbab7421241cde8593dbc4acc4986e0ea39a27dd9", "0x8fee895f0a140d88104ce442fed3966f58ff9d275e7373483f6b4249d64a25fb5374bbdc6bce6b5ab0270c2847066f83", "0x84f5bd7aab27b2509397aeb86510dd5ac0a53f2c8f73799bf720f2f87a52277f8d6b0f77f17bc80739c6a7119b7eb062", "0x9903ceced81099d7e146e661bcf01cbaccab5ba54366b85e2177f07e2d8621e19d9c9c3eee14b9266de6b3f9b6ea75ae", "0xb9c16ea2a07afa32dd6c7c06df0dec39bca2067a9339e45475c98917f47e2320f6f235da353fd5e15b477de97ddc68dd", "0x9820a9bbf8b826bec61ebf886de2c4f404c1ebdc8bab82ee1fea816d9de29127ce1852448ff717a3fe8bbfe9e92012e5", "0x817224d9359f5da6f2158c2c7bf9165501424f063e67ba9859a07ab72ee2ee62eb00ca6da821cfa19065c3282ca72c74", "0x94b95c465e6cb00da400558a3c60cfec4b79b27e602ca67cbc91aead08de4b6872d8ea096b0dc06dca4525c8992b8547", "0xa2b539a5bccd43fa347ba9c15f249b417997c6a38c63517ca38394976baa08e20be384a360969ff54e7e721db536b3e5", "0x96caf707e34f62811ee8d32ccf28d8d6ec579bc33e424d0473529af5315c456fd026aa910c1fed70c91982d51df7d3ca", "0x8a77b73e890b644c6a142bdbac59b22d6a676f3b63ddafb52d914bb9d395b8bf5aedcbcc90429337df431ebd758a07a6", "0x8857830a7351025617a08bc44caec28d2fae07ebf5ffc9f01d979ce2a53839a670e61ae2783e138313929129790a51a1", "0xaa3e420321ed6f0aa326d28d1a10f13facec6f605b6218a6eb9cbc074801f3467bf013a456d1415a5536f12599efa3d3", "0x824aed0951957b00ea2f3d423e30328a3527bf6714cf9abbae84cf27e58e5c35452ba89ccc011de7c68c75d6e021d8f1", "0xa2e87cc06bf202e953fb1081933d8b4445527dde20e38ed1a4f440144fd8fa464a2b73e068b140562e9045e0f4bd3144", "0xae3b8f06ad97d7ae3a5e5ca839efff3e4824dc238c0c03fc1a8d2fc8aa546cdfd165b784a31bb4dec7c77e9305b99a4b", "0xb30c3e12395b1fb8b776f3ec9f87c70e35763a7b2ddc68f0f60a4982a84017f27c891a98561c830038deb033698ed7fc", "0x874e507757cd1177d0dff0b0c62ce90130324442a33da3b2c8ee09dbca5d543e3ecfe707e9f1361e7c7db641c72794bb", "0xb53012dd10b5e7460b57c092eaa06d6502720df9edbbe3e3f61a9998a272bf5baaac4a5a732ad4efe35d6fac6feca744", "0x85e6509d711515534d394e6cacbed6c81da710074d16ef3f4950bf2f578d662a494d835674f79c4d6315bced4defc5f0", "0xb6132b2a34b0905dcadc6119fd215419a7971fe545e52f48b768006944b4a9d7db1a74b149e2951ea48c083b752d0804", "0x989867da6415036d19b4bacc926ce6f4df7a556f50a1ba5f3c48eea9cefbb1c09da81481c8009331ee83f0859185e164", "0x960a6c36542876174d3fbc1505413e29f053ed87b8d38fef3af180491c7eff25200b45dd5fe5d4d8e63c7e8c9c00f4c8", "0x9040b59bd739d9cc2e8f6e894683429e4e876a8106238689ff4c22770ae5fdae1f32d962b30301fa0634ee163b524f35", "0xaf3fcd0a45fe9e8fe256dc7eab242ef7f582dd832d147444483c62787ac820fafc6ca55d639a73f76bfa5e7f5462ab8f", "0xb934c799d0736953a73d91e761767fdb78454355c4b15c680ce08accb57ccf941b13a1236980001f9e6195801cffd692", "0x8871e8e741157c2c326b22cf09551e78da3c1ec0fc0543136f581f1550f8bab03b0a7b80525c1e99812cdbf3a9698f96", "0xa8a977f51473a91d178ee8cfa45ffef8d6fd93ab1d6e428f96a3c79816d9c6a93cd70f94d4deda0125fd6816e30f3bea", "0xa7688b3b0a4fc1dd16e8ba6dc758d3cfe1b7cf401c31739484c7fa253cce0967df1b290769bcefc9d23d3e0cb19e6218", "0x8ae84322662a57c6d729e6ff9d2737698cc2da2daeb1f39e506618750ed23442a6740955f299e4a15dda6db3e534d2c6", "0xa04a961cdccfa4b7ef83ced17ab221d6a043b2c718a0d6cc8e6f798507a31f10bf70361f70a049bc8058303fa7f96864", "0xb463e39732a7d9daec8a456fb58e54b30a6e160aa522a18b9a9e836488cce3342bcbb2e1deab0f5e6ec0a8796d77197d", "0xb1434a11c6750f14018a2d3bcf94390e2948f4f187e93bb22070ca3e5393d339dc328cbfc3e48815f51929465ffe7d81", "0x84ff81d73f3828340623d7e3345553610aa22a5432217ef0ebd193cbf4a24234b190c65ca0873c22d10ea7b63bd1fbed", "0xb6fe2723f0c47757932c2ddde7a4f8434f665612f7b87b4009c2635d56b6e16b200859a8ade49276de0ef27a2b6c970a", "0x9742884ed7cd52b4a4a068a43d3faa02551a424136c85a9313f7cb58ea54c04aa83b0728fd741d1fe39621e931e88f8f", "0xb7d2d65ea4d1ad07a5dee39e40d6c03a61264a56b1585b4d76fc5b2a68d80a93a42a0181d432528582bf08d144c2d6a9", "0x88c0f66bada89f8a43e5a6ead2915088173d106c76f724f4a97b0f6758aed6ae5c37c373c6b92cdd4aea8f6261f3a374", "0x81f9c43582cb42db3900747eb49ec94edb2284999a499d1527f03315fd330e5a509afa3bff659853570e9886aab5b28b", "0x821f9d27d6beb416abf9aa5c79afb65a50ed276dbda6060103bc808bcd34426b82da5f23e38e88a55e172f5c294b4d40", "0x8ba307b9e7cb63a6c4f3851b321aebfdb6af34a5a4c3bd949ff7d96603e59b27ff4dc4970715d35f7758260ff942c9e9", "0xb142eb6c5f846de33227d0bda61d445a7c33c98f0a8365fe6ab4c1fabdc130849be597ef734305894a424ea715372d08", "0xa732730ae4512e86a741c8e4c87fee8a05ee840fec0e23b2e037d58dba8dde8d10a9bc5191d34d00598941becbbe467f", "0xadce6f7c30fd221f6b10a0413cc76435c4bb36c2d60bca821e5c67409fe9dbb2f4c36ef85eb3d734695e4be4827e9fd3", "0xa74f00e0f9b23aff7b2527ce69852f8906dab9d6abe62ecd497498ab21e57542e12af9918d4fd610bb09e10b0929c510", "0xa593b6b0ef26448ce4eb3ab07e84238fc020b3cb10d542ff4b16d4e2be1bcde3797e45c9cf753b8dc3b0ffdb63984232", "0xaed3913afccf1aa1ac0eb4980eb8426d0baccebd836d44651fd72af00d09fac488a870223c42aca3ceb39752070405ae", "0xb2c44c66a5ea7fde626548ba4cef8c8710191343d3dadfd3bb653ce715c0e03056a5303a581d47dde66e70ea5a2d2779", "0x8e5029b2ccf5128a12327b5103f7532db599846e422531869560ceaff392236434d87159f597937dbf4054f810c114f4", "0x82beed1a2c4477e5eb39fc5b0e773b30cfec77ef2b1bf17eadaf60eb35b6d0dd9d8cf06315c48d3546badb3f21cd0cca", "0x90077bd6cc0e4be5fff08e5d07a5a158d36cebd1d1363125bc4fae0866ffe825b26f933d4ee5427ba5cd0c33c19a7b06", "0xa7ec0d8f079970e8e34f0ef3a53d3e0e45428ddcef9cc776ead5e542ef06f3c86981644f61c5a637e4faf001fb8c6b3e", "0xae6d4add6d1a6f90b22792bc9d40723ee6850c27d0b97eefafd5b7fd98e424aa97868b5287cc41b4fbd7023bca6a322c", "0x831aa917533d077da07c01417feaa1408846363ba2b8d22c6116bb858a95801547dd88b7d7fa1d2e3f0a02bdeb2e103d", "0x96511b860b07c8a5ed773f36d4aa9d02fb5e7882753bf56303595bcb57e37ccc60288887eb83bef08c657ec261a021a2", "0x921d2a3e7e9790f74068623de327443666b634c8443aba80120a45bba450df920b2374d96df1ce3fb1b06dd06f8cf6e3", "0xaa74451d51fe82b4581ead8e506ec6cd881010f7e7dd51fc388eb9a557db5d3c6721f81c151d08ebd9c2591689fbc13e", "0xa972bfbcf4033d5742d08716c927c442119bdae336bf5dff914523b285ccf31953da2733759aacaa246a9af9f698342c", "0xad1fcd0cae0e76840194ce4150cb8a56ebed728ec9272035f52a799d480dfc85840a4d52d994a18b6edb31e79be6e8ad", "0xa2c69fe1d36f235215432dad48d75887a44c99dfa0d78149acc74087da215a44bdb5f04e6eef88ff7eff80a5a7decc77", "0xa94ab2af2b6ee1bc6e0d4e689ca45380d9fbd3c5a65b9bd249d266a4d4c07bf5d5f7ef2ae6000623aee64027892bf8fe", "0x881ec1fc514e926cdc66480ac59e139148ff8a2a7895a49f0dff45910c90cdda97b66441a25f357d6dd2471cddd99bb3", "0x884e6d3b894a914c8cef946a76d5a0c8351843b2bffa2d1e56c6b5b99c84104381dd1320c451d551c0b966f4086e60f9", "0x817c6c10ce2677b9fc5223500322e2b880583254d0bb0d247d728f8716f5e05c9ff39f135854342a1afecd9fbdcf7c46", "0xaaf4a9cb686a14619aa1fc1ac285dd3843ac3dd99f2b2331c711ec87b03491c02f49101046f3c5c538dc9f8dba2a0ac2", "0x97ecea5ce53ca720b5d845227ae61d70269a2f53540089305c86af35f0898bfd57356e74a8a5e083fa6e1ea70080bd31", "0xa22d811e1a20a75feac0157c418a4bfe745ccb5d29466ffa854dca03e395b6c3504a734341746b2846d76583a780b32e", "0x940cbaa0d2b2db94ae96b6b9cf2deefbfd059e3e5745de9aec4a25f0991b9721e5cd37ef71c631575d1a0c280b01cd5b", "0xae33cb4951191258a11044682de861bf8d92d90ce751b354932dd9f3913f542b6a0f8a4dc228b3cd9244ac32c4582832", "0xa580df5e58c4274fe0f52ac2da1837e32f5c9db92be16c170187db4c358f43e5cfdda7c5911dcc79d77a5764e32325f5", "0x81798178cb9d8affa424f8d3be67576ba94d108a28ccc01d330c51d5a63ca45bb8ca63a2f569b5c5fe1303cecd2d777f", "0x89975b91b94c25c9c3660e4af4047a8bacf964783010820dbc91ff8281509379cb3b24c25080d5a01174dd9a049118d5", "0xa7327fcb3710ed3273b048650bde40a32732ef40a7e58cf7f2f400979c177944c8bc54117ba6c80d5d4260801dddab79", "0x92b475dc8cb5be4b90c482f122a51bcb3b6c70593817e7e2459c28ea54a7845c50272af38119406eaadb9bcb993368d0", "0x9645173e9ecefc4f2eae8363504f7c0b81d85f8949a9f8a6c01f2d49e0a0764f4eacecf3e94016dd407fc14494fce9f9", "0x9215fd8983d7de6ae94d35e6698226fc1454977ae58d42d294be9aad13ac821562ad37d5e7ee5cdfe6e87031d45cd197", "0x810360a1c9b88a9e36f520ab5a1eb8bed93f52deefbe1312a69225c0a08edb10f87cc43b794aced9c74220cefcc57e7d", "0xad7e810efd61ed4684aeda9ed8bb02fb9ae4b4b63fda8217d37012b94ff1b91c0087043bfa4e376f961fff030c729f3b", "0x8b07c95c6a06db8738d10bb03ec11b89375c08e77f0cab7e672ce70b2685667ca19c7e1c8b092821d31108ea18dfd4c7", "0x968825d025ded899ff7c57245250535c732836f7565eab1ae23ee7e513201d413c16e1ba3f5166e7ac6cf74de8ceef4f", "0x908243370c5788200703ade8164943ad5f8c458219186432e74dbc9904a701ea307fd9b94976c866e6c58595fd891c4b", "0x959969d16680bc535cdc6339e6186355d0d6c0d53d7bbfb411641b9bf4b770fd5f575beef5deec5c4fa4d192d455c350", "0xad177f4f826a961adeac76da40e2d930748effff731756c797eddc4e5aa23c91f070fb69b19221748130b0961e68a6bb", "0x82f8462bcc25448ef7e0739425378e9bb8a05e283ce54aae9dbebaf7a3469f57833c9171672ad43a79778366c72a5e37", "0xa28fb275b1845706c2814d9638573e9bc32ff552ebaed761fe96fdbce70395891ca41c400ae438369264e31a2713b15f", "0x8a9c613996b5e51dadb587a787253d6081ea446bf5c71096980bf6bd3c4b69905062a8e8a3792de2d2ece3b177a71089", "0x8d5aefef9f60cb27c1db2c649221204dda48bb9bf8bf48f965741da051340e8e4cab88b9d15c69f3f84f4c854709f48a", "0x93ebf2ca6ad85ab6deace6de1a458706285b31877b1b4d7dcb9d126b63047efaf8c06d580115ec9acee30c8a7212fa55", "0xb3ee46ce189956ca298057fa8223b7fd1128cf52f39159a58bca03c71dd25161ac13f1472301f72aef3e1993fe1ab269", "0xa24d7a8d066504fc3f5027ccb13120e2f22896860e02c45b5eba1dbd512d6a17c28f39155ea581619f9d33db43a96f92", "0xae9ceacbfe12137db2c1a271e1b34b8f92e4816bad1b3b9b6feecc34df0f8b3b0f7ed0133acdf59c537d43d33fc8d429", "0x83967e69bf2b361f86361bd705dce0e1ad26df06da6c52b48176fe8dfcbeb03c462c1a4c9e649eff8c654b18c876fdef", "0x9148e6b814a7d779c19c31e33a068e97b597de1f8100513db3c581190513edc4d544801ce3dd2cf6b19e0cd6daedd28a", "0x94ccdafc84920d320ed22de1e754adea072935d3c5f8c2d1378ebe53d140ea29853f056fb3fb1e375846061a038cc9bc", "0xafb43348498c38b0fa5f971b8cdd3a62c844f0eb52bc33daf2f67850af0880fce84ecfb96201b308d9e6168a0d443ae3", "0x86d5736520a83538d4cd058cc4b4e84213ed00ebd6e7af79ae787adc17a92ba5359e28ba6c91936d967b4b28d24c3070", "0xb5210c1ff212c5b1e9ef9126e08fe120a41e386bb12c22266f7538c6d69c7fd8774f11c02b81fd4e88f9137b020801fe", "0xb78cfd19f94d24e529d0f52e18ce6185cb238edc6bd43086270fd51dd99f664f43dd4c7d2fe506762fbd859028e13fcf", "0xa6e7220598c554abdcc3fdc587b988617b32c7bb0f82c06205467dbedb58276cc07cae317a190f19d19078773f4c2bbb", "0xb88862809487ee430368dccd85a5d72fa4d163ca4aad15c78800e19c1a95be2192719801e315d86cff7795e0544a77e4", "0x87ecb13a03921296f8c42ceb252d04716f10e09c93962239fcaa0a7fef93f19ab3f2680bc406170108bc583e9ff2e721", "0xa810cd473832b6581c36ec4cb403f2849357ba2d0b54df98ef3004b8a530c078032922a81d40158f5fb0043d56477f6e", "0xa247b45dd85ca7fbb718b328f30a03f03c84aef2c583fbdc9fcc9eb8b52b34529e8c8f535505c10598b1b4dac3d7c647", "0x96ee0b91313c68bac4aa9e065ce9e1d77e51ca4cff31d6a438718c58264dee87674bd97fc5c6b8008be709521e4fd008", "0x837567ad073e42266951a9a54750919280a2ac835a73c158407c3a2b1904cf0d17b7195a393c71a18ad029cbd9cf79ee", "0xa6a469c44b67ebf02196213e7a63ad0423aab9a6e54acc6fcbdbb915bc043586993454dc3cd9e4be8f27d67c1050879b", "0x8712d380a843b08b7b294f1f06e2f11f4ad6bcc655fdde86a4d8bc739c23916f6fad2b902fe47d6212f03607907e9f0e", "0x920adfb644b534789943cdae1bdd6e42828dda1696a440af2f54e6b97f4f97470a1c6ea9fa6a2705d8f04911d055acd1", "0xa161c73adf584a0061e963b062f59d90faac65c9b3a936b837a10d817f02fcabfa748824607be45a183dd40f991fe83f", "0x874f4ecd408c76e625ea50bc59c53c2d930ee25baf4b4eca2440bfbffb3b8bc294db579caa7c68629f4d9ec24187c1ba", "0x8bff18087f112be7f4aa654e85c71fef70eee8ae480f61d0383ff6f5ab1a0508f966183bb3fc4d6f29cb7ca234aa50d3", "0xb03b46a3ca3bc743a173cbc008f92ab1aedd7466b35a6d1ca11e894b9482ea9dc75f8d6db2ddd1add99bfbe7657518b7", "0x8b4f3691403c3a8ad9e097f02d130769628feddfa8c2b3dfe8cff64e2bed7d6e5d192c1e2ba0ac348b8585e94acd5fa1", "0xa0d9ca4a212301f97591bf65d5ef2b2664766b427c9dd342e23cb468426e6a56be66b1cb41fea1889ac5d11a8e3c50a5", "0x8c93ed74188ca23b3df29e5396974b9cc135c91fdefdea6c0df694c8116410e93509559af55533a3776ac11b228d69b1", "0x82dd331fb3f9e344ebdeeb557769b86a2cc8cc38f6c298d7572a33aea87c261afa9dbd898989139b9fc16bc1e880a099", "0xa65faedf326bcfd8ef98a51410c78b021d39206704e8291cd1f09e096a66b9b0486be65ff185ca224c45918ac337ddeb", "0xa188b37d363ac072a766fd5d6fa27df07363feff1342217b19e3c37385e42ffde55e4be8355aceaa2f267b6d66b4ac41", "0x810fa3ba3e96d843e3bafd3f2995727f223d3567c8ba77d684c993ba1773c66551eb5009897c51b3fe9b37196984f5ec", "0x87631537541852da323b4353af45a164f68b304d24c01183bf271782e11687f3fcf528394e1566c2a26cb527b3148e64", "0xb721cb2b37b3c477a48e3cc0044167d51ff568a5fd2fb606e5aec7a267000f1ddc07d3db919926ae12761a8e017c767c", "0x904dfad4ba2cc1f6e60d1b708438a70b1743b400164cd981f13c064b8328d5973987d4fb9cf894068f29d3deaf624dfb", "0xa70491538893552c20939fae6be2f07bfa84d97e2534a6bbcc0f1729246b831103505e9f60e97a8fa7d2e6c1c2384579", "0x8726cf1b26b41f443ff7485adcfddc39ace2e62f4d65dd0bb927d933e262b66f1a9b367ded5fbdd6f3b0932553ac1735", "0xae8a11cfdf7aa54c08f80cb645e3339187ab3886babe9fae5239ba507bb3dd1c0d161ca474a2df081dcd3d63e8fe445e", "0x92328719e97ce60e56110f30a00ac5d9c7a2baaf5f8d22355d53c1c77941e3a1fec7d1405e6fbf8959665fe2ba7a8cad", "0x8d9d6255b65798d0018a8cccb0b6343efd41dc14ff2058d3eed9451ceaad681e4a0fa6af67b0a04318aa628024e5553d", "0xb70209090055459296006742d946a513f0cba6d83a05249ee8e7a51052b29c0ca9722dc4af5f9816a1b7938a5dac7f79", "0xaab7b766b9bf91786dfa801fcef6d575dc6f12b77ecc662eb4498f0312e54d0de9ea820e61508fc8aeee5ab5db529349", "0xa8104b462337748b7f086a135d0c3f87f8e51b7165ca6611264b8fb639d9a2f519926cb311fa2055b5fadf03da70c678", "0xb0d2460747d5d8b30fc6c6bd0a87cb343ddb05d90a51b465e8f67d499cfc5e3a9e365da05ae233bbee792cdf90ec67d5", "0xaa55f5bf3815266b4a149f85ed18e451c93de9163575e3ec75dd610381cc0805bb0a4d7c4af5b1f94d10231255436d2c", "0x8d4c6a1944ff94426151909eb5b99cfd92167b967dabe2bf3aa66bb3c26c449c13097de881b2cfc1bf052862c1ef7b03", "0x8862296162451b9b6b77f03bf32e6df71325e8d7485cf3335d66fd48b74c2a8334c241db8263033724f26269ad95b395", "0x901aa96deb26cda5d9321190ae6624d357a41729d72ef1abfd71bebf6139af6d690798daba53b7bc5923462115ff748a", "0x96c195ec4992728a1eb38cdde42d89a7bce150db43adbc9e61e279ea839e538deec71326b618dd39c50d589f78fc0614", "0xb6ff8b8aa0837b99a1a8b46fb37f20ad4aecc6a98381b1308697829a59b8442ffc748637a88cb30c9b1f0f28a926c4f6", "0x8d807e3dca9e7bef277db1d2cfb372408dd587364e8048b304eff00eacde2c723bfc84be9b98553f83cba5c7b3cba248", "0x8800c96adb0195c4fc5b24511450dee503c32bf47044f5e2e25bd6651f514d79a2dd9b01cd8c09f3c9d3859338490f57", "0x89fe366096097e38ec28dd1148887112efa5306cc0c3da09562aafa56f4eb000bf46ff79bf0bdd270cbde6bf0e1c8957", "0xaf409a90c2776e1e7e3760b2042507b8709e943424606e31e791d42f17873a2710797f5baaab4cc4a19998ef648556b0", "0x8d761863c9b6edbd232d35ab853d944f5c950c2b643f84a1a1327ebb947290800710ff01dcfa26dc8e9828481240e8b1", "0x90b95e9be1e55c463ed857c4e0617d6dc3674e99b6aa62ed33c8e79d6dfcf7d122f4f4cc2ee3e7c5a49170cb617d2e2e", "0xb3ff381efefabc4db38cc4727432e0301949ae4f16f8d1dea9b4f4de611cf5a36d84290a0bef160dac4e1955e516b3b0", "0xa8a84564b56a9003adcadb3565dc512239fc79572762cda7b5901a255bc82656bb9c01212ad33d6bef4fbbce18dacc87", "0x90a081890364b222eef54bf0075417f85e340d2fec8b7375995f598aeb33f26b44143ebf56fca7d8b4ebb36b5747b0eb", "0xade6ee49e1293224ddf2d8ab7f14bb5be6bc6284f60fd5b3a1e0cf147b73cff57cf19763b8a36c5083badc79c606b103", "0xb2fa99806dd2fa3de09320b615a2570c416c9bcdb052e592b0aead748bbe407ec9475a3d932ae48b71c2627eb81986a6", "0x91f3b7b73c8ccc9392542711c45fe6f236057e6efad587d661ad5cb4d6e88265f86b807bb1151736b1009ab74fd7acb4", "0x8800e2a46af96696dfbdcbf2ca2918b3dcf28ad970170d2d1783b52b8d945a9167d052beeb55f56c126da7ffa7059baa", "0x9862267a1311c385956b977c9aa08548c28d758d7ba82d43dbc3d0a0fd1b7a221d39e8399997fea9014ac509ff510ac4", "0xb7d24f78886fd3e2d283e18d9ad5a25c1a904e7d9b9104bf47da469d74f34162e27e531380dbbe0a9d051e6ffd51d6e7", "0xb0f445f9d143e28b9df36b0f2c052da87ee2ca374d9d0fbe2eff66ca6fe5fe0d2c1951b428d58f7314b7e74e45d445ea", "0xb63fc4083eabb8437dafeb6a904120691dcb53ce2938b820bb553da0e1eecd476f72495aacb72600cf9cad18698fd3db", "0xb9ffd8108eaebd582d665f8690fe8bb207fd85185e6dd9f0b355a09bac1bbff26e0fdb172bc0498df025414e88fe2eda", "0x967ed453e1f1a4c5b7b6834cc9f75c13f6889edc0cc91dc445727e9f408487bbf05c337103f61397a10011dfbe25d61d", "0x98ceb673aff36e1987d5521a3984a07079c3c6155974bb8b413e8ae1ce84095fe4f7862fba7aefa14753eb26f2a5805f", "0x85f01d28603a8fdf6ce6a50cb5c44f8a36b95b91302e3f4cd95c108ce8f4d212e73aec1b8d936520d9226802a2bd9136", "0x88118e9703200ca07910345fbb789e7a8f92bd80bbc79f0a9e040e8767d33df39f6eded403a9b636eabf9101e588482a", "0x90833a51eef1b10ed74e8f9bbd6197e29c5292e469c854eed10b0da663e2bceb92539710b1858bbb21887bd538d28d89", "0xb513b905ec19191167c6193067b5cfdf5a3d3828375360df1c7e2ced5815437dfd37f0c4c8f009d7fb29ff3c8793f560", "0xb1b6d405d2d18f9554b8a358cc7e2d78a3b34269737d561992c8de83392ac9a2857be4bf15de5a6c74e0c9d0f31f393c", "0xb828bd3e452b797323b798186607849f85d1fb20c616833c0619360dfd6b3e3aa000fd09dafe4b62d74abc41072ff1a9", "0x8efde67d0cca56bb2c464731879c9ac46a52e75bac702a63200a5e192b4f81c641f855ca6747752b84fe469cb7113b6c", "0xb2762ba1c89ac3c9a983c242e4d1c2610ff0528585ed5c0dfc8a2c0253551142af9b59f43158e8915a1da7cc26b9df67", "0x8a3f1157fb820d1497ef6b25cd70b7e16bb8b961b0063ad340d82a79ee76eb2359ca9e15e6d42987ed7f154f5eeaa2da", "0xa75e29f29d38f09c879f971c11beb5368affa084313474a5ecafa2896180b9e47ea1995c2733ec46f421e395a1d9cffe", "0x8e8c3dd3e7196ef0b4996b531ec79e4a1f211db5d5635e48ceb80ff7568b2ff587e845f97ee703bb23a60945ad64314a", "0x8e7f32f4a3e3c584af5e3d406924a0aa34024c42eca74ef6cc2a358fd3c9efaf25f1c03aa1e66bb94b023a2ee2a1cace", "0xab7dce05d59c10a84feb524fcb62478906b3fa045135b23afbede3bb32e0c678d8ebe59feabccb5c8f3550ea76cae44b", "0xb38bb4b44d827f6fd3bd34e31f9186c59e312dbfadd4a7a88e588da10146a78b1f8716c91ad8b806beb8da65cab80c4c", "0x9490ce9442bbbd05438c7f5c4dea789f74a7e92b1886a730544b55ba377840740a3ae4f2f146ee73f47c9278b0e233bc", "0x83c003fab22a7178eed1a668e0f65d4fe38ef3900044e9ec63070c23f2827d36a1e73e5c2b883ec6a2afe2450171b3b3", "0x9982f02405978ddc4fca9063ebbdb152f524c84e79398955e66fe51bc7c1660ec1afc3a86ec49f58d7b7dde03505731c", "0xab337bd83ccdd2322088ffa8d005f450ced6b35790f37ab4534313315ee84312adc25e99cce052863a8bedee991729ed", "0x8312ce4bec94366d88f16127a17419ef64285cd5bf9e5eda010319b48085966ed1252ed2f5a9fd3e0259b91bb65f1827", "0xa60d5a6327c4041b0c00a1aa2f0af056520f83c9ce9d9ccd03a0bd4d9e6a1511f26a422ea86bd858a1f77438adf07e6c", "0xb84a0a0b030bdad83cf5202aa9afe58c9820e52483ab41f835f8c582c129ee3f34aa096d11c1cd922eda02ea1196a882", "0x8077d105317f4a8a8f1aadeb05e0722bb55f11abcb490c36c0904401107eb3372875b0ac233144829e734f0c538d8c1d", "0x9202503bd29a6ec198823a1e4e098f9cfe359ed51eb5174d1ca41368821bfeebcbd49debfd02952c41359d1c7c06d2b1", "0xabc28c155e09365cb77ffead8dc8f602335ef93b2f44e4ef767ce8fc8ef9dd707400f3a722e92776c2e0b40192c06354", "0xb0f6d1442533ca45c9399e0a63a11f85ff288d242cea6cb3b68c02e77bd7d158047cae2d25b3bcd9606f8f66d9b32855", "0xb01c3d56a0db84dc94575f4b6ee2de4beca3230e86bed63e2066beb22768b0a8efb08ebaf8ac3dedb5fe46708b084807", "0x8c8634b0432159f66feaabb165842d1c8ac378f79565b1b90c381aa8450eb4231c3dad11ec9317b9fc2b155c3a771e32", "0x8e67f623d69ecd430c9ee0888520b6038f13a2b6140525b056dc0951f0cfed2822e62cf11d952a483107c5c5acac4826", "0x9590bb1cba816dd6acd5ac5fba5142c0a19d53573e422c74005e0bcf34993a8138c83124cad35a3df65879dba6134edd", "0x801cd96cde0749021a253027118d3ea135f3fcdbe895db08a6c145641f95ebd368dd6a1568d995e1d0084146aebe224a", "0x848b5d196427f6fc1f762ee3d36e832b64a76ec1033cfedc8b985dea93932a7892b8ef1035c653fb9dcd9ab2d9a44ac8", "0xa1017eb83d5c4e2477e7bd2241b2b98c4951a3b391081cae7d75965cadc1acaec755cf350f1f3d29741b0828e36fedea", "0x8d6d2785e30f3c29aad17bd677914a752f831e96d46caf54446d967cb2432be2c849e26f0d193a60bee161ea5c6fe90a", "0x935c0ba4290d4595428e034b5c8001cbd400040d89ab00861108e8f8f4af4258e41f34a7e6b93b04bc253d3b9ffc13bf", "0xaac02257146246998477921cef2e9892228590d323b839f3e64ea893b991b463bc2f47e1e5092ddb47e70b2f5bce7622", "0xb921fde9412970a5d4c9a908ae8ce65861d06c7679af577cf0ad0d5344c421166986bee471fd6a6cecb7d591f06ec985", "0x8ef4c37487b139d6756003060600bb6ebac7ea810b9c4364fc978e842f13ac196d1264fbe5af60d76ff6d9203d8e7d3f", "0x94b65e14022b5cf6a9b95f94be5ace2711957c96f4211c3f7bb36206bd39cfbd0ea82186cab5ad0577a23214a5c86e9e", "0xa31c166d2a2ca1d5a75a5920fef7532681f62191a50d8555fdaa63ba4581c3391cc94a536fc09aac89f64eafceec3f90", "0x919a8cc128de01e9e10f5d83b08b52293fdd41bde2b5ae070f3d95842d4a16e5331cf2f3d61c765570c8022403610fa4", "0xb23d6f8331eef100152d60483cfa14232a85ee712c8538c9b6417a5a7c5b353c2ac401390c6c215cb101f5cee6b5f43e", "0xab357160c08a18319510a571eafff154298ce1020de8e1dc6138a09fcb0fcbcdd8359f7e9386bda00b7b9cdea745ffdc", "0xab55079aea34afa5c0bd1124b9cdfe01f325b402fdfa017301bf87812eaa811ea5798c3aaf818074d420d1c782b10ada", "0xade616010dc5009e7fc4f8d8b00dc716686a5fa0a7816ad9e503e15839d3b909b69d9dd929b7575376434ffec0d2bea8", "0x863997b97ed46898a8a014599508fa3079f414b1f4a0c4fdc6d74ae8b444afa350f327f8bfc2a85d27f9e2d049c50135", "0x8d602ff596334efd4925549ed95f2aa762b0629189f0df6dbb162581657cf3ea6863cd2287b4d9c8ad52813d87fcd235", "0xb70f68c596dcdeed92ad5c6c348578b26862a51eb5364237b1221e840c47a8702f0fbc56eb520a22c0eed99795d3903e", "0x9628088f8e0853cefadee305a8bf47fa990c50fa96a82511bbe6e5dc81ef4b794e7918a109070f92fc8384d77ace226f", "0x97e26a46e068b605ce96007197ecd943c9a23881862f4797a12a3e96ba2b8d07806ad9e2a0646796b1889c6b7d75188c", "0xb1edf467c068cc163e2d6413cc22b16751e78b3312fe47b7ea82b08a1206d64415b2c8f2a677fa89171e82cc49797150", "0xa44d15ef18745b251429703e3cab188420e2d974de07251501799b016617f9630643fcd06f895634d8ecdd579e1bf000", "0xabd126df3917ba48c618ee4dbdf87df506193462f792874439043fa1b844466f6f4e0ff2e42516e63b5b23c0892b2695", "0xa2a67f57c4aa3c2aa1eeddbfd5009a89c26c2ce8fa3c96a64626aba19514beb125f27df8559506f737de3eae0f1fc18f", "0xa633e0132197e6038197304b296ab171f1d8e0d0f34dcf66fe9146ac385b0239232a8470b9205a4802ab432389f4836d", "0xa914b3a28509a906c3821463b936455d58ff45dcbe158922f9efb2037f2eb0ce8e92532d29b5d5a3fcd0d23fa773f272", "0xa0e1412ce4505daf1a2e59ce4f0fc0e0023e335b50d2b204422f57cd65744cc7a8ed35d5ef131a42c70b27111d3115b7", "0xa2339e2f2b6072e88816224fdd612c04d64e7967a492b9f8829db15367f565745325d361fd0607b0def1be384d010d9e", "0xa7309fc41203cb99382e8193a1dcf03ac190a7ce04835304eb7e341d78634e83ea47cb15b885601956736d04cdfcaa01", "0x81f3ccd6c7f5b39e4e873365f8c37b214e8ab122d04a606fbb7339dc3298c427e922ec7418002561d4106505b5c399ee", "0x92c121cf914ca549130e352eb297872a63200e99b148d88fbc9506ad882bec9d0203d65f280fb5b0ba92e336b7f932e8", "0xa4b330cf3f064f5b131578626ad7043ce2a433b6f175feb0b52d36134a454ca219373fd30d5e5796410e005b69082e47", "0x86fe5774112403ad83f9c55d58317eeb17ad8e1176d9f2f69c2afb7ed83bc718ed4e0245ceab4b377f5f062dcd4c00e7", "0x809d152a7e2654c7fd175b57f7928365a521be92e1ed06c05188a95864ddb25f7cab4c71db7d61bbf4cae46f3a1d96ce", "0xb82d663e55c2a5ada7e169e9b1a87bc1c0177baf1ec1c96559b4cb1c5214ce1ddf2ab8d345014cab6402f3774235cf5a", "0x86580af86df1bd2c385adb8f9a079e925981b7184db66fc5fe5b14cddb82e7d836b06eaeef14924ac529487b23dae111", "0xb5f5f4c5c94944ecc804df6ab8687d64e27d988cbfeae1ba7394e0f6adbf778c5881ead7cd8082dd7d68542b9bb4ecd5", "0xa6016916146c2685c46e8fdd24186394e2d5496e77e08c0c6a709d4cd7dfa97f1efcef94922b89196819076a91ad37b5", "0xb778e7367ded3b6eab53d5fc257f7a87e8faf74a593900f2f517220add2125be3f6142022660d8181df8d164ad9441ce", "0x8581b2d36abe6f553add4d24be761bec1b8efaa2929519114346615380b3c55b59e6ad86990e312f7e234d0203bdf59b", "0x9917e74fd45c3f71a829ff5498a7f6b5599b48c098dda2339bf04352bfc7f368ccf1a407f5835901240e76452ae807d7", "0xafd196ce6f9335069138fd2e3d133134da253978b4ce373152c0f26affe77a336505787594022e610f8feb722f7cc1fb", "0xa477491a1562e329764645e8f24d8e228e5ef28c9f74c6b5b3abc4b6a562c15ffb0f680d372aed04d9e1bf944dece7be", "0x9767440d58c57d3077319d3a330e5322b9ba16981ec74a5a14d53462eab59ae7fd2b14025bfc63b268862094acb444e6", "0x80986d921be3513ef69264423f351a61cb48390c1be8673aee0f089076086aaebea7ebe268fd0aa7182695606116f679", "0xa9554c5c921c07b450ee04e34ec58e054ac1541b26ce2ce5a393367a97348ba0089f53db6660ad76b60278b66fd12e3e", "0x95097e7d2999b3e84bf052c775581cf361325325f4a50192521d8f4693c830bed667d88f482dc1e3f833aa2bd22d2cbf", "0x9014c91d0f85aefd28436b5228c12f6353c055a9326c7efbf5e071e089e2ee7c070fcbc84c5fafc336cbb8fa6fec1ca1", "0x90f57ba36ee1066b55d37384942d8b57ae00f3cf9a3c1d6a3dfee1d1af42d4b5fa9baeb0cd7e46687d1d6d090ddb931d", "0x8e4b1db12fd760a17214c9e47f1fce6e43c0dbb4589a827a13ac61aaae93759345697bb438a00edab92e0b7b62414683", "0x8022a959a513cdc0e9c705e0fc04eafd05ff37c867ae0f31f6d01cddd5df86138a426cab2ff0ac8ff03a62e20f7e8f51", "0x914e9a38829834c7360443b8ed86137e6f936389488eccf05b4b4db7c9425611705076ecb3f27105d24b85c852be7511", "0x957fb10783e2bd0db1ba66b18e794df710bc3b2b05776be146fa5863c15b1ebdd39747b1a95d9564e1772cdfc4f37b8a", "0xb6307028444daed8ed785ac9d0de76bc3fe23ff2cc7e48102553613bbfb5afe0ebe45e4212a27021c8eb870721e62a1f", "0x8f76143597777d940b15a01b39c5e1b045464d146d9a30a6abe8b5d3907250e6c7f858ff2308f8591e8b0a7b3f3c568a", "0x96163138ac0ce5fd00ae9a289648fd9300a0ca0f63a88481d703ecd281c06a52a3b5178e849e331f9c85ca4ba398f4cc", "0xa63ef47c3e18245b0482596a09f488a716df3cbd0f9e5cfabed0d742843e65db8961c556f45f49762f3a6ac8b627b3ef", "0x8cb595466552e7c4d42909f232d4063e0a663a8ef6f6c9b7ce3a0542b2459cde04e0e54c7623d404acb5b82775ac04f6", "0xb47fe69960eb45f399368807cff16d941a5a4ebad1f5ec46e3dc8a2e4d598a7e6114d8f0ca791e9720fd786070524e2b", "0x89eb5ff83eea9df490e5beca1a1fbbbbcf7184a37e2c8c91ede7a1e654c81e8cd41eceece4042ea7918a4f4646b67fd6", "0xa84f5d155ed08b9054eecb15f689ba81e44589e6e7207a99790c598962837ca99ec12344105b16641ca91165672f7153", "0xa6cc8f25c2d5b2d2f220ec359e6a37a52b95fa6af6e173c65e7cd55299eff4aa9e6d9e6f2769e6459313f1f2aecb0fab", "0xafcde944411f017a9f7979755294981e941cc41f03df5e10522ef7c7505e5f1babdd67b3bf5258e8623150062eb41d9b", "0x8fab39f39c0f40182fcd996ade2012643fe7731808afbc53f9b26900b4d4d1f0f5312d9d40b3df8baa4739970a49c732", "0xae193af9726da0ebe7df1f9ee1c4846a5b2a7621403baf8e66c66b60f523e719c30c6b4f897bb14b27d3ff3da8392eeb", "0x8ac5adb82d852eba255764029f42e6da92dcdd0e224d387d1ef94174038db9709ac558d90d7e7c57ad4ce7f89bbfc38c", "0xa2066b3458fdf678ee487a55dd5bfb74fde03b54620cb0e25412a89ee28ad0d685e309a51e3e4694be2fa6f1593a344c", "0x88d031745dd0ae07d61a15b594be5d4b2e2a29e715d081649ad63605e3404b0c3a5353f0fd9fad9c05c18e93ce674fa1", "0x8283cfb0ef743a043f2b77ecaeba3005e2ca50435585b5dd24777ee6bce12332f85e21b446b536da38508807f0f07563", "0xb376de22d5f6b0af0b59f7d9764561f4244cf8ffe22890ecd3dcf2ff1832130c9b821e068c9d8773136f4796721e5963", "0xae3afc50c764f406353965363840bf28ee85e7064eb9d5f0bb3c31c64ab10f48c853e942ee2c9b51bae59651eaa08c2f", "0x948b204d103917461a01a6c57a88f2d66b476eae5b00be20ec8c747650e864bc8a83aee0aff59cb7584b7a3387e0ee48", "0x81ab098a082b07f896c5ffd1e4446cb7fb44804cbbf38d125208b233fc82f8ec9a6a8d8dd1c9a1162dc28ffeec0dde50", "0xa149c6f1312821ced2969268789a3151bdda213451760b397139a028da609c4134ac083169feb0ee423a0acafd10eceb", "0xb0ac9e27a5dadaf523010f730b28f0ebac01f460d3bbbe277dc9d44218abb5686f4fac89ae462682fef9edbba663520a", "0x8d0e0073cca273daaaa61b6fc54bfe5a009bc3e20ae820f6c93ba77b19eca517d457e948a2de5e77678e4241807157cb", "0xad61d3a2edf7c7533a04964b97499503fd8374ca64286dba80465e68fe932e96749b476f458c6fc57cb1a7ca85764d11", "0x90eb5e121ae46bc01a30881eaa556f46bd8457a4e80787cf634aab355082de34ac57d7f497446468225f7721e68e2a47", "0x8cdac557de7c42d1f3780e33dec1b81889f6352279be81c65566cdd4952d4c15d79e656cbd46035ab090b385e90245ef", "0x82b67e61b88b84f4f4d4f65df37b3e3dcf8ec91ea1b5c008fdccd52da643adbe6468a1cfdb999e87d195afe2883a3b46", "0x8503b467e8f5d6048a4a9b78496c58493a462852cab54a70594ae3fd064cfd0deb4b8f336a262155d9fedcaa67d2f6fd", "0x8db56c5ac763a57b6ce6832930c57117058e3e5a81532b7d19346346205e2ec614eb1a2ee836ef621de50a7bc9b7f040", "0xad344699198f3c6e8c0a3470f92aaffc805b76266734414c298e10b5b3797ca53578de7ccb2f458f5e0448203f55282b", "0x80602032c43c9e2a09154cc88b83238343b7a139f566d64cb482d87436b288a98f1ea244fd3bff8da3c398686a900c14", "0xa6385bd50ecd548cfb37174cdbb89e10025b5cadaf3cff164c95d7aef5a33e3d6a9bf0c681b9e11db9ef54ebeee2a0c1", "0xabf2d95f4aa34b0581eb9257a0cc8462b2213941a5deb8ba014283293e8b36613951b61261cc67bbd09526a54cbbff76", "0xa3d5de52f48df72c289ff713e445991f142390798cd42bd9d9dbefaee4af4f5faf09042d126b975cf6b98711c3072553", "0x8e627302ff3d686cff8872a1b7c2a57b35f45bf2fc9aa42b049d8b4d6996a662b8e7cbac6597f0cb79b0cc4e29fbf133", "0x8510702e101b39a1efbf4e504e6123540c34b5689645e70d0bac1ecc1baf47d86c05cef6c4317a4e99b4edaeb53f2d00", "0xaa173f0ecbcc6088f878f8726d317748c81ebf501bba461f163b55d66099b191ec7c55f7702f351a9c8eb42cfa3280e2", "0xb560a697eafab695bcef1416648a0a664a71e311ecbe5823ae903bd0ed2057b9d7574b9a86d3fe22aa3e6ddce38ea513", "0x8df6304a3d9cf40100f3f687575419c998cd77e5cc27d579cf4f8e98642de3609af384a0337d145dd7c5635172d26a71", "0x8105c7f3e4d30a29151849673853b457c1885c186c132d0a98e63096c3774bc9deb956cf957367e633d0913680bda307", "0x95373fc22c0917c3c2044ac688c4f29a63ed858a45c0d6d2d0fe97afd6f532dcb648670594290c1c89010ecc69259bef", "0x8c2fae9bcadab341f49b55230310df93cac46be42d4caa0d42e45104148a91e527af1b4209c0d972448162aed28fab64", "0xb05a77baab70683f76209626eaefdda2d36a0b66c780a20142d23c55bd479ddd4ad95b24579384b6cf62c8eb4c92d021", "0x8e6bc6a7ea2755b4aaa19c1c1dee93811fcde514f03485fdc3252f0ab7f032c315614f6336e57cea25dcfb8fb6084eeb", "0xb656a27d06aade55eadae2ad2a1059198918ea6cc3fd22c0ed881294d34d5ac7b5e4700cc24350e27d76646263b223aa", "0xa296469f24f6f56da92d713afcd4dd606e7da1f79dc4e434593c53695847eefc81c7c446486c4b3b8c8d00c90c166f14", "0x87a326f57713ac2c9dffeb3af44b9f3c613a8f952676fc46343299122b47ee0f8d792abaa4b5db6451ced5dd153aabd0", "0xb689e554ba9293b9c1f6344a3c8fcb6951d9f9eac4a2e2df13de021aade7c186be27500e81388e5b8bcab4c80f220a31", "0x87ae0aa0aa48eac53d1ca5a7b93917de12db9e40ceabf8fdb40884ae771cfdf095411deef7c9f821af0b7070454a2608", "0xa71ffa7eae8ace94e6c3581d4cb2ad25d48cbd27edc9ec45baa2c8eb932a4773c3272b2ffaf077b40f76942a1f3af7f2", "0x94c218c91a9b73da6b7a495b3728f3028df8ad9133312fc0c03e8c5253b7ccb83ed14688fd4602e2fd41f29a0bc698bd", "0xae1e77b90ca33728af07a4c03fb2ef71cd92e2618e7bf8ed4d785ce90097fc4866c29999eb84a6cf1819d75285a03af2", "0xb7a5945b277dab9993cf761e838b0ac6eaa903d7111fca79f9fde3d4285af7a89bf6634a71909d095d7619d913972c9c", "0x8c43b37be02f39b22029b20aca31bff661abce4471dca88aa3bddefd9c92304a088b2dfc8c4795acc301ca3160656af2", "0xb32e5d0fba024554bd5fe8a793ebe8003335ddd7f585876df2048dcf759a01285fecb53daae4950ba57f3a282a4d8495", "0x85ea7fd5e10c7b659df5289b2978b2c89e244f269e061b9a15fcab7983fc1962b63546e82d5731c97ec74b6804be63ef", "0x96b89f39181141a7e32986ac02d7586088c5a9662cec39843f397f3178714d02f929af70630c12cbaba0268f8ba2d4fa", "0x929ab1a2a009b1eb37a2817c89696a06426529ebe3f306c586ab717bd34c35a53eca2d7ddcdef36117872db660024af9", "0xa696dccf439e9ca41511e16bf3042d7ec0e2f86c099e4fc8879d778a5ea79e33aa7ce96b23dc4332b7ba26859d8e674d", "0xa8fe69a678f9a194b8670a41e941f0460f6e2dbc60470ab4d6ae2679cc9c6ce2c3a39df2303bee486dbfde6844e6b31a", "0x95f58f5c82de2f2a927ca99bf63c9fc02e9030c7e46d0bf6b67fe83a448d0ae1c99541b59caf0e1ccab8326231af09a5", "0xa57badb2c56ca2c45953bd569caf22968f76ed46b9bac389163d6fe22a715c83d5e94ae8759b0e6e8c2f27bff7748f3f", "0x868726fd49963b24acb5333364dffea147e98f33aa19c7919dc9aca0fd26661cfaded74ede7418a5fadbe7f5ae67b67b", "0xa8d8550dcc64d9f1dd7bcdab236c4122f2b65ea404bb483256d712c7518f08bb028ff8801f1da6aed6cbfc5c7062e33b", "0x97e25a87dae23155809476232178538d4bc05d4ff0882916eb29ae515f2a62bfce73083466cc0010ca956aca200aeacc", "0xb4ea26be3f4bd04aa82d7c4b0913b97bcdf5e88b76c57eb1a336cbd0a3eb29de751e1bc47c0e8258adec3f17426d0c71", "0x99ee555a4d9b3cf2eb420b2af8e3bc99046880536116d0ce7193464ac40685ef14e0e3c442f604e32f8338cb0ef92558", "0x8c64efa1da63cd08f319103c5c7a761221080e74227bbc58b8fb35d08aa42078810d7af3e60446cbaff160c319535648", "0x8d9fd88040076c28420e3395cbdfea402e4077a3808a97b7939d49ecbcf1418fe50a0460e1c1b22ac3f6e7771d65169a", "0xae3c19882d7a9875d439265a0c7003c8d410367627d21575a864b9cb4918de7dbdb58a364af40c5e045f3df40f95d337", "0xb4f7bfacab7b2cafe393f1322d6dcc6f21ffe69cd31edc8db18c06f1a2b512c27bd0618091fd207ba8df1808e9d45914", "0x94f134acd0007c623fb7934bcb65ef853313eb283a889a3ffa79a37a5c8f3665f3d5b4876bc66223610c21dc9b919d37", "0xaa15f74051171daacdc1f1093d3f8e2d13da2833624b80a934afec86fc02208b8f55d24b7d66076444e7633f46375c6a", "0xa32d6bb47ef9c836d9d2371807bafbbbbb1ae719530c19d6013f1d1f813c49a60e4fa51d83693586cba3a840b23c0404", "0xb61b3599145ea8680011aa2366dc511a358b7d67672d5b0c5be6db03b0efb8ca5a8294cf220ea7409621f1664e00e631", "0x859cafc3ee90b7ececa1ed8ef2b2fc17567126ff10ca712d5ffdd16aa411a5a7d8d32c9cab1fbf63e87dce1c6e2f5f53", "0xa2fef1b0b2874387010e9ae425f3a9676d01a095d017493648bcdf3b31304b087ccddb5cf76abc4e1548b88919663b6b", "0x939e18c73befc1ba2932a65ede34c70e4b91e74cc2129d57ace43ed2b3af2a9cc22a40fbf50d79a63681b6d98852866d", "0xb3b4259d37b1b14aee5b676c9a0dd2d7f679ab95c120cb5f09f9fbf10b0a920cb613655ddb7b9e2ba5af4a221f31303c", "0x997255fe51aaca6e5a9cb3359bcbf25b2bb9e30649bbd53a8a7c556df07e441c4e27328b38934f09c09d9500b5fabf66", "0xabb91be2a2d860fd662ed4f1c6edeefd4da8dc10e79251cf87f06029906e7f0be9b486462718f0525d5e049472692cb7", "0xb2398e593bf340a15f7801e1d1fbda69d93f2a32a889ec7c6ae5e8a37567ac3e5227213c1392ee86cfb3b56ec2787839", "0x8ddf10ccdd72922bed36829a36073a460c2118fc7a56ff9c1ac72581c799b15c762cb56cb78e3d118bb9f6a7e56cb25e", "0x93e6bc0a4708d16387cacd44cf59363b994dc67d7ada7b6d6dbd831c606d975247541b42b2a309f814c1bfe205681fc6", "0xb93fc35c05998cffda2978e12e75812122831523041f10d52f810d34ff71944979054b04de0117e81ddf5b0b4b3e13c0", "0x92221631c44d60d68c6bc7b287509f37ee44cbe5fdb6935cee36b58b17c7325098f98f7910d2c3ca5dc885ad1d6dabc7", "0xa230124424a57fad3b1671f404a94d7c05f4c67b7a8fbacfccea28887b78d7c1ed40b92a58348e4d61328891cd2f6cee", "0xa6a230edb8518a0f49d7231bc3e0bceb5c2ac427f045819f8584ba6f3ae3d63ed107a9a62aad543d7e1fcf1f20605706", "0x845be1fe94223c7f1f97d74c49d682472585d8f772762baad8a9d341d9c3015534cc83d102113c51a9dea2ab10d8d27b", "0xb44262515e34f2db597c8128c7614d33858740310a49cdbdf9c8677c5343884b42c1292759f55b8b4abc4c86e4728033", "0x805592e4a3cd07c1844bc23783408310accfdb769cca882ad4d07d608e590a288b7370c2cb327f5336e72b7083a0e30f", "0x95153e8b1140df34ee864f4ca601cb873cdd3efa634af0c4093fbaede36f51b55571ab271e6a133020cd34db8411241f", "0x82878c1285cfa5ea1d32175c9401f3cc99f6bb224d622d3fd98cc7b0a27372f13f7ab463ce3a33ec96f9be38dbe2dfe3", "0xb7588748f55783077c27fc47d33e20c5c0f5a53fc0ac10194c003aa09b9f055d08ec971effa4b7f760553997a56967b3", "0xb36b4de6d1883b6951f59cfae381581f9c6352fcfcf1524fccdab1571a20f80441d9152dc6b48bcbbf00371337ca0bd5", "0x89c5523f2574e1c340a955cbed9c2f7b5fbceb260cb1133160dabb7d41c2f613ec3f6e74bbfab3c4a0a6f0626dbe068f", "0xa52f58cc39f968a9813b1a8ddc4e83f4219e4dd82c7aa1dd083bea7edf967151d635aa9597457f879771759b876774e4", "0x8300a67c2e2e123f89704abfde095463045dbd97e20d4c1157bab35e9e1d3d18f1f4aaba9cbe6aa2d544e92578eaa1b6", "0xac6a7f2918768eb6a43df9d3a8a04f8f72ee52f2e91c064c1c7d75cad1a3e83e5aba9fe55bb94f818099ac91ccf2e961", "0x8d64a2b0991cf164e29835c8ddef6069993a71ec2a7de8157bbfa2e00f6367be646ed74cbaf524f0e9fe13fb09fa15fd", "0x8b2ffe5a545f9f680b49d0a9797a4a11700a2e2e348c34a7a985fc278f0f12def6e06710f40f9d48e4b7fbb71e072229", "0x8ab8f71cd337fa19178924e961958653abf7a598e3f022138b55c228440a2bac4176cea3aea393549c03cd38a13eb3fc", "0x8419d28318c19ea4a179b7abb43669fe96347426ef3ac06b158d79c0acf777a09e8e770c2fb10e14b3a0421705990b23", "0x8bacdac310e1e49660359d0a7a17fe3d334eb820e61ae25e84cb52f863a2f74cbe89c2e9fc3283745d93a99b79132354", "0xb57ace3fa2b9f6b2db60c0d861ace7d7e657c5d35d992588aeed588c6ce3a80b6f0d49f8a26607f0b17167ab21b675e4", "0x83e265cde477f2ecc164f49ddc7fb255bb05ff6adc347408353b7336dc3a14fdedc86d5a7fb23f36b8423248a7a67ed1", "0xa60ada971f9f2d79d436de5d3d045f5ab05308cae3098acaf5521115134b2a40d664828bb89895840db7f7fb499edbc5", "0xa63eea12efd89b62d3952bf0542a73890b104dd1d7ff360d4755ebfa148fd62de668edac9eeb20507967ea37fb220202", "0xa0275767a270289adc991cc4571eff205b58ad6d3e93778ddbf95b75146d82517e8921bd0d0564e5b75fa0ccdab8e624", "0xb9b03fd3bf07201ba3a039176a965d736b4ef7912dd9e9bf69fe1b57c330a6aa170e5521fe8be62505f3af81b41d7806", "0xa95f640e26fb1106ced1729d6053e41a16e4896acac54992279ff873e5a969aad1dcfa10311e28b8f409ac1dab7f03bb", "0xb144778921742418053cb3c70516c63162c187f00db2062193bb2c14031075dbe055d020cde761b26e8c58d0ea6df2c1", "0x8432fbb799e0435ef428d4fefc309a05dd589bce74d7a87faf659823e8c9ed51d3e42603d878e80f439a38be4321c2fa", "0xb08ddef14e42d4fd5d8bf39feb7485848f0060d43b51ed5bdda39c05fe154fb111d29719ee61a23c392141358c0cfcff", "0x8ae3c5329a5e025b86b5370e06f5e61177df4bda075856fade20a17bfef79c92f54ed495f310130021ba94fb7c33632b", "0x92b6d3c9444100b4d7391febfc1dddaa224651677c3695c47a289a40d7a96d200b83b64e6d9df51f534564f272a2c6c6", "0xb432bc2a3f93d28b5e506d68527f1efeb2e2570f6be0794576e2a6ef9138926fdad8dd2eabfa979b79ab7266370e86bc", "0x8bc315eacedbcfc462ece66a29662ca3dcd451f83de5c7626ef8712c196208fb3d8a0faf80b2e80384f0dd9772f61a23", "0xa72375b797283f0f4266dec188678e2b2c060dfed5880fc6bb0c996b06e91a5343ea2b695adaab0a6fd183b040b46b56", "0xa43445036fbaa414621918d6a897d3692fdae7b2961d87e2a03741360e45ebb19fcb1703d23f1e15bb1e2babcafc56ac", "0xb9636b2ffe305e63a1a84bd44fb402442b1799bd5272638287aa87ca548649b23ce8ce7f67be077caed6aa2dbc454b78", "0x99a30bf0921d854c282b83d438a79f615424f28c2f99d26a05201c93d10378ab2cd94a792b571ddae5d4e0c0013f4006", "0x8648e3c2f93d70b392443be116b48a863e4b75991bab5db656a4ef3c1e7f645e8d536771dfe4e8d1ceda3be8d32978b0", "0xab50dc9e6924c1d2e9d2e335b2d679fc7d1a7632e84964d3bac0c9fe57e85aa5906ec2e7b0399d98ddd022e9b19b5904", "0xab729328d98d295f8f3272afaf5d8345ff54d58ff9884da14f17ecbdb7371857fdf2f3ef58080054e9874cc919b46224", "0x83fa5da7592bd451cad3ad7702b4006332b3aae23beab4c4cb887fa6348317d234bf62a359e665b28818e5410c278a09", "0x8bdbff566ae9d368f114858ef1f009439b3e9f4649f73efa946e678d6c781d52c69af195df0a68170f5f191b2eac286b", "0x91245e59b4425fd4edb2a61d0d47c1ccc83d3ced8180de34887b9655b5dcda033d48cde0bdc3b7de846d246c053a02e8", "0xa2cb00721e68f1cad8933947456f07144dc69653f96ceed845bd577d599521ba99cdc02421118971d56d7603ed118cbf", "0xaf8cd66d303e808b22ec57860dd909ca64c27ec2c60e26ffecfdc1179d8762ffd2739d87b43959496e9fee4108df71df", "0x9954136812dffcd5d3f167a500e7ab339c15cfc9b3398d83f64b0daa3dd5b9a851204f424a3493b4e326d3de81e50a62", "0x93252254d12511955f1aa464883ad0da793f84d900fea83e1df8bca0f2f4cf5b5f9acbaec06a24160d33f908ab5fea38", "0x997cb55c26996586ba436a95566bd535e9c22452ca5d2a0ded2bd175376557fa895f9f4def4519241ff386a063f2e526", "0xa12c78ad451e0ac911260ade2927a768b50cb4125343025d43474e7f465cdc446e9f52a84609c5e7e87ae6c9b3f56cda", "0xa789d4ca55cbba327086563831b34487d63d0980ba8cf55197c016702ed6da9b102b1f0709ce3da3c53ff925793a3d73", "0xa5d76acbb76741ce85be0e655b99baa04f7f587347947c0a30d27f8a49ae78cce06e1cde770a8b618d3db402be1c0c4b", "0x873c0366668c8faddb0eb7c86f485718d65f8c4734020f1a18efd5fa123d3ea8a990977fe13592cd01d17e60809cb5ff", "0xb659b71fe70f37573ff7c5970cc095a1dc0da3973979778f80a71a347ef25ad5746b2b9608bad4ab9a4a53a4d7df42d7", "0xa34cbe05888e5e5f024a2db14cb6dcdc401a9cbd13d73d3c37b348f68688f87c24ca790030b8f84fef9e74b4eab5e412", "0x94ce8010f85875c045b0f014db93ef5ab9f1f6842e9a5743dce9e4cb872c94affd9e77c1f1d1ab8b8660b52345d9acb9", "0xadefa9b27a62edc0c5b019ddd3ebf45e4de846165256cf6329331def2e088c5232456d3de470fdce3fa758bfdd387512", "0xa6b83821ba7c1f83cc9e4529cf4903adb93b26108e3d1f20a753070db072ad5a3689643144bdd9c5ea06bb9a7a515cd0", "0xa3a9ddedc2a1b183eb1d52de26718151744db6050f86f3580790c51d09226bf05f15111691926151ecdbef683baa992c", "0xa64bac89e7686932cdc5670d07f0b50830e69bfb8c93791c87c7ffa4913f8da881a9d8a8ce8c1a9ce5b6079358c54136", "0xa77b5a63452cb1320b61ab6c7c2ef9cfbcade5fd4727583751fb2bf3ea330b5ca67757ec1f517bf4d503ec924fe32fbd", "0x8746fd8d8eb99639d8cd0ca34c0d9c3230ed5a312aab1d3d925953a17973ee5aeb66e68667e93caf9cb817c868ea8f3d", "0x88a2462a26558fc1fbd6e31aa8abdc706190a17c27fdc4217ffd2297d1b1f3321016e5c4b2384c5454d5717dc732ed03", "0xb78893a97e93d730c8201af2e0d3b31cb923d38dc594ffa98a714e627c473d42ea82e0c4d2eeb06862ee22a9b2c54588", "0x920cc8b5f1297cf215a43f6fc843e379146b4229411c44c0231f6749793d40f07b9af7699fd5d21fd69400b97febe027", "0xa0f0eafce1e098a6b58c7ad8945e297cd93aaf10bc55e32e2e32503f02e59fc1d5776936577d77c0b1162cb93b88518b", "0x98480ba0064e97a2e7a6c4769b4d8c2a322cfc9a3b2ca2e67e9317e2ce04c6e1108169a20bd97692e1cb1f1423b14908", "0x83dbbb2fda7e287288011764a00b8357753a6a44794cc8245a2275237f11affdc38977214e463ad67aec032f3dfa37e9", "0x86442fff37598ce2b12015ff19b01bb8a780b40ad353d143a0f30a06f6d23afd5c2b0a1253716c855dbf445cc5dd6865", "0xb8a4c60c5171189414887847b9ed9501bff4e4c107240f063e2d254820d2906b69ef70406c585918c4d24f1dd052142b", "0x919f33a98e84015b2034b57b5ffe9340220926b2c6e45f86fd79ec879dbe06a148ae68b77b73bf7d01bd638a81165617", "0x95c13e78d89474a47fbc0664f6f806744b75dede95a479bbf844db4a7f4c3ae410ec721cb6ffcd9fa9c323da5740d5ae", "0xab7151acc41fffd8ec6e90387700bcd7e1cde291ea669567295bea1b9dd3f1df2e0f31f3588cd1a1c08af8120aca4921", "0x80e74c5c47414bd6eeef24b6793fb1fa2d8fb397467045fcff887c52476741d5bc4ff8b6d3387cb53ad285485630537f", "0xa296ad23995268276aa351a7764d36df3a5a3cffd7dbeddbcea6b1f77adc112629fdeffa0918b3242b3ccd5e7587e946", "0x813d2506a28a2b01cb60f49d6bd5e63c9b056aa56946faf2f33bd4f28a8d947569cfead3ae53166fc65285740b210f86", "0x924b265385e1646287d8c09f6c855b094daaee74b9e64a0dddcf9ad88c6979f8280ba30c8597b911ef58ddb6c67e9fe3", "0x8d531513c70c2d3566039f7ca47cd2352fd2d55b25675a65250bdb8b06c3843db7b2d29c626eed6391c238fc651cf350", "0x82b338181b62fdc81ceb558a6843df767b6a6e3ceedc5485664b4ea2f555904b1a45fbb35f6cf5d96f27da10df82a325", "0x92e62faaedea83a37f314e1d3cb4faaa200178371d917938e59ac35090be1db4b4f4e0edb78b9c991de202efe4f313d8", "0x99d645e1b642c2dc065bac9aaa0621bc648c9a8351efb6891559c3a41ba737bd155fb32d7731950514e3ecf4d75980e4", "0xb34a13968b9e414172fb5d5ece9a39cf2eb656128c3f2f6cc7a9f0c69c6bae34f555ecc8f8837dc34b5e470e29055c78", "0xa2a0bb7f3a0b23a2cbc6585d59f87cd7e56b2bbcb0ae48f828685edd9f7af0f5edb4c8e9718a0aaf6ef04553ba71f3b7", "0x8e1a94bec053ed378e524b6685152d2b52d428266f2b6eadd4bcb7c4e162ed21ab3e1364879673442ee2162635b7a4d8", "0x9944adaff14a85eab81c73f38f386701713b52513c4d4b838d58d4ffa1d17260a6d056b02334850ea9a31677c4b078bd", "0xa450067c7eceb0854b3eca3db6cf38669d72cb7143c3a68787833cbca44f02c0be9bfbe082896f8a57debb13deb2afb1", "0x8be4ad3ac9ef02f7df09254d569939757101ee2eda8586fefcd8c847adc1efe5bdcb963a0cafa17651befaafb376a531", "0x90f6de91ea50255f148ac435e08cf2ac00c772a466e38155bd7e8acf9197af55662c7b5227f88589b71abe9dcf7ba343", "0x86e5a24f0748b106dee2d4d54e14a3b0af45a96cbee69cac811a4196403ebbee17fd24946d7e7e1b962ac7f66dbaf610", "0xafdd96fbcda7aa73bf9eeb2292e036c25753d249caee3b9c013009cc22e10d3ec29e2aa6ddbb21c4e949b0c0bccaa7f4", "0xb5a4e7436d5473647c002120a2cb436b9b28e27ad4ebdd7c5f122b91597c507d256d0cbd889d65b3a908531936e53053", "0xb632414c3da704d80ac2f3e5e0e9f18a3637cdc2ebeb613c29300745582427138819c4e7b0bec3099c1b8739dac1807b", "0xa28df1464d3372ce9f37ef1db33cc010f752156afae6f76949d98cd799c0cf225c20228ae86a4da592d65f0cffe3951b", "0x898b93d0a31f7d3f11f253cb7a102db54b669fd150da302d8354d8e02b1739a47cb9bd88015f3baf12b00b879442464e", "0x96fb88d89a12049091070cb0048a381902965e67a8493e3991eaabe5d3b7ff7eecd5c94493a93b174df3d9b2c9511755", "0xb899cb2176f59a5cfba3e3d346813da7a82b03417cad6342f19cc8f12f28985b03bf031e856a4743fd7ebe16324805b0", "0xa60e2d31bc48e0c0579db15516718a03b73f5138f15037491f4dae336c904e312eda82d50862f4debd1622bb0e56d866", "0x979fc8b987b5cef7d4f4b58b53a2c278bd25a5c0ea6f41c715142ea5ff224c707de38451b0ad3aa5e749aa219256650a", "0xb2a75bff18e1a6b9cf2a4079572e41205741979f57e7631654a3c0fcec57c876c6df44733c9da3d863db8dff392b44a3", "0xb7a0f0e811222c91e3df98ff7f286b750bc3b20d2083966d713a84a2281744199e664879401e77470d44e5a90f3e5181", "0x82b74ba21c9d147fbc338730e8f1f8a6e7fc847c3110944eb17a48bea5e06eecded84595d485506d15a3e675fd0e5e62", "0xa7f44eef817d5556f0d1abcf420301217d23c69dd2988f44d91ea1f1a16c322263cbacd0f190b9ba22b0f141b9267b4f", "0xaadb68164ede84fc1cb3334b3194d84ba868d5a88e4c9a27519eef4923bc4abf81aab8114449496c073c2a6a0eb24114", "0xb5378605fabe9a8c12a5dc55ef2b1de7f51aedb61960735c08767a565793cea1922a603a6983dc25f7cea738d0f7c40d", "0xa97a4a5cd8d51302e5e670aee78fe6b5723f6cc892902bbb4f131e82ca1dfd5de820731e7e3367fb0c4c1922a02196e3", "0x8bdfeb15c29244d4a28896f2b2cb211243cd6a1984a3f5e3b0ebe5341c419beeab3304b390a009ffb47588018034b0ea", "0xa9af3022727f2aa2fca3b096968e97edad3f08edcbd0dbca107b892ae8f746a9c0485e0d6eb5f267999b23a845923ed0", "0x8e7594034feef412f055590fbb15b6322dc4c6ab7a4baef4685bd13d71a83f7d682b5781bdfa0d1c659489ce9c2b8000", "0x84977ca6c865ebee021c58106c1a4ad0c745949ecc5332948002fd09bd9b890524878d0c29da96fd11207621136421fe", "0x8687551a79158e56b2375a271136756313122132a6670fa51f99a1b5c229ed8eea1655a734abae13228b3ebfd2a825dd", "0xa0227d6708979d99edfc10f7d9d3719fd3fc68b0d815a7185b60307e4c9146ad2f9be2b8b4f242e320d4288ceeb9504c", "0x89f75583a16735f9dd8b7782a130437805b34280ccea8dac6ecaee4b83fe96947e7b53598b06fecfffdf57ffc12cc445", "0xa0056c3353227f6dd9cfc8e3399aa5a8f1d71edf25d3d64c982910f50786b1e395c508d3e3727ac360e3e040c64b5298", "0xb070e61a6d813626144b312ded1788a6d0c7cec650a762b2f8df6e4743941dd82a2511cd956a3f141fc81e15f4e092da", "0xb4e6db232e028a1f989bb5fc13416711f42d389f63564d60851f009dcffac01acfd54efa307aa6d4c0f932892d4e62b0", "0x89b5991a67db90024ddd844e5e1a03ef9b943ad54194ae0a97df775dde1addf31561874f4e40fbc37a896630f3bbda58", "0xad0e8442cb8c77d891df49cdb9efcf2b0d15ac93ec9be1ad5c3b3cca1f4647b675e79c075335c1f681d56f14dc250d76", "0xb5d55a6ae65bb34dd8306806cb49b5ccb1c83a282ee47085cf26c4e648e19a52d9c422f65c1cd7e03ca63e926c5e92ea", "0xb749501347e5ec07e13a79f0cb112f1b6534393458b3678a77f02ca89dca973fa7b30e55f0b25d8b92b97f6cb0120056", "0x94144b4a3ffc5eec6ba35ce9c245c148b39372d19a928e236a60e27d7bc227d18a8cac9983851071935d8ffb64b3a34f", "0x92bb4f9f85bc8c028a3391306603151c6896673135f8a7aefedd27acb322c04ef5dac982fc47b455d6740023e0dd3ea3", "0xb9633a4a101461a782fc2aa092e9dbe4e2ad00987578f18cd7cf0021a909951d60fe79654eb7897806795f93c8ff4d1c", "0x809f0196753024821b48a016eca5dbb449a7c55750f25981bb7a4b4c0e0846c09b8f6128137905055fc43a3f0deb4a74", "0xa27dc9cdd1e78737a443570194a03d89285576d3d7f3a3cf15cc55b3013e42635d4723e2e8fe1d0b274428604b630db9", "0x861f60f0462e04cd84924c36a28163def63e777318d00884ab8cb64c8df1df0bce5900342163edb60449296484a6c5bf", "0xb7bc23fb4e14af4c4704a944253e760adefeca8caee0882b6bbd572c84434042236f39ae07a8f21a560f486b15d82819", "0xb9a6eb492d6dd448654214bd01d6dc5ff12067a11537ab82023fc16167507ee25eed2c91693912f4155d1c07ed9650b3", "0x97678af29c68f9a5e213bf0fb85c265303714482cfc4c2c00b4a1e8a76ed08834ee6af52357b143a1ca590fb0265ea5a", "0x8a15b499e9eca5b6cac3070b5409e8296778222018ad8b53a5d1f6b70ad9bb10c68a015d105c941ed657bf3499299e33", "0xb487fefede2e8091f2c7bfe85770db2edff1db83d4effe7f7d87bff5ab1ace35e9b823a71adfec6737fede8d67b3c467", "0x8b51b916402aa2c437fce3bcad6dad3be8301a1a7eab9d163085b322ffb6c62abf28637636fe6114573950117fc92898", "0xb06a2106d031a45a494adec0881cb2f82275dff9dcdd2bc16807e76f3bec28a6734edd3d54f0be8199799a78cd6228ad", "0xaf0a185391bbe2315eb97feac98ad6dd2e5d931d012c621abd6e404a31cc188b286fef14871762190acf086482b2b5e2", "0x8e78ee8206506dd06eb7729e32fceda3bebd8924a64e4d8621c72e36758fda3d0001af42443851d6c0aea58562870b43", "0xa1ba52a569f0461aaf90b49b92be976c0e73ec4a2c884752ee52ffb62dd137770c985123d405dfb5de70692db454b54a", "0x8d51b692fa1543c51f6b62b9acb8625ed94b746ef96c944ca02859a4133a5629da2e2ce84e111a7af8d9a5b836401c64", "0xa7a20d45044cf6492e0531d0b8b26ffbae6232fa05a96ed7f06bdb64c2b0f5ca7ec59d5477038096a02579e633c7a3ff", "0x84df867b98c53c1fcd4620fef133ee18849c78d3809d6aca0fb6f50ff993a053a455993f216c42ab6090fa5356b8d564", "0xa7227c439f14c48e2577d5713c97a5205feb69acb0b449152842e278fa71e8046adfab468089c8b2288af1fc51fa945b", "0x855189b3a105670779997690876dfaa512b4a25a24931a912c2f0f1936971d2882fb4d9f0b3d9daba77eaf660e9d05d5", "0xb5696bd6706de51c502f40385f87f43040a5abf99df705d6aac74d88c913b8ecf7a99a63d7a37d9bdf3a941b9e432ff5", "0xab997beb0d6df9c98d5b49864ef0b41a2a2f407e1687dfd6089959757ba30ed02228940b0e841afe6911990c74d536c4", "0xb36b65f85546ebfdbe98823d5555144f96b4ab39279facd19c0de3b8919f105ba0315a0784dce4344b1bc62d8bb4a5a3", "0xb8371f0e4450788720ac5e0f6cd3ecc5413d33895083b2c168d961ec2b5c3de411a4cc0712481cbe8df8c2fa1a7af006", "0x98325d8026b810a8b7a114171ae59a57e8bbc9848e7c3df992efc523621729fd8c9f52114ce01d7730541a1ada6f1df1", "0x8d0e76dbd37806259486cd9a31bc8b2306c2b95452dc395546a1042d1d17863ef7a74c636b782e214d3aa0e8d717f94a", "0xa4e15ead76da0214d702c859fb4a8accdcdad75ed08b865842bd203391ec4cba2dcc916455e685f662923b96ee0c023f", "0x8618190972086ebb0c4c1b4a6c94421a13f378bc961cc8267a301de7390c5e73c3333864b3b7696d81148f9d4843fd02", "0x85369d6cc7342e1aa15b59141517d8db8baaaeb7ab9670f3ba3905353948d575923d283b7e5a05b13a30e7baf1208a86", "0x87c51ef42233c24a6da901f28c9a075d9ba3c625687c387ad6757b72ca6b5a8885e6902a3082da7281611728b1e45f26", "0xaa6348a4f71927a3106ad0ea8b02fc8d8c65531e4ab0bd0a17243e66f35afe252e40ab8eef9f13ae55a72566ffdaff5c", "0x96a3bc976e9d03765cc3fee275fa05b4a84c94fed6b767e23ca689394501e96f56f7a97cffddc579a6abff632bf153be", "0x97dbf96c6176379fdb2b888be4e757b2bca54e74124bd068d3fa1dbd82a011bbeb75079da38e0cd22a761fe208ecad9b", "0xb70cf0a1d14089a4129ec4e295313863a59da8c7e26bf74cc0e704ed7f0ee4d7760090d0ddf7728180f1bf2c5ac64955", "0x882d664714cc0ffe53cbc9bef21f23f3649824f423c4dbad1f893d22c4687ab29583688699efc4d5101aa08b0c3e267a", "0x80ecb7cc963e677ccaddbe3320831dd6ee41209acf4ed41b16dc4817121a3d86a1aac9c4db3d8c08a55d28257088af32", "0xa25ba667d832b145f9ce18c3f9b1bd00737aa36db020e1b99752c8ef7d27c6c448982bd8d352e1b6df266b8d8358a8d5", "0x83734841c13dee12759d40bdd209b277e743b0d08cc0dd1e0b7afd2d65bfa640400eefcf6be4a52e463e5b3d885eeac6", "0x848d16505b04804afc773aebabb51b36fd8aacfbb0e09b36c0d5d57df3c0a3b92f33e7d5ad0a7006ec46ebb91df42b8c", "0x909a8d793f599e33bb9f1dc4792a507a97169c87cd5c087310bc05f30afcd247470b4b56dec59894c0fb1d48d39bb54e", "0x8e558a8559df84a1ba8b244ece667f858095c50bb33a5381e60fcc6ba586b69693566d8819b4246a27287f16846c1dfa", "0x84d6b69729f5aaa000cd710c2352087592cfbdf20d5e1166977e195818e593fa1a50d1e04566be23163a2523dc1612f1", "0x9536d262b7a42125d89f4f32b407d737ba8d9242acfc99d965913ab3e043dcac9f7072a43708553562cac4cba841df30", "0x9598548923ca119d6a15fd10861596601dd1dedbcccca97bb208cdc1153cf82991ea8cc17686fbaa867921065265970c", "0xb87f2d4af6d026e4d2836bc3d390a4a18e98a6e386282ce96744603bab74974272e97ac2da281afa21885e2cbb3a8001", "0x991ece62bf07d1a348dd22191868372904b9f8cf065ae7aa4e44fd24a53faf6d851842e35fb472895963aa1992894918", "0xa8c53dea4c665b30e51d22ca6bc1bc78aaf172b0a48e64a1d4b93439b053877ec26cb5221c55efd64fa841bbf7d5aff4", "0x93487ec939ed8e740f15335b58617c3f917f72d07b7a369befd479ae2554d04deb240d4a14394b26192efae4d2f4f35d", "0xa44793ab4035443f8f2968a40e043b4555960193ffa3358d22112093aadfe2c136587e4139ffd46d91ed4107f61ea5e0", "0xb13fe033da5f0d227c75927d3dacb06dbaf3e1322f9d5c7c009de75cdcba5e308232838785ab69a70f0bedea755e003f", "0x970a29b075faccd0700fe60d1f726bdebf82d2cc8252f4a84543ebd3b16f91be42a75c9719a39c4096139f0f31393d58", "0xa4c3eb1f7160f8216fc176fb244df53008ff32f2892363d85254002e66e2de21ccfe1f3b1047589abee50f29b9d507e3", "0x8c552885eab04ba40922a8f0c3c38c96089c95ff1405258d3f1efe8d179e39e1295cbf67677894c607ae986e4e6b1fb0", "0xb3671746fa7f848c4e2ae6946894defadd815230b906b419143523cc0597bc1d6c0a4c1e09d49b66b4a2c11cde3a4de3", "0x937a249a95813a5e2ef428e355efd202e15a37d73e56cfb7e57ea9f943f2ce5ca8026f2f1fd25bf164ba89d07077d858", "0x83646bdf6053a04aa9e2f112499769e5bd5d0d10f2e13db3ca89bd45c0b3b7a2d752b7d137fb3909f9c62b78166c9339", "0xb4eac4b91e763666696811b7ed45e97fd78310377ebea1674b58a2250973f80492ac35110ed1240cd9bb2d17493d708c", "0x82db43a99bc6573e9d92a3fd6635dbbb249ac66ba53099c3c0c8c8080b121dd8243cd5c6e36ba0a4d2525bae57f5c89c", "0xa64d6a264a681b49d134c655d5fc7756127f1ee7c93d328820f32bca68869f53115c0d27fef35fe71f7bc4fdaed97348", "0x8739b7a9e2b4bc1831e7f04517771bc7cde683a5e74e052542517f8375a2f64e53e0d5ac925ef722327e7bb195b4d1d9", "0x8f337cdd29918a2493515ebb5cf702bbe8ecb23b53c6d18920cc22f519e276ca9b991d3313e2d38ae17ae8bdfa4f8b7e", "0xb0edeab9850e193a61f138ef2739fc42ceec98f25e7e8403bfd5fa34a7bc956b9d0898250d18a69fa4625a9b3d6129da", "0xa9920f26fe0a6d51044e623665d998745c9eca5bce12051198b88a77d728c8238f97d4196f26e43b24f8841500b998d0", "0x86e655d61502b979eeeeb6f9a7e1d0074f936451d0a1b0d2fa4fb3225b439a3770767b649256fe481361f481a8dbc276", "0x84d3b32fa62096831cc3bf013488a9f3f481dfe293ae209ed19585a03f7db8d961a7a9dd0db82bd7f62d612707575d9c", "0x81c827826ec9346995ffccf62a241e3b2d32f7357acd1b1f8f7a7dbc97022d3eb51b8a1230e23ce0b401d2e535e8cd78", "0x94a1e40c151191c5b055b21e86f32e69cbc751dcbdf759a48580951834b96a1eed75914c0d19a38aefd21fb6c8d43d0c", "0xab890222b44bc21b71f7c75e15b6c6e16bb03371acce4f8d4353ff3b8fcd42a14026589c5ed19555a3e15e4d18bfc3a3", "0xaccb0be851e93c6c8cc64724cdb86887eea284194b10e7a43c90528ed97e9ec71ca69c6fac13899530593756dd49eab2", "0xb630220aa9e1829c233331413ee28c5efe94ea8ea08d0c6bfd781955078b43a4f92915257187d8526873e6c919c6a1de", "0xadd389a4d358c585f1274b73f6c3c45b58ef8df11f9d11221f620e241bf3579fba07427b288c0c682885a700cc1fa28d", "0xa9fe6ca8bf2961a3386e8b8dcecc29c0567b5c0b3bcf3b0f9169f88e372b80151af883871fc5229815f94f43a6f5b2b0", "0xad839ae003b92b37ea431fa35998b46a0afc3f9c0dd54c3b3bf7a262467b13ff3c323ada1c1ae02ac7716528bdf39e3e", "0x9356d3fd0edcbbb65713c0f2a214394f831b26f792124b08c5f26e7f734b8711a87b7c4623408da6a091c9aef1f6af3c", "0x896b25b083c35ac67f0af3784a6a82435b0e27433d4d74cd6d1eafe11e6827827799490fb1c77c11de25f0d75f14e047", "0x8bfa019391c9627e8e5f05c213db625f0f1e51ec68816455f876c7e55b8f17a4f13e5aae9e3fb9e1cf920b1402ee2b40", "0x8ba3a6faa6a860a8f3ce1e884aa8769ceded86380a86520ab177ab83043d380a4f535fe13884346c5e51bee68da6ab41", "0xa8292d0844084e4e3bb7af92b1989f841a46640288c5b220fecfad063ee94e86e13d3d08038ec2ac82f41c96a3bfe14d", "0x8229bb030b2fc566e11fd33c7eab7a1bb7b49fed872ea1f815004f7398cb03b85ea14e310ec19e1f23e0bdaf60f8f76c", "0x8cfbf869ade3ec551562ff7f63c2745cc3a1f4d4dc853a0cd42dd5f6fe54228f86195ea8fe217643b32e9f513f34a545", "0xac52a3c8d3270ddfe1b5630159da9290a5ccf9ccbdef43b58fc0a191a6c03b8a5974cf6e2bbc7bd98d4a40a3581482d7", "0xab13decb9e2669e33a7049b8eca3ca327c40dea15ad6e0e7fa63ed506db1d258bc36ac88b35f65cae0984e937eb6575d", "0xb5e748eb1a7a1e274ff0cc56311c198f2c076fe4b7e73e5f80396fe85358549df906584e6bb2c8195b3e2be7736850a5", "0xb5cb911325d8f963c41f691a60c37831c7d3bbd92736efa33d1f77a22b3fde7f283127256c2f47e197571e6fe0b46149", "0x8a01dc6ed1b55f26427a014faa347130738b191a06b800e32042a46c13f60b49534520214359d68eb2e170c31e2b8672", "0xa72fa874866e19b2efb8e069328362bf7921ec375e3bcd6b1619384c3f7ee980f6cf686f3544e9374ff54b4d17a1629c", "0x8db21092f7c5f110fba63650b119e82f4b42a997095d65f08f8237b02dd66fdf959f788df2c35124db1dbd330a235671", "0x8c65d50433d9954fe28a09fa7ba91a70a590fe7ba6b3060f5e4be0f6cef860b9897fa935fb4ebc42133524eb071dd169", "0xb4614058e8fa21138fc5e4592623e78b8982ed72aa35ee4391b164f00c68d277fa9f9eba2eeefc890b4e86eba5124591", "0xab2ad3a1bce2fbd55ca6b7c23786171fe1440a97d99d6df4d80d07dd56ac2d7203c294b32fc9e10a6c259381a73f24a1", "0x812ae3315fdc18774a8da3713a4679e8ed10b9405edc548c00cacbe25a587d32040566676f135e4723c5dc25df5a22e9", "0xa464b75f95d01e5655b54730334f443c8ff27c3cb79ec7af4b2f9da3c2039c609908cd128572e1fd0552eb597e8cef8d", "0xa0db3172e93ca5138fe419e1c49a1925140999f6eff7c593e5681951ee0ec1c7e454c851782cbd2b8c9bc90d466e90e0", "0x806db23ba7d00b87d544eed926b3443f5f9c60da6b41b1c489fba8f73593b6e3b46ebfcab671ee009396cd77d5e68aa1", "0x8bfdf2c0044cc80260994e1c0374588b6653947b178e8b312be5c2a05e05767e98ea15077278506aee7df4fee1aaf89e", "0x827f6558c16841b5592ff089c9c31e31eb03097623524394813a2e4093ad2d3f8f845504e2af92195aaa8a1679d8d692", "0x925c4f8eab2531135cd71a4ec88e7035b5eea34ba9d799c5898856080256b4a15ed1a746e002552e2a86c9c157e22e83", "0xa9f9a368f0e0b24d00a35b325964c85b69533013f9c2cfad9708be5fb87ff455210f8cb8d2ce3ba58ca3f27495552899", "0x8ac0d3bebc1cae534024187e7c71f8927ba8fcc6a1926cb61c2b6c8f26bb7831019e635a376146c29872a506784a4aaa", "0x97c577be2cbbfdb37ad754fae9df2ada5fc5889869efc7e18a13f8e502fbf3f4067a509efbd46fd990ab47ce9a70f5a8", "0x935e7d82bca19f16614aa43b4a3474e4d20d064e4bfdf1cea2909e5c9ab72cfe3e54dc50030e41ee84f3588cebc524e9", "0x941aafc08f7c0d94cebfbb1f0aad5202c02e6e37f2c12614f57e727efa275f3926348f567107ee6d8914dd71e6060271", "0xaf0fbc1ba05b4b5b63399686df3619968be5d40073de0313cbf5f913d3d4b518d4c249cdd2176468ccaa36040a484f58", "0xa0c414f23f46ca6d69ce74c6f8a00c036cb0edd098af0c1a7d39c802b52cfb2d5dbdf93fb0295453d4646e2af7954d45", "0x909cf39e11b3875bb63b39687ae1b5d1f5a15445e39bf164a0b14691b4ddb39a8e4363f584ef42213616abc4785b5d66", "0xa92bac085d1194fbd1c88299f07a061d0bdd3f980b663e81e6254dbb288bf11478c0ee880e28e01560f12c5ccb3c0103", "0x841705cd5cd76b943e2b7c5e845b9dd3c8defe8ef67e93078d6d5e67ade33ad4b0fd413bc196f93b0a4073c855cd97d4", "0x8e7eb8364f384a9161e81d3f1d52ceca9b65536ae49cc35b48c3e2236322ba4ae9973e0840802d9fa4f4d82ea833544f", "0xaed3ab927548bc8bec31467ba80689c71a168e34f50dcb6892f19a33a099f5aa6b3f9cb79f5c0699e837b9a8c7f27efe", "0xb8fbf7696210a36e20edabd77839f4dfdf50d6d015cdf81d587f90284a9bcef7d2a1ff520728d7cc69a4843d6c20dedd", "0xa9d533769ce6830211c884ae50a82a7bf259b44ac71f9fb11f0296fdb3981e6b4c1753fe744647b247ebc433a5a61436", "0x8b4bdf90d33360b7f428c71cde0a49fb733badba8c726876945f58c620ce7768ae0e98fc8c31fa59d8955a4823336bb1", "0x808d42238e440e6571c59e52a35ae32547d502dc24fd1759d8ea70a7231a95859baf30b490a4ba55fa2f3aaa11204597", "0x85594701f1d2fee6dc1956bc44c7b31db93bdeec2f3a7d622c1a08b26994760773e3d57521a44cfd7e407ac3fd430429", "0xa66de045ce7173043a6825e9dc440ac957e2efb6df0a337f4f8003eb0c719d873a52e6eba3cb0d69d977ca37d9187674", "0x87a1c6a1fdff993fa51efa5c3ba034c079c0928a7d599b906336af7c2dcab9721ceaf3108c646490af9dff9a754f54b3", "0x926424223e462ceb75aed7c22ade8a7911a903b7e5dd4bc49746ddce8657f4616325cd12667d4393ac52cdd866396d0e", "0xb5dc96106593b42b30f06f0b0a1e0c1aafc70432e31807252d3674f0b1ea5e58eac8424879d655c9488d85a879a3e572", "0x997ca0987735cc716507cb0124b1d266d218b40c9d8e0ecbf26a1d65719c82a637ce7e8be4b4815d307df717bde7c72a", "0x92994d3f57a569b7760324bb5ae4e8e14e1633d175dab06aa57b8e391540e05f662fdc08b8830f489a063f59b689a688", "0xa8087fcc6aa4642cb998bea11facfe87eb33b90a9aa428ab86a4124ad032fc7d2e57795311a54ec9f55cc120ebe42df1", "0xa9bd7d1de6c0706052ca0b362e2e70e8c8f70f1f026ea189b4f87a08ce810297ebfe781cc8004430776c54c1a05ae90c", "0x856d33282e8a8e33a3d237fb0a0cbabaf77ba9edf2fa35a831fdafcadf620561846aa6cbb6bdc5e681118e1245834165", "0x9524a7aa8e97a31a6958439c5f3339b19370f03e86b89b1d02d87e4887309dbbe9a3a8d2befd3b7ed5143c8da7e0a8ad", "0x824fdf433e090f8acbd258ac7429b21f36f9f3b337c6d0b71d1416a5c88a767883e255b2888b7c906dd2e9560c4af24c", "0x88c7fee662ca7844f42ed5527996b35723abffd0d22d4ca203b9452c639a5066031207a5ae763dbc0865b3299d19b1ec", "0x919dca5c5595082c221d5ab3a5bc230f45da7f6dec4eb389371e142c1b9c6a2c919074842479c2844b72c0d806170c0c", "0xb939be8175715e55a684578d8be3ceff3087f60fa875fff48e52a6e6e9979c955efef8ff67cfa2b79499ea23778e33b0", "0x873b6db725e7397d11bc9bed9ac4468e36619135be686790a79bc6ed4249058f1387c9a802ea86499f692cf635851066", "0xaeae06db3ec47e9e5647323fa02fac44e06e59b885ad8506bf71b184ab3895510c82f78b6b22a5d978e8218e7f761e9f", "0xb99c0a8359c72ab88448bae45d4bf98797a26bca48b0d4460cd6cf65a4e8c3dd823970ac3eb774ae5d0cea4e7fadf33e", "0x8f10c8ec41cdfb986a1647463076a533e6b0eec08520c1562401b36bb063ac972aa6b28a0b6ce717254e35940b900e3c", "0xa106d9be199636d7add43b942290269351578500d8245d4aae4c083954e4f27f64740a3138a66230391f2d0e6043a8de", "0xa469997908244578e8909ff57cffc070f1dbd86f0098df3cfeb46b7a085cfecc93dc69ee7cad90ff1dc5a34d50fe580c", "0xa4ef087bea9c20eb0afc0ee4caba7a9d29dfa872137828c721391273e402fb6714afc80c40e98bbd8276d3836bffa080", "0xb07a013f73cd5b98dae0d0f9c1c0f35bff8a9f019975c4e1499e9bee736ca6fcd504f9bc32df1655ff333062382cff04", "0xb0a77188673e87cc83348c4cc5db1eecf6b5184e236220c8eeed7585e4b928db849944a76ec60ef7708ef6dac02d5592", "0xb1284b37e59b529f0084c0dacf0af6c0b91fc0f387bf649a8c74819debf606f7b07fc3e572500016fb145ec2b24e9f17", "0x97b20b5b4d6b9129da185adfbf0d3d0b0faeba5b9715f10299e48ea0521709a8296a9264ce77c275a59c012b50b6519a", "0xb9d37e946fae5e4d65c1fbfacc8a62e445a1c9d0f882e60cca649125af303b3b23af53c81d7bac544fb7fcfc7a314665", "0x8e5acaac379f4bb0127efbef26180f91ff60e4c525bc9b798fc50dfaf4fe8a5aa84f18f3d3cfb8baead7d1e0499af753", "0xb0c0b8ab1235bf1cda43d4152e71efc1a06c548edb964eb4afceb201c8af24240bf8ab5cae30a08604e77432b0a5faf0", "0x8cc28d75d5c8d062d649cbc218e31c4d327e067e6dbd737ec0a35c91db44fbbd0d40ec424f5ed79814add16947417572", "0x95ae6219e9fd47efaa9cb088753df06bc101405ba50a179d7c9f7c85679e182d3033f35b00dbba71fdcd186cd775c52e", "0xb5d28fa09f186ebc5aa37453c9b4d9474a7997b8ae92748ecb940c14868792292ac7d10ade01e2f8069242b308cf97e5", "0x8c922a0faa14cc6b7221f302df3342f38fc8521ec6c653f2587890192732c6da289777a6cd310747ea7b7d104af95995", "0xb9ad5f660b65230de54de535d4c0fcae5bc6b59db21dea5500fdc12eea4470fb8ea003690fdd16d052523418d5e01e8c", "0xa39a9dd41a0ff78c82979483731f1cd68d3921c3e9965869662c22e02dde3877802e180ba93f06e7346f96d9fa9261d2", "0x8b32875977ec372c583b24234c27ed73aef00cdff61eb3c3776e073afbdeade548de9497c32ec6d703ff8ad0a5cb7fe4", "0x9644cbe755a5642fe9d26cfecf170d3164f1848c2c2e271d5b6574a01755f3980b3fc870b98cf8528fef6ecef4210c16", "0x81ea9d1fdd9dd66d60f40ce0712764b99da9448ae0b300f8324e1c52f154e472a086dda840cb2e0b9813dc8ce8afd4b5", "0x906aaa4a7a7cdf01909c5cfbc7ded2abc4b869213cbf7c922d4171a4f2e637e56f17020b852ad339d83b8ac92f111666", "0x939b5f11acbdeff998f2a080393033c9b9d8d5c70912ea651c53815c572d36ee822a98d6dfffb2e339f29201264f2cf4", "0xaba4898bf1ccea9b9e2df1ff19001e05891581659c1cbbde7ee76c349c7fc7857261d9785823c9463a8aea3f40e86b38", "0x83ca1a56b8a0be4820bdb5a9346357c68f9772e43f0b887729a50d2eb2a326bbcede676c8bf2e51d7c89bbd8fdb778a6", "0x94e86e9fe6addfe2c3ee3a547267ed921f4230d877a85bb4442c2d9350c2fa9a9c54e6fe662de82d1a2407e4ab1691c2", "0xa0cc3bdef671a59d77c6984338b023fa2b431b32e9ed2abe80484d73edc6540979d6f10812ecc06d4d0c5d4eaca7183c", "0xb5343413c1b5776b55ea3c7cdd1f3af1f6bd802ea95effe3f2b91a523817719d2ecc3f8d5f3cc2623ace7e35f99ca967", "0x92085d1ed0ed28d8cabe3e7ff1905ed52c7ceb1eac5503760c52fb5ee3a726aba7c90b483c032acc3f166b083d7ec370", "0x8ec679520455275cd957fca8122724d287db5df7d29f1702a322879b127bff215e5b71d9c191901465d19c86c8d8d404", "0xb65eb2c63d8a30332eb24ee8a0c70156fc89325ebbb38bacac7cf3f8636ad8a472d81ccca80423772abc00192d886d8a", "0xa9fe1c060b974bee4d590f2873b28635b61bfcf614e61ff88b1be3eee4320f4874e21e8d666d8ac8c9aba672efc6ecae", "0xb3fe2a9a389c006a831dea7e777062df84b5c2803f9574d7fbe10b7e1c125817986af8b6454d6be9d931a5ac94cfe963", "0x95418ad13b734b6f0d33822d9912c4c49b558f68d08c1b34a0127fcfa666bcae8e6fda8832d2c75bb9170794a20e4d7c", "0xa9a7df761e7f18b79494bf429572140c8c6e9d456c4d4e336184f3f51525a65eb9582bea1e601bdb6ef8150b7ca736a5", "0xa0de03b1e75edf7998c8c1ac69b4a1544a6fa675a1941950297917366682e5644a4bda9cdeedfaf9473d7fccd9080b0c", "0xa61838af8d95c95edf32663a68f007d95167bf6e41b0c784a30b22d8300cfdd5703bd6d16e86396638f6db6ae7e42a85", "0x8866d62084d905c145ff2d41025299d8b702ac1814a7dec4e277412c161bc9a62fed735536789cb43c88693c6b423882", "0x91da22c378c81497fe363e7f695c0268443abee50f8a6625b8a41e865638a643f07b157ee566de09ba09846934b4e2d7", "0x941d21dd57c9496aa68f0c0c05507405fdd413acb59bc668ce7e92e1936c68ec4b065c3c30123319884149e88228f0b2", "0xa77af9b094bc26966ddf2bf9e1520c898194a5ccb694915950dadc204facbe3066d3d89f50972642d76b14884cfbaa21", "0x8e76162932346869f4618bde744647f7ab52ab498ad654bdf2a4feeb986ac6e51370841e5acbb589e38b6e7142bb3049", "0xb60979ace17d6937ece72e4f015da4657a443dd01cebc7143ef11c09e42d4aa8855999a65a79e2ea0067f31c9fc2ab0f", "0xb3e2ffdd5ee6fd110b982fd4fad4b93d0fca65478f986d086eeccb0804960bfaa1919afa743c2239973ea65091fe57d2", "0x8ce0ce05e7d7160d44574011da687454dbd3c8b8290aa671731b066e2c82f8cf2d63cb8e932d78c6122ec610e44660e6", "0xab005dd8d297045c39e2f72fb1c48edb501ccf3575d3d04b9817b3afee3f0bb0f3f53f64bda37d1d9cde545aae999bae", "0x95bd7edb4c4cd60e3cb8a72558845a3cce6bb7032ccdf33d5a49ebb6ddf203bc3c79e7b7e550735d2d75b04c8b2441e8", "0x889953ee256206284094e4735dbbb17975bafc7c3cb94c9fbfee4c3e653857bfd49e818f64a47567f721b98411a3b454", "0xb188423e707640ab0e75a061e0b62830cde8afab8e1ad3dae30db69ffae4e2fc005bababbdcbd7213b918ed4f70e0c14", "0xa97e0fafe011abd70d4f99a0b36638b3d6e7354284588f17a88970ed48f348f88392779e9a038c6cbc9208d998485072", "0x87db11014a91cb9b63e8dfaa82cdebca98272d89eb445ee1e3ff9dbaf2b3fad1a03b888cffc128e4fe208ed0dddece0f", "0xaad2e40364edd905d66ea4ac9d51f9640d6fda9a54957d26ba233809851529b32c85660fa401dbee3679ec54fa6dd966", "0x863e99336ca6edf03a5a259e59a2d0f308206e8a2fb320cfc0be06057366df8e0f94b33a28f574092736b3c5ada84270", "0xb34bcc56a057589f34939a1adc51de4ff6a9f4fee9c7fa9aa131e28d0cf0759a0c871b640162acdfbf91f3f1b59a3703", "0x935dd28f2896092995c5eff1618e5b6efe7a40178888d7826da9b0503c2d6e68a28e7fac1a334e166d0205f0695ef614", "0xb842cd5f8f5de5ca6c68cb4a5c1d7b451984930eb4cc18fd0934d52fdc9c3d2d451b1c395594d73bc3451432bfba653f", "0x9014537885ce2debad736bc1926b25fdab9f69b216bf024f589c49dc7e6478c71d595c3647c9f65ff980b14f4bb2283b", "0x8e827ccca1dd4cd21707140d10703177d722be0bbe5cac578db26f1ef8ad2909103af3c601a53795435b27bf95d0c9ed", "0x8a0b8ad4d466c09d4f1e9167410dbe2edc6e0e6229d4b3036d30f85eb6a333a18b1c968f6ca6d6889bb08fecde017ef4", "0x9241ee66c0191b06266332dc9161dede384c4bb4e116dbd0890f3c3790ec5566da4568243665c4725b718ac0f6b5c179", "0xaeb4d5fad81d2b505d47958a08262b6f1b1de9373c2c9ba6362594194dea3e002ab03b8cbb43f867be83065d3d370f19", "0x8781bc83bb73f7760628629fe19e4714b494dbed444c4e4e4729b7f6a8d12ee347841a199888794c2234f51fa26fc2b9", "0xb58864f0acd1c2afa29367e637cbde1968d18589245d9936c9a489c6c495f54f0113ecdcbe4680ac085dd3c397c4d0c3", "0x94a24284afaeead61e70f3e30f87248d76e9726759445ca18cdb9360586c60cc9f0ec1c397f9675083e0b56459784e2e", "0xaed358853f2b54dcbddf865e1816c2e89be12e940e1abfa661e2ee63ffc24a8c8096be2072fa83556482c0d89e975124", "0xb95374e6b4fc0765708e370bc881e271abf2e35c08b056a03b847e089831ef4fe3124b9c5849d9c276eb2e35b3daf264", "0xb834cdbcfb24c8f84bfa4c552e7fadc0028a140952fd69ed13a516e1314a4cd35d4b954a77d51a1b93e1f5d657d0315d", "0x8fb6d09d23bfa90e7443753d45a918d91d75d8e12ec7d016c0dfe94e5c592ba6aaf483d2f16108d190822d955ad9cdc3", "0xaa315cd3c60247a6ad4b04f26c5404c2713b95972843e4b87b5a36a89f201667d70f0adf20757ebe1de1b29ae27dda50", "0xa116862dca409db8beff5b1ccd6301cdd0c92ca29a3d6d20eb8b87f25965f42699ca66974dd1a355200157476b998f3b", "0xb4c2f5fe173c4dc8311b60d04a65ce1be87f070ac42e13cd19c6559a2931c6ee104859cc2520edebbc66a13dc7d30693", "0x8d4a02bf99b2260c334e7d81775c5cf582b00b0c982ce7745e5a90624919028278f5e9b098573bad5515ce7fa92a80c8", "0x8543493bf564ce6d97bd23be9bff1aba08bd5821ca834f311a26c9139c92a48f0c2d9dfe645afa95fec07d675d1fd53b", "0x9344239d13fde08f98cb48f1f87d34cf6abe8faecd0b682955382a975e6eed64e863fa19043290c0736261622e00045c", "0xaa49d0518f343005ca72b9e6c7dcaa97225ce6bb8b908ebbe7b1a22884ff8bfb090890364e325a0d414ad180b8f161d1", "0x907d7fd3e009355ab326847c4a2431f688627faa698c13c03ffdd476ecf988678407f029b8543a475dcb3dafdf2e7a9c", "0x845f1f10c6c5dad2adc7935f5cd2e2b32f169a99091d4f1b05babe7317b9b1cdce29b5e62f947dc621b9acbfe517a258", "0x8f3be8e3b380ea6cdf9e9c237f5e88fd5a357e5ded80ea1fc2019810814de82501273b4da38916881125b6fa0cfd4459", "0xb9c7f487c089bf1d20c822e579628db91ed9c82d6ca652983aa16d98b4270c4da19757f216a71b9c13ddee3e6e43705f", "0x8ba2d8c88ad2b872db104ea8ddbb006ec2f3749fd0e19298a804bb3a5d94de19285cc7fb19fee58a66f7851d1a66c39f", "0x9375ecd3ed16786fe161af5d5c908f56eeb467a144d3bbddfc767e90065b7c94fc53431adebecba2b6c9b5821184d36e", "0xa49e069bfadb1e2e8bff6a4286872e2a9765d62f0eaa4fcb0e5af4bbbed8be3510fb19849125a40a8a81d1e33e81c3eb", "0x9522cc66757b386aa6b88619525c8ce47a5c346d590bb3647d12f991e6c65c3ab3c0cfc28f0726b6756c892eae1672be", "0xa9a0f1f51ff877406fa83a807aeb17b92a283879f447b8a2159653db577848cc451cbadd01f70441e351e9ed433c18bc", "0x8ff7533dcff6be8714df573e33f82cf8e9f2bcaaa43e939c4759d52b754e502717950de4b4252fb904560fc31dce94a4", "0x959724671e265a28d67c29d95210e97b894b360da55e4cf16e6682e7912491ed8ca14bfaa4dce9c25a25b16af580494f", "0x92566730c3002f4046c737032487d0833c971e775de59fe02d9835c9858e2e3bc37f157424a69764596c625c482a2219", "0xa84b47ceff13ed9c3e5e9cdf6739a66d3e7c2bd8a6ba318fefb1a9aecf653bb2981da6733ddb33c4b0a4523acc429d23", "0xb4ddf571317e44f859386d6140828a42cf94994e2f1dcbcc9777f4eebbfc64fc1e160b49379acc27c4672b8e41835c5d", "0x8ab95c94072b853d1603fdd0a43b30db617d13c1d1255b99075198e1947bfa5f59aed2b1147548a1b5e986cd9173d15c", "0x89511f2eab33894fd4b3753d24249f410ff7263052c1fef6166fc63a79816656b0d24c529e45ccce6be28de6e375d916", "0xa0866160ca63d4f2be1b4ea050dac6b59db554e2ebb4e5b592859d8df339b46fd7cb89aaed0951c3ee540aee982c238a", "0x8fcc5cbba1b94970f5ff2eb1922322f5b0aa7d918d4b380c9e7abfd57afd8b247c346bff7b87af82efbce3052511cd1b", "0x99aeb2a5e846b0a2874cca02c66ed40d5569eb65ab2495bc3f964a092e91e1517941f2688e79f8cca49cd3674c4e06dc", "0xb7a096dc3bad5ca49bee94efd884aa3ff5615cf3825cf95fbe0ce132e35f46581d6482fa82666c7ef5f1643eaee8f1ca", "0x94393b1da6eaac2ffd186b7725eca582f1ddc8cdd916004657f8a564a7c588175cb443fc6943b39029f5bbe0add3fad8", "0x884b85fe012ccbcd849cb68c3ad832d83b3ef1c40c3954ffdc97f103b1ed582c801e1a41d9950f6bddc1d11f19d5ec76", "0xb00061c00131eded8305a7ce76362163deb33596569afb46fe499a7c9d7a0734c084d336b38d168024c2bb42b58e7660", "0xa439153ac8e6ca037381e3240e7ba08d056c83d7090f16ed538df25901835e09e27de2073646e7d7f3c65056af6e4ce7", "0x830fc9ca099097d1f38b90e6843dc86f702be9d20bdacc3e52cae659dc41df5b8d2c970effa6f83a5229b0244a86fe22", "0xb81ea2ffaaff2bb00dd59a9ab825ba5eed4db0d8ac9c8ed1a632ce8f086328a1cddd045fbe1ace289083c1325881b7e7", "0xb51ea03c58daf2db32c99b9c4789b183365168cb5019c72c4cc91ac30b5fb7311d3db76e6fa41b7cd4a8c81e2f6cdc94", "0xa4170b2c6d09ca5beb08318730419b6f19215ce6c631c854116f904be3bc30dd85a80c946a8ab054d3e307afaa3f8fbc", "0x897cc42ff28971ff54d2a55dd6b35cfb8610ac902f3c06e3a5cea0e0a257e870c471236a8e84709211c742a09c5601a6", "0xa18f2e98d389dace36641621488664ecbb422088ab03b74e67009b8b8acacaaa24fdcf42093935f355207d934adc52a8", "0x92adcfb678cc2ba19c866f3f2b988fdcb4610567f3ab436cc0cb9acaf5a88414848d71133ebdbec1983e38e6190f1b5f", "0xa86d43c2ce01b366330d3b36b3ca85f000c3548b8297e48478da1ee7d70d8576d4650cba7852ed125c0d7cb6109aa7f3", "0x8ed31ceed9445437d7732dce78a762d72ff32a7636bfb3fd7974b7ae15db414d8184a1766915244355deb354fbc5803b", "0x9268f70032584f416e92225d65af9ea18c466ebc7ae30952d56a4e36fd9ea811dde0a126da9220ba3c596ec54d8a335e", "0x9433b99ee94f2d3fbdd63b163a2bdf440379334c52308bd24537f7defd807145a062ff255a50d119a7f29f4b85d250e3", "0x90ce664f5e4628a02278f5cf5060d1a34f123854634b1870906e5723ac9afd044d48289be283b267d45fcbf3f4656aaf", "0xaaf21c4d59378bb835d42ae5c5e5ab7a3c8c36a59e75997989313197752b79a472d866a23683b329ea69b048b87fa13e", "0xb83c0589b304cec9ede549fde54f8a7c2a468c6657da8c02169a6351605261202610b2055c639b9ed2d5b8c401fb8f56", "0x9370f326ea0f170c2c05fe2c5a49189f20aec93b6b18a5572a818cd4c2a6adb359e68975557b349fb54f065d572f4c92", "0xac3232fa5ce6f03fca238bef1ce902432a90b8afce1c85457a6bee5571c033d4bceefafc863af04d4e85ac72a4d94d51", "0x80d9ea168ff821b22c30e93e4c7960ce3ad3c1e6deeebedd342a36d01bd942419b187e2f382dbfd8caa34cca08d06a48", "0xa387a3c61676fb3381eefa2a45d82625635a666e999aba30e3b037ec9e040f414f9e1ad9652abd3bcad63f95d85038db", "0xa1b229fe32121e0b391b0f6e0180670b9dc89d79f7337de4c77ea7ad0073e9593846f06797c20e923092a08263204416", "0x92164a9d841a2b828cedf2511213268b698520f8d1285852186644e9a0c97512cafa4bfbe29af892c929ebccd102e998", "0x82ee2fa56308a67c7db4fd7ef539b5a9f26a1c2cc36da8c3206ba4b08258fbb3cec6fe5cdbd111433fb1ba2a1e275927", "0x8c77bfe9e191f190a49d46f05600603fa42345592539b82923388d72392404e0b29a493a15e75e8b068dddcd444c2928", "0x80b927f93ccf79dcf5c5b20bcf5a7d91d7a17bc0401bb7cc9b53a6797feac31026eb114257621f5a64a52876e4474cc1", "0xb6b68b6501c37804d4833d5a063dd108a46310b1400549074e3cac84acc6d88f73948b7ad48d686de89c1ec043ae8c1a", "0xab3da00f9bdc13e3f77624f58a3a18fc3728956f84b5b549d62f1033ae4b300538e53896e2d943f160618e05af265117", "0xb6830e87233b8eace65327fdc764159645b75d2fd4024bf8f313b2dd5f45617d7ecfb4a0b53ccafb5429815a9a1adde6", "0xb9251cfe32a6dc0440615aadcd98b6b1b46e3f4e44324e8f5142912b597ee3526bea2431e2b0282bb58f71be5b63f65e", "0xaf8d70711e81cdddfb39e67a1b76643292652584c1ce7ce4feb1641431ad596e75c9120e85f1a341e7a4da920a9cdd94", "0x98cd4e996594e89495c078bfd52a4586b932c50a449a7c8dfdd16043ca4cda94dafbaa8ad1b44249c99bbcc52152506e", "0xb9fc6d1c24f48404a4a64fbe3e43342738797905db46e4132aee5f086aaa4c704918ad508aaefa455cfe1b36572e6242", "0xa365e871d30ba9291cedaba1be7b04e968905d003e9e1af7e3b55c5eb048818ae5b913514fb08b24fb4fbdccbb35d0b8", "0x93bf99510971ea9af9f1e364f1234c898380677c8e8de9b0dd24432760164e46c787bc9ec42a7ad450500706cf247b2d", "0xb872f825a5b6e7b9c7a9ddfeded3516f0b1449acc9b4fd29fc6eba162051c17416a31e5be6d3563f424d28e65bab8b8f", "0xb06b780e5a5e8eb4f4c9dc040f749cf9709c8a4c9ef15e925f442b696e41e5095db0778a6c73bcd329b265f2c6955c8b", "0x848f1a981f5fc6cd9180cdddb8d032ad32cdfa614fc750d690dbae36cc0cd355cbf1574af9b3ffc8b878f1b2fafb9544", "0xa03f48cbff3e9e8a3a655578051a5ae37567433093ac500ed0021c6250a51b767afac9bdb194ee1e3eac38a08c0eaf45", "0xb5be78ce638ff8c4aa84352b536628231d3f7558c5be3bf010b28feac3022e64691fa672f358c8b663904aebe24a54ed", "0xa9d4da70ff676fa55d1728ba6ab03b471fa38b08854d99e985d88c2d050102d8ccffbe1c90249a5607fa7520b15fe791", "0x8fe9f7092ffb0b69862c8e972fb1ecf54308c96d41354ed0569638bb0364f1749838d6d32051fff1599112978c6e229c", "0xae6083e95f37770ecae0df1e010456f165d96cfe9a7278c85c15cffd61034081ce5723e25e2bede719dc9341ec8ed481", "0xa260891891103089a7afbd9081ea116cfd596fd1015f5b65e10b0961eb37fab7d09c69b7ce4be8bf35e4131848fb3fe4", "0x8d729fa32f6eb9fd2f6a140bef34e8299a2f3111bffd0fe463aa8622c9d98bfd31a1df3f3e87cd5abc52a595f96b970e", "0xa30ec6047ae4bc7da4daa7f4c28c93aedb1112cfe240e681d07e1a183782c9ff6783ac077c155af23c69643b712a533f", "0xac830726544bfe7b5467339e5114c1a75f2a2a8d89453ce86115e6a789387e23551cd64620ead6283dfa4538eb313d86", "0x8445c135b7a48068d8ed3e011c6d818cfe462b445095e2fbf940301e50ded23f272d799eea47683fc027430ce14613ef", "0x95785411715c9ae9d8293ce16a693a2aa83e3cb1b4aa9f76333d0da2bf00c55f65e21e42e50e6c5772ce213dd7b4f7a0", "0xb273b024fa18b7568c0d1c4d2f0c4e79ec509dafac8c5951f14192d63ddbcf2d8a7512c1c1b615cc38fa3e336618e0c5", "0xa78b9d3ea4b6a90572eb27956f411f1d105fdb577ee2ffeec9f221da9b45db84bfe866af1f29597220c75e0c37a628d8", "0xa4be2bf058c36699c41513c4d667681ce161a437c09d81383244fc55e1c44e8b1363439d0cce90a3e44581fb31d49493", "0xb6eef13040f17dd4eba22aaf284d2f988a4a0c4605db44b8d2f4bf9567ac794550b543cc513c5f3e2820242dd704152e", "0x87eb00489071fa95d008c5244b88e317a3454652dcb1c441213aa16b28cd3ecaa9b22fec0bdd483c1df71c37119100b1", "0x92d388acdcb49793afca329cd06e645544d2269234e8b0b27d2818c809c21726bc9cf725651b951e358a63c83dedee24", "0xae27e219277a73030da27ab5603c72c8bd81b6224b7e488d7193806a41343dff2456132274991a4722fdb0ef265d04cd", "0x97583e08ecb82bbc27c0c8476d710389fa9ffbead5c43001bd36c1b018f29faa98de778644883e51870b69c5ffb558b5", "0x90a799a8ce73387599babf6b7da12767c0591cadd36c20a7990e7c05ea1aa2b9645654ec65308ee008816623a2757a6a", "0xa1b47841a0a2b06efd9ab8c111309cc5fc9e1d5896b3e42ed531f6057e5ade8977c29831ce08dbda40348386b1dcc06d", "0xb92b8ef59bbddb50c9457691bc023d63dfcc54e0fd88bd5d27a09e0d98ac290fc90e6a8f6b88492043bf7c87fac8f3e4", "0xa9d6240b07d62e22ec8ab9b1f6007c975a77b7320f02504fc7c468b4ee9cfcfd945456ff0128bc0ef2174d9e09333f8d", "0x8e96534c94693226dc32bca79a595ca6de503af635f802e86442c67e77564829756961d9b701187fe91318da515bf0e6", "0xb6ba290623cd8dd5c2f50931c0045d1cfb0c30877bc8fe58cbc3ff61ee8da100045a39153916efa1936f4aee0892b473", "0xb43baa7717fac02d4294f5b3bb5e58a65b3557747e3188b482410388daac7a9c177f762d943fd5dcf871273921213da8", "0xb9cf00f8fb5e2ef2b836659fece15e735060b2ea39b8e901d3dcbdcf612be8bf82d013833718c04cd46ffaa70b85f42e", "0x8017d0c57419e414cbba504368723e751ef990cc6f05dad7b3c2de6360adc774ad95512875ab8337d110bf39a42026fa", "0xae7401048b838c0dcd4b26bb6c56d79d51964a0daba780970b6c97daee4ea45854ea0ac0e4139b3fe60dac189f84df65", "0x887b237b0cd0f816b749b21db0b40072f9145f7896c36916296973f9e6990ede110f14e5976c906d08987c9836cca57f", "0xa88c3d5770148aee59930561ca1223aceb2c832fb5417e188dca935905301fc4c6c2c9270bc1dff7add490a125eb81c6", "0xb6cf9b02c0cd91895ad209e38c54039523f137b5848b9d3ad33ae43af6c20c98434952db375fe378de7866f2d0e8b18a", "0x84ef3d322ff580c8ad584b1fe4fe346c60866eb6a56e982ba2cf3b021ecb1fdb75ecc6c29747adda86d9264430b3f816", "0xa0561c27224baf0927ad144cb71e31e54a064c598373fcf0d66aebf98ab7af1d8e2f343f77baefff69a6da750a219e11", "0xaa5cc43f5b8162b016f5e1b61214c0c9d15b1078911c650b75e6cdfb49b85ee04c6739f5b1687d15908444f691f732de", "0xad4ac099b935589c7b8fdfdf3db332b7b82bb948e13a5beb121ebd7db81a87d278024a1434bcf0115c54ca5109585c3d", "0x8a00466abf3f109a1dcd19e643b603d3af23d42794ef8ca2514dd507ecea44a031ac6dbc18bd02f99701168b25c1791e", "0xb00b5900dfad79645f8bee4e5adc7b84eb22e5b1e67df77ccb505b7fc044a6c08a8ea5faca662414eb945f874f884cea", "0x950e204e5f17112250b22ea6bb8423baf522fc0af494366f18fe0f949f51d6e6812074a80875cf1ed9c8e7420058d541", "0x91e5cbf8bb1a1d50c81608c9727b414d0dd2fb467ebc92f100882a3772e54f94979cfdf8e373fdef7c7fcdd60fec9e00", "0xa093f6a857b8caaff80599c2e89c962b415ecbaa70d8fd973155fa976a284c6b29a855f5f7a3521134d00d2972755188", "0xb4d55a3551b00da54cc010f80d99ddd2544bde9219a3173dfaadf3848edc7e4056ab532fb75ac26f5f7141e724267663", "0xa03ea050fc9b011d1b04041b5765d6f6453a93a1819cd9bd6328637d0b428f08526466912895dcc2e3008ee58822e9a7", "0x99b12b3665e473d01bc6985844f8994fb65cb15745024fb7af518398c4a37ff215da8f054e8fdf3286984ae36a73ca5e", "0x9972c7e7a7fb12e15f78d55abcaf322c11249cd44a08f62c95288f34f66b51f146302bce750ff4d591707075d9123bd2", "0xa64b4a6d72354e596d87cda213c4fc2814009461570ccb27d455bbe131f8d948421a71925425b546d8cf63d5458cd64b", "0x91c215c73b195795ede2228b7ed1f6e37892e0c6b0f4a0b5a16c57aa1100c84df9239054a173b6110d6c2b7f4bf1ce52", "0x88807198910ec1303480f76a3683870246a995e36adaeadc29c22f0bdba8152fe705bd070b75de657b04934f7d0ccf80", "0xb37c0026c7b32eb02cacac5b55cb5fe784b8e48b2945c64d3037af83ece556a117f0ff053a5968c2f5fa230e291c1238", "0x94c768384ce212bc2387e91ce8b45e4ff120987e42472888a317abc9dcdf3563b62e7a61c8e98d7cdcbe272167d91fc6", "0xa10c2564936e967a390cb14ef6e8f8b04ea9ece5214a38837eda09e79e0c7970b1f83adf017c10efd6faa8b7ffa2c567", "0xa5085eed3a95f9d4b1269182ea1e0d719b7809bf5009096557a0674bde4201b0ddc1f0f16a908fc468846b3721748ce3", "0x87468eb620b79a0a455a259a6b4dfbc297d0d53336537b771254dd956b145dc816b195b7002647ea218552e345818a3f", "0xace2b77ffb87366af0a9cb5d27d6fc4a14323dbbf1643f5f3c4559306330d86461bb008894054394cbfaefeaa0bc2745", "0xb27f56e840a54fbd793f0b7a7631aa4cee64b5947e4382b2dfb5eb1790270288884c2a19afebe5dc0c6ef335d4531c1c", "0x876e438633931f7f895062ee16c4b9d10428875f7bc79a8e156a64d379a77a2c45bf5430c5ab94330f03da352f1e9006", "0xa2512a252587d200d2092b44c914df54e04ff8bcef36bf631f84bde0cf5a732e3dc7f00f662842cfd74b0b0f7f24180e", "0x827f1bc8f54a35b7a4bd8154f79bcc055e45faed2e74adf7cf21cca95df44d96899e847bd70ead6bb27b9c0ed97bbd8b", "0xa0c92cf5a9ed843714f3aea9fe7b880f622d0b4a3bf66de291d1b745279accf6ba35097849691370f41732ba64b5966b", "0xa63f5c1e222775658421c487b1256b52626c6f79cb55a9b7deb2352622cedffb08502042d622eb3b02c97f9c09f9c957", "0x8cc093d52651e65fb390e186db6cc4de559176af4624d1c44cb9b0e836832419dacac7b8db0627b96288977b738d785d", "0xaa7b6a17dfcec146134562d32a12f7bd7fe9522e300859202a02939e69dbd345ed7ff164a184296268f9984f9312e8fc", "0x8ac76721f0d2b679f023d06cbd28c85ae5f4b43c614867ccee88651d4101d4fd352dbdb65bf36bfc3ebc0109e4b0c6f9", "0x8d350f7c05fc0dcd9a1170748846fb1f5d39453e4cb31e6d1457bed287d96fc393b2ecc53793ca729906a33e59c6834a", "0xb9913510dfc5056d7ec5309f0b631d1ec53e3a776412ada9aefdaf033c90da9a49fdde6719e7c76340e86599b1f0eec2", "0x94955626bf4ce87612c5cfffcf73bf1c46a4c11a736602b9ba066328dc52ad6d51e6d4f53453d4ed55a51e0aad810271", "0xb0fcab384fd4016b2f1e53f1aafd160ae3b1a8865cd6c155d7073ecc1664e05b1d8bca1def39c158c7086c4e1103345e", "0x827de3f03edfbde08570b72de6662c8bfa499b066a0a27ebad9b481c273097d17a5a0a67f01553da5392ec3f149b2a78", "0xab7940384c25e9027c55c40df20bd2a0d479a165ced9b1046958353cd69015eeb1e44ed2fd64e407805ba42df10fc7bf", "0x8ad456f6ff8cd58bd57567d931f923d0c99141978511b17e03cab7390a72b9f62498b2893e1b05c7c22dd274e9a31919", "0xac75399e999effe564672db426faa17a839e57c5ef735985c70cd559a377adec23928382767b55ed5a52f7b11b54b756", "0xb17f975a00b817299ac7af5f2024ea820351805df58b43724393bfb3920a8cd747a3bbd4b8286e795521489db3657168", "0xa2bed800a6d95501674d9ee866e7314063407231491d794f8cf57d5be020452729c1c7cefd8c50dc1540181f5caab248", "0x9743f5473171271ffdd3cc59a3ae50545901a7b45cd4bc3570db487865f3b73c0595bebabbfe79268809ee1862e86e4a", "0xb7eab77c2d4687b60d9d7b04e842b3880c7940140012583898d39fcc22d9b9b0a9be2c2e3788b3e6f30319b39c338f09", "0x8e2b8f797a436a1b661140e9569dcf3e1eea0a77c7ff2bc4ff0f3e49af04ed2de95e255df8765f1d0927fb456a9926b1", "0x8aefea201d4a1f4ff98ffce94e540bb313f2d4dfe7e9db484a41f13fc316ed02b282e1acc9bc6f56cad2dc2e393a44c9", "0xb950c17c0e5ca6607d182144aa7556bb0efe24c68f06d79d6413a973b493bfdf04fd147a4f1ab03033a32004cc3ea66f", "0xb7b8dcbb179a07165f2dc6aa829fad09f582a71b05c3e3ea0396bf9e6fe73076f47035c031c2101e8e38e0d597eadd30", "0xa9d77ed89c77ec1bf8335d08d41c3c94dcca9fd1c54f22837b4e54506b212aa38d7440126c80648ab7723ff18e65ed72", "0xa819d6dfd4aef70e52b8402fe5d135f8082d40eb7d3bb5c4d7997395b621e2bb10682a1bad2c9caa33dd818550fc3ec6", "0x8f6ee34128fac8bbf13ce2d68b2bb363eb4fd65b297075f88e1446ddeac242500eeb4ef0735e105882ff5ba8c44c139b", "0xb4440e48255c1644bcecf3a1e9958f1ec4901cb5b1122ee5b56ffd02cad1c29c4266999dbb85aa2605c1b125490074d4", "0xa43304a067bede5f347775d5811cf65a6380a8d552a652a0063580b5c5ef12a0867a39c7912fa219e184f4538eba1251", "0xa891ad67a790089ffc9f6d53e6a3d63d3556f5f693e0cd8a7d0131db06fd4520e719cfcc3934f0a8f62a95f90840f1d4", "0xaea6df8e9bb871081aa0fc5a9bafb00be7d54012c5baf653791907d5042a326aeee966fd9012a582cc16695f5baf7042", "0x8ffa2660dc52ed1cd4eff67d6a84a8404f358a5f713d04328922269bee1e75e9d49afeec0c8ad751620f22352a438e25", "0x87ec6108e2d63b06abed350f8b363b7489d642486f879a6c3aa90e5b0f335efc2ff2834eef9353951a42136f8e6a1b32", "0x865619436076c2760d9e87ddc905023c6de0a8d56eef12c98a98c87837f2ca3f27fd26a2ad752252dbcbe2b9f1d5a032", "0x980437dce55964293cb315c650c5586ffd97e7a944a83f6618af31c9d92c37b53ca7a21bb5bc557c151b9a9e217e7098", "0x95d128fc369df4ad8316b72aea0ca363cbc7b0620d6d7bb18f7076a8717a6a46956ff140948b0cc4f6d2ce33b5c10054", "0x8c7212d4a67b9ec70ebbca04358ad2d36494618d2859609163526d7b3acc2fc935ca98519380f55e6550f70a9bc76862", "0x893a2968819401bf355e85eee0f0ed0406a6d4a7d7f172d0017420f71e00bb0ba984f6020999a3cdf874d3cd8ebcd371", "0x9103c1af82dece25d87274e89ea0acd7e68c2921c4af3d8d7c82ab0ed9990a5811231b5b06113e7fa43a6bd492b4564f", "0x99cfd87a94eab7d35466caa4ed7d7bb45e5c932b2ec094258fb14bf205659f83c209b83b2f2c9ccb175974b2a33e7746", "0x874b6b93e4ee61be3f00c32dd84c897ccd6855c4b6251eb0953b4023634490ed17753cd3223472873cbc6095b2945075", "0x84a32c0dc4ea60d33aac3e03e70d6d639cc9c4cc435c539eff915017be3b7bdaba33349562a87746291ebe9bc5671f24", "0xa7057b24208928ad67914e653f5ac1792c417f413d9176ba635502c3f9c688f7e2ee81800d7e3dc0a340c464da2fd9c5", "0xa03fb9ed8286aacfa69fbd5d953bec591c2ae4153400983d5dbb6cd9ea37fff46ca9e5cceb9d117f73e9992a6c055ad2", "0x863b2de04e89936c9a4a2b40380f42f20aefbae18d03750fd816c658aee9c4a03df7b12121f795c85d01f415baaeaa59", "0x8526eb9bd31790fe8292360d7a4c3eed23be23dd6b8b8f01d2309dbfdc0cfd33ad1568ddd7f8a610f3f85a9dfafc6a92", "0xb46ab8c5091a493d6d4d60490c40aa27950574a338ea5bbc045be3a114af87bdcb160a8c80435a9b7ad815f3cb56a3f3", "0xaeadc47b41a8d8b4176629557646202f868b1d728b2dda58a347d937e7ffc8303f20d26d6c00b34c851b8aeec547885d", "0xaebb19fc424d72c1f1822aa7adc744cd0ef7e55727186f8df8771c784925058c248406ebeeaf3c1a9ee005a26e9a10c6", "0x8ff96e81c1a4a2ab1b4476c21018fae0a67e92129ee36120cae8699f2d7e57e891f5c624902cb1b845b944926a605cc3", "0x8251b8d2c43fadcaa049a9e7aff838dae4fb32884018d58d46403ac5f3beb5c518bfd45f03b8abb710369186075eb71c", "0xa8b2a64f865f51a5e5e86a66455c093407933d9d255d6b61e1fd81ffafc9538d73caaf342338a66ba8ee166372a3d105", "0xaad915f31c6ba7fdc04e2aaac62e84ef434b7ee76a325f07dc430d12c84081999720181067b87d792efd0117d7ee1eab", "0xa13db3bb60389883fd41d565c54fb5180d9c47ce2fe7a169ae96e01d17495f7f4fa928d7e556e7c74319c4c25d653eb2", "0xa4491b0198459b3f552855d680a59214eb74e6a4d6c5fa3b309887dc50ebea2ecf6d26c040550f7dc478b452481466fb", "0x8f017f13d4b1e3f0c087843582b52d5f8d13240912254d826dd11f8703a99a2f3166dfbdfdffd9a3492979d77524276b", "0x96c3d5dcd032660d50d7cd9db2914f117240a63439966162b10c8f1f3cf74bc83b0f15451a43b31dbd85e4a7ce0e4bb1", "0xb479ec4bb79573d32e0ec93b92bdd7ec8c26ddb5a2d3865e7d4209d119fd3499eaac527615ffac78c440e60ef3867ae0", "0xb2c49c4a33aa94b52b6410b599e81ff15490aafa7e43c8031c865a84e4676354a9c81eb4e7b8be6825fdcefd1e317d44", "0x906dc51d6a90c089b6704b47592805578a6eed106608eeb276832f127e1b8e858b72e448edcbefb497d152447e0e68ff", "0xb0e81c63b764d7dfbe3f3fddc9905aef50f3633e5d6a4af6b340495124abedcff5700dfd1577bbbed7b6bf97d02719cb", "0x9304c64701e3b4ed6d146e48a881f7d83a17f58357cca0c073b2bb593afd2d94f6e2a7a1ec511d0a67ad6ff4c3be5937", "0xb6fdbd12ba05aa598d80b83f70a15ef90e5cba7e6e75fa038540ee741b644cd1f408a6cecfd2a891ef8d902de586c6b5", "0xb80557871a6521b1b3c74a1ba083ae055b575df607f1f7b04c867ba8c8c181ea68f8d90be6031f4d25002cca27c44da2", "0xaa7285b8e9712e06b091f64163f1266926a36607f9d624af9996856ed2aaf03a580cb22ce407d1ade436c28b44ca173f", "0x8148d72b975238b51e6ea389e5486940d22641b48637d7dfadfa603a605bfc6d74a016480023945d0b85935e396aea5d", "0x8a014933a6aea2684b5762af43dcf4bdbb633cd0428d42d71167a2b6fc563ece5e618bff22f1db2ddb69b845b9a2db19", "0x990d91740041db770d0e0eb9d9d97d826f09fd354b91c41e0716c29f8420e0e8aac0d575231efba12fe831091ec38d5a", "0x9454d0d32e7e308ddec57cf2522fb1b67a2706e33fb3895e9e1f18284129ab4f4c0b7e51af25681d248d7832c05eb698", "0xa5bd434e75bac105cb3e329665a35bce6a12f71dd90c15165777d64d4c13a82bceedb9b48e762bd24034e0fc9fbe45f4", "0xb09e3b95e41800d4dc29c6ffdaab2cd611a0050347f6414f154a47ee20ee59bf8cf7181454169d479ebce1eb5c777c46", "0xb193e341d6a047d15eea33766d656d807b89393665a783a316e9ba10518e5515c8e0ade3d6e15641d917a8a172a5a635", "0xade435ec0671b3621dde69e07ead596014f6e1daa1152707a8c18877a8b067bde2895dd47444ffa69db2bbef1f1d8816", "0xa7fd3d6d87522dfc56fb47aef9ce781a1597c56a8bbfd796baba907afdc872f753d732bfda1d3402aee6c4e0c189f52d", "0xa298cb4f4218d0464b2fab393e512bbc477c3225aa449743299b2c3572f065bc3a42d07e29546167ed9e1b6b3b3a3af3", "0xa9ee57540e1fd9c27f4f0430d194b91401d0c642456c18527127d1f95e2dba41c2c86d1990432eb38a692fda058fafde", "0x81d6c1a5f93c04e6d8e5a7e0678c1fc89a1c47a5c920bcd36180125c49fcf7c114866b90e90a165823560b19898a7c16", "0xa4b7a1ec9e93c899b9fd9aaf264c50e42c36c0788d68296a471f7a3447af4dbc81e4fa96070139941564083ec5b5b5a1", "0xb3364e327d381f46940c0e11e29f9d994efc6978bf37a32586636c0070b03e4e23d00650c1440f448809e1018ef9f6d8", "0x8056e0913a60155348300e3a62e28b5e30629a90f7dd4fe11289097076708110a1d70f7855601782a3cdc5bdb1ca9626", "0xb4980fd3ea17bac0ba9ee1c470b17e575bb52e83ebdd7d40c93f4f87bebeaff1c8a679f9d3d09d635f068d37d5bd28bd", "0x905a9299e7e1853648e398901dfcd437aa575c826551f83520df62984f5679cb5f0ea86aa45ed3e18b67ddc0dfafe809", "0xab99553bf31a84f2e0264eb34a08e13d8d15e2484aa9352354becf9a15999c76cc568d68274b70a65e49703fc23540d0", "0xa43681597bc574d2dae8964c9a8dc1a07613d7a1272bdcb818d98c85d44e16d744250c33f3b5e4d552d97396b55e601f", "0xa54e5a31716fccb50245898c99865644405b8dc920ded7a11f3d19bdc255996054b268e16f2e40273f11480e7145f41e", "0x8134f3ad5ef2ad4ba12a8a4e4d8508d91394d2bcdc38b7c8c8c0b0a820357ac9f79d286c65220f471eb1adca1d98fc68", "0x94e2f755e60471578ab2c1adb9e9cea28d4eec9b0e92e0140770bca7002c365fcabfe1e5fb4fe6cfe79a0413712aa3ef", "0xad48f8d0ce7eb3cc6e2a3086ad96f562e5bed98a360721492ae2e74dc158586e77ec8c35d5fd5927376301b7741bad2b", "0x8614f0630bdd7fbad3a31f55afd9789f1c605dc85e7dc67e2edfd77f5105f878bb79beded6e9f0b109e38ea7da67e8d5", "0x9804c284c4c5e77dabb73f655b12181534ca877c3e1e134aa3f47c23b7ec92277db34d2b0a5d38d2b69e5d1c3008a3e3", "0xa51b99c3088e473afdaa9e0a9f7e75a373530d3b04e44e1148da0726b95e9f5f0c7e571b2da000310817c36f84b19f7f", "0xac4ff909933b3b76c726b0a382157cdc74ab851a1ac6cef76953c6444441804cc43abb883363f416592e8f6cfbc4550b", "0xae7d915eb9fc928b65a29d6edbc75682d08584d0014f7bcf17d59118421ae07d26a02137d1e4de6938bcd1ab8ef48fad", "0x852f7e453b1af89b754df6d11a40d5d41ea057376e8ecacd705aacd2f917457f4a093d6b9a8801837fa0f62986ad7149", "0x92c6bf5ada5d0c3d4dd8058483de36c215fa98edab9d75242f3eff9db07c734ad67337da6f0eefe23a487bf75a600dee", "0xa2b42c09d0db615853763552a48d2e704542bbd786aae016eb58acbf6c0226c844f5fb31e428cb6450b9db855f8f2a6f", "0x880cc07968266dbfdcfbc21815cd69e0eddfee239167ac693fb0413912d816f2578a74f7716eecd6deefa68c6eccd394", "0xb885b3ace736cd373e8098bf75ba66fa1c6943ca1bc4408cd98ac7074775c4478594f91154b8a743d9c697e1b29f5840", "0xa51ce78de512bd87bfa0835de819941dffbf18bec23221b61d8096fc9436af64e0693c335b54e7bfc763f287bdca2db6", "0xa3c76166a3bdb9b06ef696e57603b58871bc72883ee9d45171a30fe6e1d50e30bc9c51b4a0f5a7270e19a77b89733850", "0xacefc5c6f8a1e7c24d7b41e0fc7f6f3dc0ede6cf3115ffb9a6e54b1d954cbca9bda8ad7a084be9be245a1b8e9770d141", "0xb420ed079941842510e31cfad117fa11fb6b4f97dfbc6298cb840f27ebaceba23eeaf3f513bcffbf5e4aae946310182d", "0x95c3bb5ef26c5ed2f035aa5d389c6b3c15a6705b9818a3fefaed28922158b35642b2e8e5a1a620fdad07e75ad4b43af4", "0x825149f9081ecf07a2a4e3e8b5d21bade86c1a882475d51c55ee909330b70c5a2ac63771c8600c6f38df716af61a3ea1", "0x873b935aae16d9f08adbc25353cee18af2f1b8d5f26dec6538d6bbddc515f2217ed7d235dcfea59ae61b428798b28637", "0x9294150843a2bedcedb3bb74c43eb28e759cf9499582c5430bccefb574a8ddd4f11f9929257ff4c153990f9970a2558f", "0xb619563a811cc531da07f4f04e5c4c6423010ff9f8ed7e6ec9449162e3d501b269fb1c564c09c0429431879b0f45df02", "0x91b509b87eb09f007d839627514658c7341bc76d468920fe8a740a8cb96a7e7e631e0ea584a7e3dc1172266f641d0f5c", "0x8b8aceace9a7b9b4317f1f01308c3904d7663856946afbcea141a1c615e21ccad06b71217413e832166e9dd915fbe098", "0x87b3b36e725833ea0b0f54753c3728c0dbc87c52d44d705ffc709f2d2394414c652d3283bab28dcce09799504996cee0", "0xb2670aad5691cbf308e4a6a77a075c4422e6cbe86fdba24e9f84a313e90b0696afb6a067eebb42ba2d10340d6a2f6e51", "0x876784a9aff3d54faa89b2bacd3ff5862f70195d0b2edc58e8d1068b3c9074c0da1cfa23671fe12f35e33b8a329c0ccd", "0x8b48b9e758e8a8eae182f5cbec96f67d20cca6d3eee80a2d09208eb1d5d872e09ef23d0df8ebbb9b01c7449d0e3e3650", "0xb79303453100654c04a487bdcadc9e3578bc80930c489a7069a52e8ca1dba36c492c8c899ce025f8364599899baa287d", "0x961b35a6111da54ece6494f24dacd5ea46181f55775b5f03df0e370c34a5046ac2b4082925855325bb42bc2a2c98381d", "0xa31feb1be3f5a0247a1f7d487987eb622e34fca817832904c6ee3ee60277e5847945a6f6ea1ac24542c72e47bdf647df", "0xa12a2aa3e7327e457e1aae30e9612715dd2cfed32892c1cd6dcda4e9a18203af8a44afb46d03b2eed89f6b9c5a2c0c23", "0xa08265a838e69a2ca2f80fead6ccf16f6366415b920c0b22ee359bcd8d4464ecf156f400a16a7918d52e6d733dd64211", "0xb723d6344e938d801cca1a00032af200e541d4471fd6cbd38fb9130daa83f6a1dffbbe7e67fc20f9577f884acd7594b2", "0xa6733d83ec78ba98e72ddd1e7ff79b7adb0e559e256760d0c590a986e742445e8cdf560d44b29439c26d87edd0b07c8c", "0xa61c2c27d3f7b9ff4695a17afedf63818d4bfba390507e1f4d0d806ce8778d9418784430ce3d4199fd3bdbc2504d2af3", "0x8332f3b63a6dc985376e8b1b25eeae68be6160fbe40053ba7bcf6f073204f682da72321786e422d3482fd60c9e5aa034", "0xa280f44877583fbb6b860d500b1a3f572e3ee833ec8f06476b3d8002058e25964062feaa1e5bec1536d734a5cfa09145", "0xa4026a52d277fcea512440d2204f53047718ebfcae7b48ac57ea7f6bfbc5de9d7304db9a9a6cbb273612281049ddaec5", "0x95cdf69c831ab2fad6c2535ede9c07e663d2ddccc936b64e0843d2df2a7b1c31f1759c3c20f1e7a57b1c8f0dbb21b540", "0x95c96cec88806469c277ab567863c5209027cecc06c7012358e5f555689c0d9a5ffb219a464f086b45817e8536b86d2f", "0xafe38d4684132a0f03d806a4c8df556bf589b25271fbc6fe2e1ed16de7962b341c5003755da758d0959d2e6499b06c68", "0xa9b77784fda64987f97c3a23c5e8f61b918be0f7c59ba285084116d60465c4a2aaafc8857eb16823282cc83143eb9126", "0xa830f05881ad3ce532a55685877f529d32a5dbe56cea57ffad52c4128ee0fad0eeaf0da4362b55075e77eda7babe70e5", "0x992b3ad190d6578033c13ed5abfee4ef49cbc492babb90061e3c51ee4b5790cdd4c8fc1abff1fa2c00183b6b64f0bbbe", "0xb1015424d9364aeff75de191652dc66484fdbec3e98199a9eb9671ec57bec6a13ff4b38446e28e4d8aedb58dd619cd90", "0xa745304604075d60c9db36cada4063ac7558e7ec2835d7da8485e58d8422e817457b8da069f56511b02601289fbb8981", "0xa5ba4330bc5cb3dbe0486ddf995632a7260a46180a08f42ae51a2e47778142132463cc9f10021a9ad36986108fefa1a9", "0xb419e9fd4babcaf8180d5479db188bb3da232ae77a1c4ed65687c306e6262f8083070a9ac32220cddb3af2ec73114092", "0xa49e23dc5f3468f3bf3a0bb7e4a114a788b951ff6f23a3396ae9e12cbff0abd1240878a3d1892105413dbc38818e807c", "0xb7ecc7b4831f650202987e85b86bc0053f40d983f252e9832ef503aea81c51221ce93279da4aa7466c026b2d2070e55d", "0x96a8c35cb87f84fa84dcd6399cc2a0fd79cc9158ef4bdde4bae31a129616c8a9f2576cd19baa3f497ca34060979aed7d", "0x8681b2c00aa62c2b519f664a95dcb8faef601a3b961bb4ce5d85a75030f40965e2983871d41ea394aee934e859581548", "0x85c229a07efa54a713d0790963a392400f55fbb1a43995a535dc6c929f20d6a65cf4efb434e0ad1cb61f689b8011a3bc", "0x90856f7f3444e5ad44651c28e24cc085a5db4d2ffe79aa53228c26718cf53a6e44615f3c5cda5aa752d5f762c4623c66", "0x978999b7d8aa3f28a04076f74d11c41ef9c89fdfe514936c4238e0f13c38ec97e51a5c078ebc6409e517bfe7ccb42630", "0xa099914dd7ed934d8e0d363a648e9038eb7c1ec03fa04dbcaa40f7721c618c3ef947afef7a16b4d7ac8c12aa46637f03", "0xab2a104fed3c83d16f2cda06878fa5f30c8c9411de71bfb67fd2fc9aa454dcbcf3d299d72f8cc12e919466a50fcf7426", "0xa4471d111db4418f56915689482f6144efc4664cfb0311727f36c864648d35734351becc48875df96f4abd3cfcf820f9", "0x83be11727cd30ea94ccc8fa31b09b81c9d6a9a5d3a4686af9da99587332fe78c1f94282f9755854bafd6033549afec91", "0x88020ff971dc1a01a9e993cd50a5d2131ffdcbb990c1a6aaa54b20d8f23f9546a70918ea57a21530dcc440c1509c24ad", "0xae24547623465e87905eaffa1fa5d52bb7c453a8dbd89614fa8819a2abcedaf455c2345099b7324ae36eb0ad7c8ef977", "0xb59b0c60997de1ee00b7c388bc7101d136c9803bf5437b1d589ba57c213f4f835a3e4125b54738e78abbc21b000f2016", "0xa584c434dfe194546526691b68fa968c831c31da42303a1d735d960901c74011d522246f37f299555416b8cf25c5a548", "0x80408ce3724f4837d4d52376d255e10f69eb8558399ae5ca6c11b78b98fe67d4b93157d2b9b639f1b5b64198bfe87713", "0xabb941e8d406c2606e0ddc35c113604fdd9d249eacc51cb64e2991e551b8639ce44d288cc92afa7a1e7fc599cfc84b22", "0xb223173f560cacb1c21dba0f1713839e348ad02cbfdef0626748604c86f89e0f4c919ed40b583343795bdd519ba952c8", "0xaf1c70512ec3a19d98b8a1fc3ff7f7f5048a27d17d438d43f561974bbdd116fcd5d5c21040f3447af3f0266848d47a15", "0x8a44809568ebe50405bede19b4d2607199159b26a1b33e03d180e6840c5cf59d991a4fb150d111443235d75ecad085b7", "0xb06207cdca46b125a27b3221b5b50cf27af4c527dd7c80e2dbcebbb09778a96df3af67e50f07725239ce3583dad60660", "0x993352d9278814ec89b26a11c4a7c4941bf8f0e6781ae79559d14749ee5def672259792db4587f85f0100c7bb812f933", "0x9180b8a718b971fd27bc82c8582d19c4b4f012453e8c0ffeeeffe745581fc6c07875ab28be3af3fa3896d19f0c89ac5b", "0x8b8e1263eb48d0fe304032dd5ea1f30e73f0121265f7458ba9054d3626894e8a5fef665340abd2ede9653045c2665938", "0x99a2beee4a10b7941c24b2092192faf52b819afd033e4a2de050fd6c7f56d364d0cf5f99764c3357cf32399e60fc5d74", "0x946a4aad7f8647ea60bee2c5fcdeb6f9a58fb2cfca70c4d10e458027a04846e13798c66506151be3df9454b1e417893f", "0xa672a88847652d260b5472d6908d1d57e200f1e492d30dd1cecc441cdfc9b76e016d9bab560efd4d7f3c30801de884a9", "0x9414e1959c156cde1eb24e628395744db75fc24b9df4595350aaad0bc38e0246c9b4148f6443ef68b8e253a4a6bcf11c", "0x9316e9e4ec5fab4f80d6540df0e3a4774db52f1d759d2e5b5bcd3d7b53597bb007eb1887cb7dc61f62497d51ffc8d996", "0x902d6d77bb49492c7a00bc4b70277bc28c8bf9888f4307bb017ac75a962decdedf3a4e2cf6c1ea9f9ba551f4610cbbd7", "0xb07025a18b0e32dd5e12ec6a85781aa3554329ea12c4cd0d3b2c22e43d777ef6f89876dd90a9c8fb097ddf61cf18adc5", "0xb355a849ad3227caa4476759137e813505ec523cbc2d4105bc7148a4630f9e81918d110479a2d5f5e4cd9ccec9d9d3e3", "0xb49532cfdf02ee760109881ad030b89c48ee3bb7f219ccafc13c93aead754d29bdafe345be54c482e9d5672bd4505080", "0x9477802410e263e4f938d57fa8f2a6cac7754c5d38505b73ee35ea3f057aad958cb9722ba6b7b3cfc4524e9ca93f9cdc", "0x9148ea83b4436339580f3dbc9ba51509e9ab13c03063587a57e125432dd0915f5d2a8f456a68f8fff57d5f08c8f34d6e", "0xb00b6b5392b1930b54352c02b1b3b4f6186d20bf21698689bbfc7d13e86538a4397b90e9d5c93fd2054640c4dbe52a4f", "0x926a9702500441243cd446e7cbf15dde16400259726794694b1d9a40263a9fc9e12f7bcbf12a27cb9aaba9e2d5848ddc", "0xa0c6155f42686cbe7684a1dc327100962e13bafcf3db97971fc116d9f5c0c8355377e3d70979cdbd58fd3ea52440901c", "0xa277f899f99edb8791889d0817ea6a96c24a61acfda3ad8c3379e7c62b9d4facc4b965020b588651672fd261a77f1bfc", "0x8f528cebb866b501f91afa50e995234bef5bf20bff13005de99cb51eaac7b4f0bf38580cfd0470de40f577ead5d9ba0f", "0x963fc03a44e9d502cc1d23250efef44d299befd03b898d07ce63ca607bb474b5cf7c965a7b9b0f32198b04a8393821f7", "0xab087438d0a51078c378bf4a93bd48ef933ff0f1fa68d02d4460820df564e6642a663b5e50a5fe509527d55cb510ae04", "0xb0592e1f2c54746bb076be0fa480e1c4bebc4225e1236bcda3b299aa3853e3afb401233bdbcfc4a007b0523a720fbf62", "0x851613517966de76c1c55a94dc4595f299398a9808f2d2f0a84330ba657ab1f357701d0895f658c18a44cb00547f6f57", "0xa2fe9a1dd251e72b0fe4db27be508bb55208f8f1616b13d8be288363ec722826b1a1fd729fc561c3369bf13950bf1fd6", "0xb896cb2bc2d0c77739853bc59b0f89b2e008ba1f701c9cbe3bef035f499e1baee8f0ff1e794854a48c320586a2dfc81a", "0xa1b60f98e5e5106785a9b81a85423452ee9ef980fa7fa8464f4366e73f89c50435a0c37b2906052b8e58e212ebd366cf", "0xa853b0ebd9609656636df2e6acd5d8839c0fda56f7bf9288a943b06f0b67901a32b95e016ca8bc99bd7b5eab31347e72", "0xb290fa4c1346963bd5225235e6bdf7c542174dab4c908ab483d1745b9b3a6015525e398e1761c90e4b49968d05e30eea", "0xb0f65a33ad18f154f1351f07879a183ad62e5144ad9f3241c2d06533dad09cbb2253949daff1bb02d24d16a3569f7ef0", "0xa00db59b8d4218faf5aeafcd39231027324408f208ec1f54d55a1c41228b463b88304d909d16b718cfc784213917b71e", "0xb8d695dd33dc2c3bc73d98248c535b2770ad7fa31aa726f0aa4b3299efb0295ba9b4a51c71d314a4a1bd5872307534d1", "0xb848057cca2ca837ee49c42b88422303e58ea7d2fc76535260eb5bd609255e430514e927cc188324faa8e657396d63ec", "0x92677836061364685c2aaf0313fa32322746074ed5666fd5f142a7e8f87135f45cd10e78a17557a4067a51dfde890371", "0xa854b22c9056a3a24ab164a53e5c5cf388616c33e67d8ebb4590cb16b2e7d88b54b1393c93760d154208b5ca822dc68f", "0x86fff174920388bfab841118fb076b2b0cdec3fdb6c3d9a476262f82689fb0ed3f1897f7be9dbf0932bb14d346815c63", "0x99661cf4c94a74e182752bcc4b98a8c2218a8f2765642025048e12e88ba776f14f7be73a2d79bd21a61def757f47f904", "0x8a8893144d771dca28760cba0f950a5d634195fd401ec8cf1145146286caffb0b1a6ba0c4c1828d0a5480ce49073c64c", "0x938a59ae761359ee2688571e7b7d54692848eb5dde57ffc572b473001ea199786886f8c6346a226209484afb61d2e526", "0x923f68a6aa6616714cf077cf548aeb845bfdd78f2f6851d8148cba9e33a374017f2f3da186c39b82d14785a093313222", "0xac923a93d7da7013e73ce8b4a2b14b8fd0cc93dc29d5de941a70285bdd19be4740fedfe0c56b046689252a3696e9c5bc", "0xb49b32c76d4ec1a2c68d4989285a920a805993bc6fcce6dacd3d2ddae73373050a5c44ba8422a3781050682fa0ef6ba2", "0x8a367941c07c3bdca5712524a1411bad7945c7c48ffc7103b1d4dff2c25751b0624219d1ccde8c3f70c465f954be5445", "0xb838f029df455efb6c530d0e370bbbf7d87d61a9aea3d2fe5474c5fe0a39cf235ceecf9693c5c6c5820b1ba8f820bd31", "0xa8983b7c715eaac7f13a001d2abc462dfc1559dab4a6b554119c271aa8fe00ffcf6b6949a1121f324d6d26cb877bcbae", "0xa2afb24ad95a6f14a6796315fbe0d8d7700d08f0cfaf7a2abe841f5f18d4fecf094406cbd54da7232a159f9c5b6e805e", "0x87e8e95ad2d62f947b2766ff405a23f7a8afba14e7f718a691d95369c79955cdebe24c54662553c60a3f55e6322c0f6f", "0x87c2cbcecb754e0cc96128e707e5c5005c9de07ffd899efa3437cadc23362f5a1d3fcdd30a1f5bdc72af3fb594398c2a", "0x91afd6ee04f0496dc633db88b9370d41c428b04fd991002502da2e9a0ef051bcd7b760e860829a44fbe5539fa65f8525", "0x8c50e5d1a24515a9dd624fe08b12223a75ca55196f769f24748686315329b337efadca1c63f88bee0ac292dd0a587440", "0x8a07e8f912a38d94309f317c32068e87f68f51bdfa082d96026f5f5f8a2211621f8a3856dda8069386bf15fb2d28c18f", "0x94ad1dbe341c44eeaf4dc133eed47d8dbfe752575e836c075745770a6679ff1f0e7883b6aa917462993a7f469d74cab5", "0x8745f8bd86c2bb30efa7efb7725489f2654f3e1ac4ea95bd7ad0f3cfa223055d06c187a16192d9d7bdaea7b050c6a324", "0x900d149c8d79418cda5955974c450a70845e02e5a4ecbcc584a3ca64d237df73987c303e3eeb79da1af83bf62d9e579f", "0x8f652ab565f677fb1a7ba03b08004e3cda06b86c6f1b0b9ab932e0834acf1370abb2914c15b0d08327b5504e5990681c", "0x9103097d088be1f75ab9d3da879106c2f597e2cc91ec31e73430647bdd5c33bcfd771530d5521e7e14df6acda44f38a6", "0xb0fec7791cfb0f96e60601e1aeced9a92446b61fedab832539d1d1037558612d78419efa87ff5f6b7aab8fd697d4d9de", "0xb9d2945bdb188b98958854ba287eb0480ef614199c4235ce5f15fc670b8c5ffe8eeb120c09c53ea8a543a022e6a321ac", "0xa9461bb7d5490973ebaa51afc0bb4a5e42acdccb80e2f939e88b77ac28a98870e103e1042899750f8667a8cc9123bae9", "0xa37fdf11d4bcb2aed74b9f460a30aa34afea93386fa4cdb690f0a71bc58f0b8df60bec56e7a24f225978b862626fa00e", "0xa214420e183e03d531cf91661466ea2187d84b6e814b8b20b3730a9400a7d25cf23181bb85589ebc982cec414f5c2923", "0xad09a45a698a6beb3e0915f540ef16e9af7087f53328972532d6b5dfe98ce4020555ece65c6cbad8bd6be8a4dfefe6fd", "0xab6742800b02728c92d806976764cb027413d6f86edd08ad8bb5922a2969ee9836878cd39db70db0bd9a2646862acc4f", "0x974ca9305bd5ea1dc1755dff3b63e8bfe9f744321046c1395659bcea2a987b528e64d5aa96ac7b015650b2253b37888d", "0x84eee9d6bce039c52c2ebc4fccc0ad70e20c82f47c558098da4be2f386a493cbc76adc795b5488c8d11b6518c2c4fab8", "0x875d7bda46efcb63944e1ccf760a20144df3b00d53282b781e95f12bfc8f8316dfe6492c2efbf796f1150e36e436e9df", "0xb68a2208e0c587b5c31b5f6cb32d3e6058a9642e2d9855da4f85566e1412db528475892060bb932c55b3a80877ad7b4a", "0xba006368ecab5febb6ab348644d9b63de202293085ed468df8bc24d992ae8ce468470aa37f36a73630c789fb9c819b30", "0x90a196035150846cd2b482c7b17027471372a8ce7d914c4d82b6ea7fa705d8ed5817bd42d63886242585baf7d1397a1c", "0xa223b4c85e0daa8434b015fd9170b5561fe676664b67064974a1e9325066ecf88fc81f97ab5011c59fad28cedd04b240", "0x82e8ec43139cf15c6bbeed484b62e06cded8a39b5ce0389e4cbe9c9e9c02f2f0275d8d8d4e8dfec8f69a191bef220408", "0x81a3fc07a7b68d92c6ee4b6d28f5653ee9ec85f7e2ee1c51c075c1b130a8c5097dc661cf10c5aff1c7114b1a6a19f11a", "0x8ed2ef8331546d98819a5dd0e6c9f8cb2630d0847671314a28f277faf68da080b53891dd75c82cbcf7788b255490785d", "0xacecabf84a6f9bbed6b2fc2e7e4b48f02ef2f15e597538a73aea8f98addc6badda15e4695a67ecdb505c1554e8f345ec", "0xb8f51019b2aa575f8476e03dcadf86cc8391f007e5f922c2a36b2daa63f5a503646a468990cd5c65148d323942193051", "0xaaa595a84b403ec65729bc1c8055a94f874bf9adddc6c507b3e1f24f79d3ad359595a672b93aab3394db4e2d4a7d8970", "0x895144c55fcbd0f64d7dd69e6855cfb956e02b5658eadf0f026a70703f3643037268fdd673b0d21b288578a83c6338dd", "0xa2e92ae6d0d237d1274259a8f99d4ea4912a299816350b876fba5ebc60b714490e198a916e1c38c6e020a792496fa23c", "0xa45795fda3b5bb0ad1d3c628f6add5b2a4473a1414c1a232e80e70d1cfffd7f8a8d9861f8df2946999d7dbb56bf60113", "0xb6659bf7f6f2fef61c39923e8c23b8c70e9c903028d8f62516d16755cd3fba2fe41c285aa9432dc75ab08f8a1d8a81fc", "0xa735609a6bc5bfd85e58234fc439ff1f58f1ff1dd966c5921d8b649e21f006bf2b8642ad8a75063c159aaf6935789293", "0xa3c622eb387c9d15e7bda2e3e84d007cb13a6d50d655c3f2f289758e49d3b37b9a35e4535d3cc53d8efd51f407281f19", "0x8afe147b53ad99220f5ef9d763bfc91f9c20caecbcf823564236fb0e6ede49414c57d71eec4772c8715cc65a81af0047", "0xb5f0203233cf71913951e9c9c4e10d9243e3e4a1f2cb235bf3f42009120ba96e04aa414c9938ea8873b63148478927e8", "0x93c52493361b458d196172d7ba982a90a4f79f03aa8008edc322950de3ce6acf4c3977807a2ffa9e924047e02072b229", "0xb9e72b805c8ac56503f4a86c82720afbd5c73654408a22a2ac0b2e5caccdfb0e20b59807433a6233bc97ae58cf14c70a", "0xaf0475779b5cee278cca14c82da2a9f9c8ef222eb885e8c50cca2315fea420de6e04146590ed0dd5a29c0e0812964df5", "0xb430ccab85690db02c2d0eb610f3197884ca12bc5f23c51e282bf3a6aa7e4a79222c3d8761454caf55d6c01a327595f9", "0x830032937418b26ee6da9b5206f3e24dc76acd98589e37937e963a8333e5430abd6ce3dd93ef4b8997bd41440eed75d6", "0x8820a6d73180f3fe255199f3f175c5eb770461ad5cfdde2fb11508041ed19b8c4ce66ad6ecebf7d7e836cc2318df47ca", "0xaef1393e7d97278e77bbf52ef6e1c1d5db721ccf75fe753cf47a881fa034ca61eaa5098ee5a344c156d2b14ff9e284ad", "0x8a4a26c07218948c1196c45d927ef4d2c42ade5e29fe7a91eaebe34a29900072ce5194cf28d51f746f4c4c649daf4396", "0x84011dc150b7177abdcb715efbd8c201f9cb39c36e6069af5c50a096021768ba40cef45b659c70915af209f904ede3b6", "0xb1bd90675411389bb66910b21a4bbb50edce5330850c5ab0b682393950124252766fc81f5ecfc72fb7184387238c402e", "0x8dfdcd30583b696d2c7744655f79809f451a60c9ad5bf1226dc078b19f4585d7b3ef7fa9d54e1ac09520d95cbfd20928", "0xb351b4dc6d98f75b8e5a48eb7c6f6e4b78451991c9ba630e5a1b9874c15ac450cd409c1a024713bf2cf82dc400e025ef", "0xa462b8bc97ac668b97b28b3ae24b9f5de60e098d7b23ecb600d2194cd35827fb79f77c3e50d358f5bd72ee83fef18fa0", "0xa183753265c5f7890270821880cce5f9b2965b115ba783c6dba9769536f57a04465d7da5049c7cf8b3fcf48146173c18", "0xa8a771b81ed0d09e0da4d79f990e58eabcd2be3a2680419502dd592783fe52f657fe55125b385c41d0ba3b9b9cf54a83", "0xa71ec577db46011689d073245e3b1c3222a9b1fe6aa5b83629adec5733dd48617ebea91346f0dd0e6cdaa86e4931b168", "0xa334b8b244f0d598a02da6ae0f918a7857a54dce928376c4c85df15f3b0f2ba3ac321296b8b7c9dd47d770daf16c8f8c", "0xa29037f8ef925c417c90c4df4f9fb27fb977d04e2b3dd5e8547d33e92ab72e7a00f5461de21e28835319eae5db145eb7", "0xb91054108ae78b00e3298d667b913ebc44d8f26e531eae78a8fe26fdfb60271c97efb2dee5f47ef5a3c15c8228138927", "0x926c13efbe90604f6244be9315a34f72a1f8d1aab7572df431998949c378cddbf2fe393502c930fff614ff06ae98a0ce", "0x995c758fd5600e6537089b1baa4fbe0376ab274ff3e82a17768b40df6f91c2e443411de9cafa1e65ea88fb8b87d504f4", "0x9245ba307a7a90847da75fca8d77ec03fdfc812c871e7a2529c56a0a79a6de16084258e7a9ac4ae8a3756f394336e21c", "0x99e0cfa2bb57a7e624231317044c15e52196ecce020db567c8e8cb960354a0be9862ee0c128c60b44777e65ac315e59f", "0xad4f6b3d27bbbb744126601053c3dc98c07ff0eb0b38a898bd80dce778372846d67e5ab8fb34fb3ad0ef3f235d77ba7f", "0xa0f12cae3722bbbca2e539eb9cc7614632a2aefe51410430070a12b5bc5314ecec5857b7ff8f41e9980cac23064f7c56", "0xb487f1bc59485848c98222fd3bc36c8c9bb3d2912e2911f4ceca32c840a7921477f9b1fe00877e05c96c75d3eecae061", "0xa6033db53925654e18ecb3ce715715c36165d7035db9397087ac3a0585e587998a53973d011ac6d48af439493029cee6", "0xa6b4d09cd01c70a3311fd131d3710ccf97bde3e7b80efd5a8c0eaeffeb48cca0f951ced905290267b115b06d46f2693b", "0xa9dff1df0a8f4f218a98b6f818a693fb0d611fed0fc3143537cbd6578d479af13a653a8155e535548a2a0628ae24fa58", "0xa58e469f65d366b519f9a394cacb7edaddac214463b7b6d62c2dbc1316e11c6c5184ce45c16de2d77f990dcdd8b55430", "0x989e71734f8119103586dc9a3c5f5033ddc815a21018b34c1f876cdfc112efa868d5751bf6419323e4e59fa6a03ece1c", "0xa2da00e05036c884369e04cf55f3de7d659cd5fa3f849092b2519dd263694efe0f051953d9d94b7e121f0aee8b6174d7", "0x968f3c029f57ee31c4e1adea89a7f92e28483af9a74f30fbdb995dc2d40e8e657dff8f8d340d4a92bf65f54440f2859f", "0x932778df6f60ac1639c1453ef0cbd2bf67592759dcccb3e96dcc743ff01679e4c7dd0ef2b0833dda548d32cb4eba49e2", "0xa805a31139f8e0d6dae1ac87d454b23a3dc9fc653d4ca18d4f8ebab30fc189c16e73981c2cb7dd6f8c30454a5208109d", "0xa9ba0991296caa2aaa4a1ceacfb205544c2a2ec97088eace1d84ee5e2767656a172f75d2f0c4e16a3640a0e0dec316e0", "0xb1e49055c968dced47ec95ae934cf45023836d180702e20e2df57e0f62fb85d7ac60d657ba3ae13b8560b67210449459", "0xa94e1da570a38809c71e37571066acabff7bf5632737c9ab6e4a32856924bf6211139ab3cedbf083850ff2d0e0c0fcfc", "0x88ef1bb322000c5a5515b310c838c9af4c1cdbb32eab1c83ac3b2283191cd40e9573747d663763a28dad0d64adc13840", "0xa987ce205f923100df0fbd5a85f22c9b99b9b9cbe6ddfa8dfda1b8fe95b4f71ff01d6c5b64ca02eb24edb2b255a14ef0", "0x84fe8221a9e95d9178359918a108de4763ebfa7a6487facb9c963406882a08a9a93f492f8e77cf9e7ea41ae079c45993", "0xaa1cf3dc7c5dcfa15bbbc811a4bb6dbac4fba4f97fb1ed344ab60264d7051f6eef19ea9773441d89929ee942ed089319", "0x8f6a7d610d59d9f54689bbe6a41f92d9f6096cde919c1ab94c3c7fcecf0851423bc191e5612349e10f855121c0570f56", "0xb5af1fa7894428a53ea520f260f3dc3726da245026b6d5d240625380bfb9c7c186df0204bb604efac5e613a70af5106e", "0xa5bce6055ff812e72ce105f147147c7d48d7a2313884dd1f488b1240ee320f13e8a33f5441953a8e7a3209f65b673ce1", "0xb9b55b4a1422677d95821e1d042ab81bbf0bf087496504021ec2e17e238c2ca6b44fb3b635a5c9eac0871a724b8d47c3", "0x941c38e533ce4a673a3830845b56786585e5fe49c427f2e5c279fc6db08530c8f91db3e6c7822ec6bb4f956940052d18", "0xa38e191d66c625f975313c7007bbe7431b5a06ed2da1290a7d5d0f2ec73770d476efd07b8e632de64597d47df175cbb0", "0x94ba76b667abf055621db4c4145d18743a368d951565632ed4e743dd50dd3333507c0c34f286a5c5fdbf38191a2255cd", "0xa5ca38c60be5602f2bfa6e00c687ac96ac36d517145018ddbee6f12eb0faa63dd57909b9eeed26085fe5ac44e55d10ab", "0xb00fea3b825e60c1ed1c5deb4b551aa65a340e5af36b17d5262c9cd2c508711e4dc50dc2521a2c16c7c901902266e64a", "0x971b86fc4033485e235ccb0997a236206ba25c6859075edbcdf3c943116a5030b7f75ebca9753d863a522ba21a215a90", "0xb3b31f52370de246ee215400975b674f6da39b2f32514fe6bd54e747752eedca22bb840493b44a67df42a3639c5f901f", "0xaffbbfac9c1ba7cbfa1839d2ae271dd6149869b75790bf103230637da41857fc326ef3552ff31c15bda0694080198143", "0xa95d42aa7ef1962520845aa3688f2752d291926f7b0d73ea2ee24f0612c03b43f2b0fe3c9a9a99620ffc8d487b981bc2", "0x914a266065caf64985e8c5b1cb2e3f4e3fe94d7d085a1881b1fefa435afef4e1b39a98551d096a62e4f5cc1a7f0fdc2e", "0x81a0b4a96e2b75bc1bf2dbd165d58d55cfd259000a35504d1ffb18bc346a3e6f07602c683723864ffb980f840836fd8d", "0x91c1556631cddd4c00b65b67962b39e4a33429029d311c8acf73a18600e362304fb68bccb56fde40f49e95b7829e0b87", "0x8befbacc19e57f7c885d1b7a6028359eb3d80792fe13b92a8400df21ce48deb0bb60f2ddb50e3d74f39f85d7eab23adc", "0x92f9458d674df6e990789690ec9ca73dacb67fc9255b58c417c555a8cc1208ace56e8e538f86ba0f3615573a0fbac00d", "0xb4b1b3062512d6ae7417850c08c13f707d5838e43d48eb98dd4621baf62eee9e82348f80fe9b888a12874bfa538771f8", "0xa13c4a3ac642ede37d9c883f5319e748d2b938f708c9d779714108a449b343f7b71a6e3ef4080fee125b416762920273", "0xaf44983d5fc8cceee0551ef934e6e653f2d3efa385e5c8a27a272463a6f333e290378cc307c2b664eb923c78994e706e", "0xa389fd6c59fe2b4031cc244e22d3991e541bd203dd5b5e73a6159e72df1ab41d49994961500dcde7989e945213184778", "0x8d2141e4a17836c548de9598d7b298b03f0e6c73b7364979a411c464e0628e21cff6ac3d6decdba5d1c4909eff479761", "0x980b22ef53b7bdf188a3f14bc51b0dbfdf9c758826daa3cbc1e3986022406a8aa9a6a79e400567120b88c67faa35ce5f", "0xa28882f0a055f96df3711de5d0aa69473e71245f4f3e9aa944e9d1fb166e02caa50832e46da6d3a03b4801735fd01b29", "0x8db106a37d7b88f5d995c126abb563934dd8de516af48e85695d02b1aea07f79217e3cdd03c6f5ca57421830186c772b", "0xb5a7e50da0559a675c472f7dfaee456caab6695ab7870541b2be8c2b118c63752427184aad81f0e1afc61aef1f28c46f", "0x9962118780e20fe291d10b64f28d09442a8e1b5cffd0f3dd68d980d0614050a626c616b44e9807fbee7accecae00686a", "0xb38ddf33745e8d2ad6a991aefaf656a33c5f8cbe5d5b6b6fd03bd962153d8fd0e01b5f8f96d80ae53ab28d593ab1d4e7", "0x857dc12c0544ff2c0c703761d901aba636415dee45618aba2e3454ff9cbc634a85c8b05565e88520ff9be2d097c8b2b1", "0xa80d465c3f8cc63af6d74a6a5086b626c1cb4a8c0fee425964c3bd203d9d7094e299f81ce96d58afc20c8c9a029d9dae", "0x89e1c8fbde8563763be483123a3ed702efac189c6d8ab4d16c85e74bbaf856048cc42d5d6e138633a38572ba5ec3f594", "0x893a594cf495535f6d216508f8d03c317dcf03446668cba688da90f52d0111ac83d76ad09bf5ea47056846585ee5c791", "0xaadbd8be0ae452f7f9450c7d2957598a20cbf10139a4023a78b4438172d62b18b0de39754dd2f8862dbd50a3a0815e53", "0xae7d39670ecca3eb6db2095da2517a581b0e8853bdfef619b1fad9aacd443e7e6a40f18209fadd44038a55085c5fe8b2", "0x866ef241520eacb6331593cfcb206f7409d2f33d04542e6e52cba5447934e02d44c471f6c9a45963f9307e9809ab91d9", "0xb1a09911ad3864678f7be79a9c3c3eb5c84a0a45f8dcb52c67148f43439aeaaa9fd3ed3471276b7e588b49d6ebe3033a", "0xadd07b7f0dbb34049cd8feeb3c18da5944bf706871cfd9f14ff72f6c59ad217ebb1f0258b13b167851929387e4e34cfe", "0xae048892d5c328eefbdd4fba67d95901e3c14d974bfc0a1fc68155ca9f0d59e61d7ba17c6c9948b120cf35fd26e6fee9", "0x9185b4f3b7da0ddb4e0d0f09b8a9e0d6943a4611e43f13c3e2a767ed8592d31e0ba3ebe1914026a3627680274291f6e5", "0xa9c022d4e37b0802284ce3b7ee9258628ab4044f0db4de53d1c3efba9de19d15d65cc5e608dbe149c21c2af47d0b07b5", "0xb24dbd5852f8f24921a4e27013b6c3fa8885b973266cb839b9c388efad95821d5d746348179dcc07542bd0d0aefad1ce", "0xb5fb4f279300876a539a27a441348764908bc0051ebd66dc51739807305e73db3d2f6f0f294ffb91b508ab150eaf8527", "0xace50841e718265b290c3483ed4b0fdd1175338c5f1f7530ae9a0e75d5f80216f4de37536adcbc8d8c95982e88808cd0", "0xb19cadcde0f63bd1a9c24bd9c2806f53c14c0b9735bf351601498408ba503ddbd2037c891041cbba47f58b8c483f3b21", "0xb6061e63558d312eb891b97b39aa552fa218568d79ee26fe6dd5b864aea9e3216d8f2e2f3b093503be274766dac41426", "0x89730fdb2876ab6f0fe780d695f6e12090259027e789b819956d786e977518057e5d1d7f5ab24a3ae3d5d4c97773bd2b", "0xb6fa841e81f9f2cad0163a02a63ae96dc341f7ae803b616efc6e1da2fbea551c1b96b11ad02c4afbdf6d0cc9f23da172", "0x8fb66187182629c861ddb6896d7ed3caf2ad050c3dba8ab8eb0d7a2c924c3d44c48d1a148f9e33fb1f061b86972f8d21", "0x86022ac339c1f84a7fa9e05358c1a5b316b4fc0b83dbe9c8c7225dc514f709d66490b539359b084ce776e301024345fa", "0xb50b9c321468da950f01480bb62b6edafd42f83c0001d6e97f2bd523a1c49a0e8574fb66380ea28d23a7c4d54784f9f0", "0xa31c05f7032f30d1dac06678be64d0250a071fd655e557400e4a7f4c152be4d5c7aa32529baf3e5be7c4bd49820054f6", "0xb95ac0848cd322684772119f5b682d90a66bbf9dac411d9d86d2c34844bbd944dbaf8e47aa41380455abd51687931a78", "0xae4a6a5ce9553b65a05f7935e61e496a4a0f6fd8203367a2c627394c9ce1e280750297b74cdc48fd1d9a31e93f97bef4", "0xa22daf35f6e9b05e52e0b07f7bd1dbbebd2c263033fb0e1b2c804e2d964e2f11bc0ece6aca6af079dd3a9939c9c80674", "0x902150e0cb1f16b9b59690db35281e28998ce275acb313900da8b2d8dfd29fa1795f8ca3ff820c31d0697de29df347c1", "0xb17b5104a5dc665cdd7d47e476153d715eb78c6e5199303e4b5445c21a7fa7cf85fe7cfd08d7570f4e84e579b005428c", "0xa03f49b81c15433f121680aa02d734bb9e363af2156654a62bcb5b2ba2218398ccb0ff61104ea5d7df5b16ea18623b1e", "0x802101abd5d3c88876e75a27ffc2f9ddcce75e6b24f23dba03e5201281a7bd5cc7530b6a003be92d225093ca17d3c3bb", "0xa4d183f63c1b4521a6b52226fc19106158fc8ea402461a5cccdaa35fee93669df6a8661f45c1750cd01308149b7bf08e", "0x8d17c22e0c8403b69736364d460b3014775c591032604413d20a5096a94d4030d7c50b9fe3240e31d0311efcf9816a47", "0x947225acfcce5992eab96276f668c3cbe5f298b90a59f2bb213be9997d8850919e8f496f182689b5cbd54084a7332482", "0x8df6f4ed216fc8d1905e06163ba1c90d336ab991a18564b0169623eb39b84e627fa267397da15d3ed754d1f3423bff07", "0x83480007a88f1a36dea464c32b849a3a999316044f12281e2e1c25f07d495f9b1710b4ba0d88e9560e72433addd50bc2", "0xb3019d6e591cf5b33eb972e49e06c6d0a82a73a75d78d383dd6f6a4269838289e6e07c245f54fed67f5c9bb0fd5e1c5f", "0x92e8ce05e94927a9fb02debadb99cf30a26172b2705003a2c0c47b3d8002bf1060edb0f6a5750aad827c98a656b19199", "0xac2aff801448dbbfc13cca7d603fd9c69e82100d997faf11f465323b97255504f10c0c77401e4d1890339d8b224f5803", "0xb0453d9903d08f508ee27e577445dc098baed6cde0ac984b42e0f0efed62760bd58d5816cf1e109d204607b7b175e30c", "0xae68dc4ba5067e825d46d2c7c67f1009ceb49d68e8d3e4c57f4bcd299eb2de3575d42ea45e8722f8f28497a6e14a1cfe", "0xb22486c2f5b51d72335ce819bbafb7fa25eb1c28a378a658f13f9fc79cd20083a7e573248d911231b45a5cf23b561ca7", "0x89d1201d1dbd6921867341471488b4d2fd0fc773ae1d4d074c78ae2eb779a59b64c00452c2a0255826fca6b3d03be2b1", "0xa2998977c91c7a53dc6104f5bc0a5b675e5350f835e2f0af69825db8af4aeb68435bdbcc795f3dd1f55e1dd50bc0507f", "0xb0be4937a925b3c05056ed621910d535ccabf5ab99fd3b9335080b0e51d9607d0fd36cb5781ff340018f6acfca4a9736", "0xaea145a0f6e0ba9df8e52e84bb9c9de2c2dc822f70d2724029b153eb68ee9c17de7d35063dcd6a39c37c59fdd12138f7", "0x91cb4545d7165ee8ffbc74c874baceca11fdebbc7387908d1a25877ca3c57f2c5def424dab24148826832f1e880bede0", "0xb3b579cb77573f19c571ad5eeeb21f65548d7dff9d298b8d7418c11f3e8cd3727c5b467f013cb87d6861cfaceee0d2e3", "0xb98a1eeec2b19fecc8378c876d73645aa52fb99e4819903735b2c7a885b242787a30d1269a04bfb8573d72d9bbc5f0f0", "0x940c1f01ed362bd588b950c27f8cc1d52276c71bb153d47f07ec85b038c11d9a8424b7904f424423e714454d5e80d1cd", "0xaa343a8ecf09ce11599b8cf22f7279cf80f06dbf9f6d62cb05308dbbb39c46fd0a4a1240b032665fbb488a767379b91b", "0x87c3ac72084aca5974599d3232e11d416348719e08443acaba2b328923af945031f86432e170dcdd103774ec92e988c9", "0x91d6486eb5e61d2b9a9e742c20ec974a47627c6096b3da56209c2b4e4757f007e793ebb63b2b246857c9839b64dc0233", "0xaebcd3257d295747dd6fc4ff910d839dd80c51c173ae59b8b2ec937747c2072fa85e3017f9060aa509af88dfc7529481", "0xb3075ba6668ca04eff19efbfa3356b92f0ab12632dcda99cf8c655f35b7928c304218e0f9799d68ef9f809a1492ff7db", "0x93ba7468bb325639ec2abd4d55179c69fd04eaaf39fc5340709227bbaa4ad0a54ea8b480a1a3c8d44684e3be0f8d1980", "0xa6aef86c8c0d92839f38544d91b767c582568b391071228ff5a5a6b859c87bf4f81a7d926094a4ada1993ddbd677a920", "0x91dcd6d14207aa569194aa224d1e5037b999b69ade52843315ca61ba26abe9a76412c9e88259bc5cf5d7b95b97d9c3bc", "0xb3b483d31c88f78d49bd065893bc1e3d2aa637e27dedb46d9a7d60be7660ce7a10aaaa7deead362284a52e6d14021178", "0x8e5730070acf8371461ef301cc4523e8e672aa0e3d945d438a0e0aa6bdf8cb9c685dcf38df429037b0c8aff3955c6f5b", "0xb8c6d769890a8ee18dc4f9e917993315877c97549549b34785a92543cbeec96a08ae3a28d6e809c4aacd69de356c0012", "0x95ca86cd384eaceaa7c077c5615736ca31f36824bd6451a16142a1edc129fa42b50724aeed7c738f08d7b157f78b569e", "0x94df609c6d71e8eee7ab74226e371ccc77e01738fe0ef1a6424435b4570fe1e5d15797b66ed0f64eb88d4a3a37631f0e", "0x89057b9783212add6a0690d6bb99097b182738deff2bd9e147d7fd7d6c8eacb4c219923633e6309ad993c24572289901", "0x83a0f9f5f265c5a0e54defa87128240235e24498f20965009fef664f505a360b6fb4020f2742565dfc7746eb185bcec0", "0x91170da5306128931349bc3ed50d7df0e48a68b8cc8420975170723ac79d8773e4fa13c5f14dc6e3fafcad78379050b1", "0xb7178484d1b55f7e56a4cc250b6b2ec6040437d96bdfddfa7b35ed27435860f3855c2eb86c636f2911b012eb83b00db8", "0xac0b00c4322d1e4208e09cd977b4e54d221133ff09551f75b32b0b55d0e2be80941dda26257b0e288c162e63c7e9cf68", "0x9690ed9e7e53ed37ff362930e4096b878b12234c332fd19d5d064824084245952eda9f979e0098110d6963e468cf513e", "0xb6fa547bb0bb83e5c5be0ed462a8783fba119041c136a250045c09d0d2af330c604331e7de960df976ff76d67f8000cd", "0x814603907c21463bcf4e59cfb43066dfe1a50344ae04ef03c87c0f61b30836c3f4dea0851d6fa358c620045b7f9214c8", "0x9495639e3939fad2a3df00a88603a5a180f3c3a0fe4d424c35060e2043e0921788003689887b1ed5be424d9a89bb18bb", "0xaba4c02d8d57f2c92d5bc765885849e9ff8393d6554f5e5f3e907e5bfac041193a0d8716d7861104a4295d5a03c36b03", "0x8ead0b56c1ca49723f94a998ba113b9058059321da72d9e395a667e6a63d5a9dac0f5717cec343f021695e8ced1f72af", "0xb43037f7e3852c34ed918c5854cd74e9d5799eeddfe457d4f93bb494801a064735e326a76e1f5e50a339844a2f4a8ec9", "0x99db8422bb7302199eb0ff3c3d08821f8c32f53a600c5b6fb43e41205d96adae72be5b460773d1280ad1acb806af9be8", "0x8a9be08eae0086c0f020838925984df345c5512ff32e37120b644512b1d9d4fecf0fd30639ca90fc6cf334a86770d536", "0x81b43614f1c28aa3713a309a88a782fb2bdfc4261dd52ddc204687791a40cf5fd6a263a8179388596582cccf0162efc2", "0xa9f3a8b76912deb61d966c75daf5ddb868702ebec91bd4033471c8e533183df548742a81a2671de5be63a502d827437d", "0x902e2415077f063e638207dc7e14109652e42ab47caccd6204e2870115791c9defac5425fd360b37ac0f7bd8fe7011f8", "0xaa18e4fdc1381b59c18503ae6f6f2d6943445bd00dd7d4a2ad7e5adad7027f2263832690be30d456e6d772ad76f22350", "0xa348b40ba3ba7d81c5d4631f038186ebd5e5f314f1ea737259151b07c3cc8cf0c6ed4201e71bcc1c22fefda81a20cde6", "0xaa1306f7ac1acbfc47dc6f7a0cb6d03786cec8c8dc8060388ccda777bca24bdc634d03e53512c23dba79709ff64f8620", "0x818ccfe46e700567b7f3eb400e5a35f6a5e39b3db3aa8bc07f58ace35d9ae5a242faf8dbccd08d9a9175bbce15612155", "0xb7e3da2282b65dc8333592bb345a473f03bd6df69170055fec60222de9897184536bf22b9388b08160321144d0940279", "0xa4d976be0f0568f4e57de1460a1729129252b44c552a69fceec44e5b97c96c711763360d11f9e5bf6d86b4976bf40d69", "0x85d185f0397c24c2b875b09b6328a23b87982b84ee880f2677a22ff4c9a1ba9f0fea000bb3f7f66375a00d98ebafce17", "0xb4ccbb8c3a2606bd9b87ce022704663af71d418351575f3b350d294f4efc68c26f9a2ce49ff81e6ff29c3b63d746294e", "0x93ffd3265fddb63724dfde261d1f9e22f15ecf39df28e4d89e9fea03221e8e88b5dd9b77628bacaa783c6f91802d47cc", "0xb1fd0f8d7a01378e693da98d03a2d2fda6b099d03454b6f2b1fa6472ff6bb092751ce6290059826b74ac0361eab00e1e", "0xa89f440c71c561641589796994dd2769616b9088766e983c873fae0716b95c386c8483ab8a4f367b6a68b72b7456dd32", "0xaf4fe92b01d42d03dd5d1e7fa55e96d4bbcb7bf7d4c8c197acd16b3e0f3455807199f683dcd263d74547ef9c244b35cc", "0xa8227f6e0a344dfe76bfbe7a1861be32c4f4bed587ccce09f9ce2cf481b2dda8ae4f566154bc663d15f962f2d41761bd", "0xa7b361663f7495939ed7f518ba45ea9ff576c4e628995b7aea026480c17a71d63fc2c922319f0502eb7ef8f14a406882", "0x8ddcf382a9f39f75777160967c07012cfa89e67b19714a7191f0c68eaf263935e5504e1104aaabd0899348c972a8d3c6", "0x98c95b9f6f5c91f805fb185eedd06c6fc4457d37dd248d0be45a6a168a70031715165ea20606245cbdf8815dc0ac697f", "0x805b44f96e001e5909834f70c09be3efcd3b43632bcac5b6b66b6d227a03a758e4b1768ce2a723045681a1d34562aaeb", "0xb0e81b07cdc45b3dca60882676d9badb99f25c461b7efe56e3043b80100bb62d29e1873ae25eb83087273160ece72a55", "0xb0c53f0abe78ee86c7b78c82ae1f7c070bb0b9c45c563a8b3baa2c515d482d7507bb80771e60b38ac13f78b8af92b4a9", "0xa7838ef6696a9e4d2e5dfd581f6c8d6a700467e8fd4e85adabb5f7a56f514785dd4ab64f6f1b48366f7d94728359441b", "0x88c76f7700a1d23c30366a1d8612a796da57b2500f97f88fdf2d76b045a9d24e7426a8ffa2f4e86d3046937a841dad58", "0xad8964baf98c1f02e088d1d9fcb3af6b1dfa44cdfe0ed2eae684e7187c33d3a3c28c38e8f4e015f9c04d451ed6f85ff6", "0x90e9d00a098317ececaa9574da91fc149eda5b772dedb3e5a39636da6603aa007804fa86358550cfeff9be5a2cb7845e", "0xa56ff4ddd73d9a6f5ab23bb77efa25977917df63571b269f6a999e1ad6681a88387fcc4ca3b26d57badf91b236503a29", "0x97ad839a6302c410a47e245df84c01fb9c4dfef86751af3f9340e86ff8fc3cd52fa5ff0b9a0bd1d9f453e02ca80658a6", "0xa4c8c44cbffa804129e123474854645107d1f0f463c45c30fd168848ebea94880f7c0c5a45183e9eb837f346270bdb35", "0xa72e53d0a1586d736e86427a93569f52edd2f42b01e78aee7e1961c2b63522423877ae3ac1227a2cf1e69f8e1ff15bc3", "0x8559f88a7ef13b4f09ac82ae458bbae6ab25671cfbf52dae7eac7280d6565dd3f0c3286aec1a56a8a16dc3b61d78ce47", "0x8221503f4cdbed550876c5dc118a3f2f17800c04e8be000266633c83777b039a432d576f3a36c8a01e8fd18289ebc10b", "0x99bfbe5f3e46d4d898a578ba86ed26de7ed23914bd3bcdf3c791c0bcd49398a52419077354a5ab75cea63b6c871c6e96", "0xaa134416d8ff46f2acd866c1074af67566cfcf4e8be8d97329dfa0f603e1ff208488831ce5948ac8d75bfcba058ddcaa", "0xb02609d65ebfe1fe8e52f21224a022ea4b5ea8c1bd6e7b9792eed8975fc387cdf9e3b419b8dd5bcce80703ab3a12a45f", "0xa4f14798508698fa3852e5cac42a9db9797ecee7672a54988aa74037d334819aa7b2ac7b14efea6b81c509134a6b7ad2", "0x884f01afecbcb987cb3e7c489c43155c416ed41340f61ecb651d8cba884fb9274f6d9e7e4a46dd220253ae561614e44c", "0xa05523c9e71dce1fe5307cc71bd721feb3e1a0f57a7d17c7d1c9fb080d44527b7dbaa1f817b1af1c0b4322e37bc4bb1e", "0x8560aec176a4242b39f39433dd5a02d554248c9e49d3179530815f5031fee78ba9c71a35ceeb2b9d1f04c3617c13d8f0", "0x996aefd402748d8472477cae76d5a2b92e3f092fc834d5222ae50194dd884c9fb8b6ed8e5ccf8f6ed483ddbb4e80c747", "0x8fd09900320000cbabc40e16893e2fcf08815d288ec19345ad7b6bb22f7d78a52b6575a3ca1ca2f8bc252d2eafc928ec", "0x939e51f73022bc5dc6862a0adf8fb8a3246b7bfb9943cbb4b27c73743926cc20f615a036c7e5b90c80840e7f1bfee0e7", "0xa0a6258700cadbb9e241f50766573bf9bdb7ad380b1079dc3afb4054363d838e177b869cad000314186936e40359b1f2", "0x972699a4131c8ed27a2d0e2104d54a65a7ff1c450ad9da3a325c662ab26869c21b0a84d0700b98c8b5f6ce3b746873d7", "0xa454c7fe870cb8aa6491eafbfb5f7872d6e696033f92e4991d057b59d70671f2acdabef533e229878b60c7fff8f748b1", "0xa167969477214201f09c79027b10221e4707662e0c0fde81a0f628249f2f8a859ce3d30a7dcc03b8ecca8f7828ad85c7", "0x8ff6b7265175beb8a63e1dbf18c9153fb2578c207c781282374f51b40d57a84fd2ef2ea2b9c6df4a54646788a62fd17f", "0xa3d7ebeccde69d73d8b3e76af0da1a30884bb59729503ff0fb0c3bccf9221651b974a6e72ea33b7956fc3ae758226495", "0xb71ef144c9a98ce5935620cb86c1590bd4f48e5a2815d25c0cdb008fde628cf628c31450d3d4f67abbfeb16178a74cfd", "0xb5e0a16d115134f4e2503990e3f2035ed66b9ccf767063fe6747870d97d73b10bc76ed668550cb82eedc9a2ca6f75524", "0xb30ffaaf94ee8cbc42aa2c413175b68afdb207dbf351fb20be3852cb7961b635c22838da97eaf43b103aff37e9e725cc", "0x98aa7d52284f6c1f22e272fbddd8c8698cf8f5fbb702d5de96452141fafb559622815981e50b87a72c2b1190f59a7deb", "0x81fbacda3905cfaf7780bb4850730c44166ed26a7c8d07197a5d4dcd969c09e94a0461638431476c16397dd7bdc449f9", "0x95e47021c1726eac2e5853f570d6225332c6e48e04c9738690d53e07c6b979283ebae31e2af1fc9c9b3e59f87e5195b1", "0xac024a661ba568426bb8fce21780406537f518075c066276197300841e811860696f7588188bc01d90bace7bc73d56e3", "0xa4ebcaf668a888dd404988ab978594dee193dad2d0aec5cdc0ccaf4ec9a7a8228aa663db1da8ddc52ec8472178e40c32", "0xa20421b8eaf2199d93b083f2aff37fb662670bd18689d046ae976d1db1fedd2c2ff897985ecc6277b396db7da68bcb27", "0x8bc33d4b40197fd4d49d1de47489d10b90d9b346828f53a82256f3e9212b0cbc6930b895e879da9cec9fedf026aadb3e", "0xaaafdd1bec8b757f55a0433eddc0a39f818591954fd4e982003437fcceb317423ad7ee74dbf17a2960380e7067a6b4e2", "0xaad34277ebaed81a6ec154d16736866f95832803af28aa5625bf0461a71d02b1faba02d9d9e002be51c8356425a56867", "0x976e9c8b150d08706079945bd0e84ab09a648ecc6f64ded9eb5329e57213149ae409ae93e8fbd8eda5b5c69f5212b883", "0x8097fae1653247d2aed4111533bc378171d6b2c6d09cbc7baa9b52f188d150d645941f46d19f7f5e27b7f073c1ebd079", "0x83905f93b250d3184eaba8ea7d727c4464b6bdb027e5cbe4f597d8b9dc741dcbea709630bd4fd59ce24023bec32fc0f3", "0x8095030b7045cff28f34271386e4752f9a9a0312f8df75de4f424366d78534be2b8e1720a19cb1f9a2d21105d790a225", "0xa7b7b73a6ae2ed1009c49960374b0790f93c74ee03b917642f33420498c188a169724945a975e5adec0a1e83e07fb1b2", "0x856a41c54df393b6660b7f6354572a4e71c8bfca9cabaffb3d4ef2632c015e7ee2bc10056f3eccb3dbed1ad17d939178", "0xa8f7a55cf04b38cd4e330394ee6589da3a07dc9673f74804fdf67b364e0b233f14aec42e783200a2e4666f7c5ff62490", "0x82c529f4e543c6bca60016dc93232c115b359eaee2798a9cf669a654b800aafe6ab4ba58ea8b9cdda2b371c8d62fa845", "0x8caab020c1baddce77a6794113ef1dfeafc5f5000f48e97f4351b588bf02f1f208101745463c480d37f588d5887e6d8c", "0x8fa91b3cc400f48b77b6fd77f3b3fbfb3f10cdff408e1fd22d38f77e087b7683adad258804409ba099f1235b4b4d6fea", "0x8aa02787663d6be9a35677d9d8188b725d5fcd770e61b11b64e3def8808ea5c71c0a9afd7f6630c48634546088fcd8e2", "0xb5635b7b972e195cab878b97dea62237c7f77eb57298538582a330b1082f6207a359f2923864630136d8b1f27c41b9aa", "0x8257bb14583551a65975946980c714ecd6e5b629672bb950b9caacd886fbd22704bc9e3ba7d30778adab65dc74f0203a", "0xab5fe1cd12634bfa4e5c60d946e2005cbd38f1063ec9a5668994a2463c02449a0a185ef331bd86b68b6e23a8780cb3ba", "0xa7d3487da56cda93570cc70215d438204f6a2709bfb5fda6c5df1e77e2efc80f4235c787e57fbf2c74aaff8cbb510a14", "0xb61cff7b4c49d010e133319fb828eb900f8a7e55114fc86b39c261a339c74f630e1a7d7e1350244ada566a0ff3d46c4b", "0x8d4d1d55d321d278db7a85522ccceca09510374ca81d4d73e3bb5249ace7674b73900c35a531ec4fa6448fabf7ad00dc", "0x966492248aee24f0f56c8cfca3c8ec6ba3b19abb69ae642041d4c3be8523d22c65c4dafcab4c58989ccc4e0bd2f77919", "0xb20c320a90cb220b86e1af651cdc1e21315cd215da69f6787e28157172f93fc8285dcd59b039c626ed8ca4633cba1a47", "0xaae9e6b22f018ceb5c0950210bb8182cb8cb61014b7e14581a09d36ebd1bbfebdb2b82afb7fdb0cf75e58a293d9c456d", "0x875547fb67951ad37b02466b79f0c9b985ccbc500cfb431b17823457dc79fb9597ec42cd9f198e15523fcd88652e63a4", "0x92afce49773cb2e20fb21e4f86f18e0959ebb9c33361547ddb30454ee8e36b1e234019cbdca0e964cb292f7f77df6b90", "0x8af85343dfe1821464c76ba11c216cbef697b5afc69c4d821342e55afdac047081ec2e3f7b09fc14b518d9a23b78c003", "0xb7de4a1648fd63f3a918096ea669502af5357438e69dac77cb8102b6e6c15c76e033cfaa80dafc806e535ede5c1a20aa", "0xac80e9b545e8bd762951d96c9ce87f629d01ffcde07efc2ef7879ca011f1d0d8a745abf26c9d452541008871304fac00", "0xa4cf0f7ed724e481368016c38ea5816698a5f68eb21af4d3c422d2ba55f96a33e427c2aa40de1b56a7cfac7f7cf43ab0", "0x899b0a678bb2db2cae1b44e75a661284844ebcdd87abf308fedeb2e4dbe5c5920c07db4db7284a7af806a2382e8b111a", "0xaf0588a2a4afce2b1b13c1230816f59e8264177e774e4a341b289a101dcf6af813638fed14fb4d09cb45f35d5d032609", "0xa4b8df79e2be76e9f5fc5845f06fe745a724cf37c82fcdb72719b77bdebea3c0e763f37909373e3a94480cc5e875cba0", "0x83e42c46d88930c8f386b19fd999288f142d325e2ebc86a74907d6d77112cb0d449bc511c95422cc810574031a8cbba9", "0xb5e39534070de1e5f6e27efbdd3dc917d966c2a9b8cf2d893f964256e95e954330f2442027dc148c776d63a95bcde955", "0x958607569dc28c075e658cd4ae3927055c6bc456eef6212a6fea8205e48ed8777a8064f584cda38fe5639c371e2e7fba", "0x812adf409fa63575113662966f5078a903212ffb65c9b0bbe62da0f13a133443a7062cb8fd70f5e5dd5559a32c26d2c8", "0xa679f673e5ce6a3cce7fa31f22ee3785e96bcb55e5a776e2dd3467bef7440e3555d1a9b87cb215e86ee9ed13a090344b", "0xafedbb34508b159eb25eb2248d7fe328f86ef8c7d84c62d5b5607d74aae27cc2cc45ee148eb22153b09898a835c58df4", "0xb75505d4f6b67d31e665cfaf5e4acdb5838ae069166b7fbcd48937c0608a59e40a25302fcc1873d2e81c1782808c70f0", "0xb62515d539ec21a155d94fc00ea3c6b7e5f6636937bce18ed5b618c12257fb82571886287fd5d1da495296c663ebc512", "0xab8e1a9446bbdd588d1690243b1549d230e6149c28f59662b66a8391a138d37ab594df38e7720fae53217e5c3573b5be", "0xb31e8abf4212e03c3287bb2c0a153065a7290a16764a0bac8f112a72e632185a654bb4e88fdd6053e6c7515d9719fadb", "0xb55165477fe15b6abd2d0f4fddaa9c411710dcc4dd712daba3d30e303c9a3ee5415c256f9dc917ecf18c725b4dbab059", "0xa0939d4f57cacaae549b78e87cc234de4ff6a35dc0d9cd5d7410abc30ebcd34c135e008651c756e5a9d2ca79c40ef42b", "0x8cf10e50769f3443340844aad4d56ec790850fed5a41fcbd739abac4c3015f0a085a038fbe7fae9f5ad899cce5069f6b", "0x924055e804d82a99ea4bb160041ea4dc14b568abf379010bc1922fde5d664718c31d103b8b807e3a1ae809390e708c73", "0x8ec0f9d26f71b0f2e60a179e4fd1778452e2ffb129d50815e5d7c7cb9415fa69ae5890578086e8ef6bfde35ad2a74661", "0x98c7f12b15ec4426b59f737f73bf5faea4572340f4550b7590dfb7f7ffedb2372e3e555977c63946d579544c53210ad0", "0x8a935f7a955c78f69d66f18eee0092e5e833fa621781c9581058e219af4d7ceee48b84e472e159dda6199715fb2f9acf", "0xb78d4219f95a2dbfaa7d0c8a610c57c358754f4f43c2af312ab0fe8f10a5f0177e475332fb8fd23604e474fc2abeb051", "0x8d086a14803392b7318c28f1039a17e3cfdcece8abcaca3657ec3d0ac330842098a85c0212f889fabb296dfb133ce9aa", "0xa53249f417aac82f2c2a50c244ce21d3e08a5e5a8bd33bec2a5ab0d6cd17793e34a17edfa3690899244ce201e2fb9986", "0x8619b0264f9182867a1425be514dc4f1ababc1093138a728a28bd7e4ecc99b9faaff68c23792264bc6e4dce5f52a5c52", "0x8c171edbbbde551ec19e31b2091eb6956107dd9b1f853e1df23bff3c10a3469ac77a58335eee2b79112502e8e163f3de", "0xa9d19ec40f0ca07c238e9337c6d6a319190bdba2db76fb63902f3fb459aeeb50a1ac30db5b25ee1b4201f3ca7164a7f4", "0xb9c6ec14b1581a03520b8d2c1fbbc31fb8ceaef2c0f1a0d0080b6b96e18442f1734bea7ef7b635d787c691de4765d469", "0x8cb437beb4cfa013096f40ccc169a713dc17afee6daa229a398e45fd5c0645a9ad2795c3f0cd439531a7151945d7064d", "0xa6e8740cc509126e146775157c2eb278003e5bb6c48465c160ed27888ca803fa12eee1f6a8dd7f444f571664ed87fdc1", "0xb75c1fecc85b2732e96b3f23aefb491dbd0206a21d682aee0225838dc057d7ed3b576176353e8e90ae55663f79e986e4", "0xad8d249b0aea9597b08358bce6c77c1fd552ef3fbc197d6a1cfe44e5e6f89b628b12a6fb04d5dcfcbacc51f46e4ae7bb", "0xb998b2269932cbd58d04b8e898d373ac4bb1a62e8567484f4f83e224061bc0f212459f1daae95abdbc63816ae6486a55", "0x827988ef6c1101cddc96b98f4a30365ff08eea2471dd949d2c0a9b35c3bbfa8c07054ad1f4c88c8fbf829b20bb5a9a4f", "0x8692e638dd60babf7d9f2f2d2ce58e0ac689e1326d88311416357298c6a2bffbfebf55d5253563e7b3fbbf5072264146", "0xa685d75b91aea04dbc14ab3c1b1588e6de96dae414c8e37b8388766029631b28dd860688079b12d09cd27f2c5af11adf", "0xb57eced93eec3371c56679c259b34ac0992286be4f4ff9489d81cf9712403509932e47404ddd86f89d7c1c3b6391b28c", "0xa1c8b4e42ebcbd8927669a97f1b72e236fb19249325659e72be7ddaaa1d9e81ca2abb643295d41a8c04a2c01f9c0efd7", "0x877c33de20d4ed31674a671ba3e8f01a316581e32503136a70c9c15bf0b7cb7b1cba6cd4eb641fad165fb3c3c6c235fd", "0xa2a469d84ec478da40838f775d11ad38f6596eb41caa139cc190d6a10b5108c09febae34ffdafac92271d2e73c143693", "0x972f817caedb254055d52e963ed28c206848b6c4cfdb69dbc961c891f8458eaf582a6d4403ce1177d87bc2ea410ef60a", "0xaccbd739e138007422f28536381decc54bb6bd71d93edf3890e54f9ef339f83d2821697d1a4ac1f5a98175f9a9ecb9b5", "0x8940f8772e05389f823b62b3adc3ed541f91647f0318d7a0d3f293aeeb421013de0d0a3664ea53dd24e5fbe02d7efef6", "0x8ecce20f3ef6212edef07ec4d6183fda8e0e8cad2c6ccd0b325e75c425ee1faba00b5c26b4d95204238931598d78f49d", "0x97cc72c36335bd008afbed34a3b0c7225933faba87f7916d0a6d2161e6f82e0cdcda7959573a366f638ca75d30e9dab1", "0x9105f5de8699b5bdb6bd3bb6cc1992d1eac23929c29837985f83b22efdda92af64d9c574aa9640475087201bbbe5fd73", "0x8ffb33c4f6d05c413b9647eb6933526a350ed2e4278ca2ecc06b0e8026d8dbe829c476a40e45a6df63a633090a3f82ef", "0x8bfc6421fdc9c2d2aaa68d2a69b1a2728c25b84944cc3e6a57ff0c94bfd210d1cbf4ff3f06702d2a8257024d8be7de63", "0xa80e1dc1dddfb41a70220939b96dc6935e00b32fb8be5dff4eed1f1c650002ff95e4af481c43292e3827363b7ec4768a", "0x96f714ebd54617198bd636ba7f7a7f8995a61db20962f2165078d9ed8ee764d5946ef3cbdc7ebf8435bb8d5dd4c1deac", "0x8cdb0890e33144d66391d2ae73f5c71f5a861f72bc93bff6cc399fc25dd1f9e17d8772592b44593429718784802ac377", "0x8ccf9a7f80800ee770b92add734ed45a73ecc31e2af0e04364eefc6056a8223834c7c0dc9dfc52495bdec6e74ce69994", "0xaa0875f423bd68b5f10ba978ddb79d3b96ec093bfbac9ff366323193e339ed7c4578760fb60f60e93598bdf1e5cc4995", "0xa9214f523957b59c7a4cb61a40251ad72aba0b57573163b0dc0f33e41d2df483fb9a1b85a5e7c080e9376c866790f8cb", "0xb6224b605028c6673a536cc8ff9aeb94e7a22e686fda82cf16068d326469172f511219b68b2b3affb7933af0c1f80d07", "0xb6d58968d8a017c6a34e24c2c09852f736515a2c50f37232ac6b43a38f8faa7572cc31dade543b594b61b5761c4781d0", "0x8a97cefe5120020c38deeb861d394404e6c993c6cbd5989b6c9ebffe24f46ad11b4ba6348e2991cbf3949c28cfc3c99d", "0x95bf046f8c3a9c0ce2634be4de3713024daec3fc4083e808903b25ce3ac971145af90686b451efcc72f6b22df0216667", "0xa6a4e2f71b8fa28801f553231eff2794c0f10d12e7e414276995e21195abc9c2983a8997e41af41e78d19ff6fbb2680b", "0x8e5e62a7ca9c2f58ebaab63db2ff1fb1ff0877ae94b7f5e2897f273f684ae639dff44cc65718f78a9c894787602ab26a", "0x8542784383eec4f565fcb8b9fc2ad8d7a644267d8d7612a0f476fc8df3aff458897a38003d506d24142ad18f93554f2b", "0xb7db68ba4616ea072b37925ec4fb39096358c2832cc6d35169e032326b2d6614479f765ae98913c267105b84afcb9bf2", "0x8b31dbb9457d23d416c47542c786e07a489af35c4a87dadb8ee91bea5ac4a5315e65625d78dad2cf8f9561af31b45390", "0xa8545a1d91ac17257732033d89e6b7111db8242e9c6ebb0213a88906d5ef407a2c6fdb444e29504b06368b6efb4f4839", "0xb1bd85d29ebb28ccfb05779aad8674906b267c2bf8cdb1f9a0591dd621b53a4ee9f2942687ee3476740c0b4a7621a3ae", "0xa2b54534e152e46c50d91fff03ae9cd019ff7cd9f4168b2fe7ac08ef8c3bbc134cadd3f9d6bd33d20ae476c2a8596c8a", "0xb19b571ff4ae3e9f5d95acda133c455e72c9ea9973cae360732859836c0341c4c29ab039224dc5bc3deb824e031675d8", "0x940b5f80478648bac025a30f3efeb47023ce20ee98be833948a248bca6979f206bb28fc0f17b90acf3bb4abd3d14d731", "0x8f106b40588586ac11629b96d57808ad2808915d89539409c97414aded90b4ff23286a692608230a52bff696055ba5d6", "0xae6bda03aa10da3d2abbc66d764ca6c8d0993e7304a1bdd413eb9622f3ca1913baa6da1e9f4f9e6cf847f14f44d6924d", "0xa18e7796054a340ef826c4d6b5a117b80927afaf2ebd547794c400204ae2caf277692e2eabb55bc2f620763c9e9da66d", "0x8d2d25180dc2c65a4844d3e66819ccfcf48858f0cc89e1c77553b463ec0f7feb9a4002ce26bc618d1142549b9850f232", "0x863f413a394de42cc8166c1c75d513b91d545fff1de6b359037a742c70b008d34bf8e587afa2d62c844d0c6f0ea753e7", "0x83cd0cf62d63475e7fcad18a2e74108499cdbf28af2113cfe005e3b5887794422da450b1944d0a986eb7e1f4c3b18f25", "0xb4f8b350a6d88fea5ab2e44715a292efb12eb52df738c9b2393da3f1ddee68d0a75b476733ccf93642154bceb208f2b8", "0xb3f52aaa4cd4221cb9fc45936cc67fd3864bf6d26bf3dd86aa85aa55ecfc05f5e392ecce5e7cf9406b4b1c4fce0398c8", "0xb33137084422fb643123f40a6df2b498065e65230fc65dc31791c330e898c51c3a65ff738930f32c63d78f3c9315f85b", "0x91452bfa75019363976bb7337fe3a73f1c10f01637428c135536b0cdc7da5ce558dae3dfc792aa55022292600814a8ef", "0xad6ba94c787cd4361ca642c20793ea44f1f127d4de0bb4a77c7fbfebae0fcadbf28e2cb6f0c12c12a07324ec8c19761d", "0x890aa6248b17f1501b0f869c556be7bf2b1d31a176f9978bb97ab7a6bd4138eed32467951c5ef1871944b7f620542f43", "0x82111db2052194ee7dd22ff1eafffac0443cf969d3762cceae046c9a11561c0fdce9c0711f88ac01d1bed165f8a7cee3", "0xb1527b71df2b42b55832f72e772a466e0fa05743aacc7814f4414e4bcc8d42a4010c9e0fd940e6f254cafedff3cd6543", "0x922370fa49903679fc565f09c16a5917f8125e72acfeb060fcdbadbd1644eb9f4016229756019c93c6d609cda5d5d174", "0xaa4c7d98a96cab138d2a53d4aee8ebff6ef903e3b629a92519608d88b3bbd94de5522291a1097e6acf830270e64c8ee1", "0xb3dc21608a389a72d3a752883a382baaafc61ecc44083b832610a237f6a2363f24195acce529eb4aed4ef0e27a12b66e", "0x94619f5de05e07b32291e1d7ab1d8b7337a2235e49d4fb5f3055f090a65e932e829efa95db886b32b153bdd05a53ec8c", "0xade1e92722c2ffa85865d2426fb3d1654a16477d3abf580cfc45ea4b92d5668afc9d09275d3b79283e13e6b39e47424d", "0xb7201589de7bed094911dd62fcd25c459a8e327ac447b69f541cdba30233063e5ddffad0b67e9c3e34adcffedfd0e13d", "0x809d325310f862d6549e7cb40f7e5fc9b7544bd751dd28c4f363c724a0378c0e2adcb5e42ec8f912f5f49f18f3365c07", "0xa79c20aa533de7a5d671c99eb9eb454803ba54dd4f2efa3c8fec1a38f8308e9905c71e9282955225f686146388506ff6", "0xa85eeacb5e8fc9f3ed06a3fe2dc3108ab9f8c5877b148c73cf26e4e979bf5795edbe2e63a8d452565fd1176ed40402b2", "0x97ef55662f8a1ec0842b22ee21391227540adf7708f491436044f3a2eb18c471525e78e1e14fa292507c99d74d7437c6", "0x93110d64ed5886f3d16ce83b11425576a3a7a9bb831cd0de3f9a0b0f2270a730d68136b4ef7ff035ede004358f419b5c", "0xac9ed0a071517f0ae4f61ce95916a90ba9a77a3f84b0ec50ef7298acdcd44d1b94525d191c39d6bd1bb68f4471428760", "0x98abd6a02c7690f5a339adf292b8c9368dfc12e0f8069cf26a5e0ce54b4441638f5c66ea735142f3c28e00a0024267e6", "0xb51efb73ba6d44146f047d69b19c0722227a7748b0e8f644d0fc9551324cf034c041a2378c56ce8b58d06038fb8a78de", "0x8f115af274ef75c1662b588b0896b97d71f8d67986ae846792702c4742ab855952865ce236b27e2321967ce36ff93357", "0xb3c4548f14d58b3ab03c222da09e4381a0afe47a72d18d50a94e0008797f78e39e99990e5b4757be62310d400746e35a", "0xa9b1883bd5f31f909b8b1b6dcb48c1c60ed20aa7374b3ffa7f5b2ed036599b5bef33289d23c80a5e6420d191723b92f7", "0x85d38dffd99487ae5bb41ab4a44d80a46157bbbe8ef9497e68f061721f74e4da513ccc3422936b059575975f6787c936", "0xadf870fcb96e972c033ab7a35d28ae79ee795f82bc49c3bd69138f0e338103118d5529c53f2d72a9c0d947bf7d312af2", "0xab4c7a44e2d9446c6ff303eb49aef0e367a58b22cc3bb27b4e69b55d1d9ee639c9234148d2ee95f9ca8079b1457d5a75", "0xa386420b738aba2d7145eb4cba6d643d96bda3f2ca55bb11980b318d43b289d55a108f4bc23a9606fb0bccdeb3b3bb30", "0x847020e0a440d9c4109773ecca5d8268b44d523389993b1f5e60e541187f7c597d79ebd6e318871815e26c96b4a4dbb1", "0xa530aa7e5ca86fcd1bec4b072b55cc793781f38a666c2033b510a69e110eeabb54c7d8cbcb9c61fee531a6f635ffa972", "0x87364a5ea1d270632a44269d686b2402da737948dac27f51b7a97af80b66728b0256547a5103d2227005541ca4b7ed04", "0x8816fc6e16ea277de93a6d793d0eb5c15e9e93eb958c5ef30adaf8241805adeb4da8ce19c3c2167f971f61e0b361077d", "0x8836a72d301c42510367181bb091e4be377777aed57b73c29ef2ce1d475feedd7e0f31676284d9a94f6db01cc4de81a2", "0xb0d9d8b7116156d9dde138d28aa05a33e61f8a85839c1e9071ccd517b46a5b4b53acb32c2edd7150c15bc1b4bd8db9e3", "0xae931b6eaeda790ba7f1cd674e53dc87f6306ff44951fa0df88d506316a5da240df9794ccbd7215a6470e6b31c5ea193", "0x8c6d5bdf87bd7f645419d7c6444e244fe054d437ed1ba0c122fde7800603a5fadc061e5b836cb22a6cfb2b466f20f013", "0x90d530c6d0cb654999fa771b8d11d723f54b8a8233d1052dc1e839ea6e314fbed3697084601f3e9bbb71d2b4eaa596df", "0xb0d341a1422588c983f767b1ed36c18b141774f67ef6a43cff8e18b73a009da10fc12120938b8bba27f225bdfd3138f9", "0xa131b56f9537f460d304e9a1dd75702ace8abd68cb45419695cb8dee76998139058336c87b7afd6239dc20d7f8f940cc", "0xaa6c51fa28975f709329adee1bbd35d49c6b878041841a94465e8218338e4371f5cb6c17f44a63ac93644bf28f15d20f", "0x88440fb584a99ebd7f9ea04aaf622f6e44e2b43bbb49fb5de548d24a238dc8f26c8da2ccf03dd43102bda9f16623f609", "0x9777b8695b790e702159a4a750d5e7ff865425b95fa0a3c15495af385b91c90c00a6bd01d1b77bffe8c47d01baae846f", "0x8b9d764ece7799079e63c7f01690c8eff00896a26a0d095773dea7a35967a8c40db7a6a74692f0118bf0460c26739af4", "0x85808c65c485520609c9e61fa1bb67b28f4611d3608a9f7a5030ee61c3aa3c7e7dc17fff48af76b4aecee2cb0dbd22ac", "0xad2783a76f5b3db008ef5f7e67391fda4e7e36abde6b3b089fc4835b5c339370287935af6bd53998bed4e399eda1136d", "0x96f18ec03ae47c205cc4242ca58e2eff185c9dca86d5158817e2e5dc2207ab84aadda78725f8dc080a231efdc093b940", "0x97de1ab6c6cc646ae60cf7b86df73b9cf56cc0cd1f31b966951ebf79fc153531af55ca643b20b773daa7cab784b832f7", "0x870ba266a9bfa86ef644b1ef025a0f1b7609a60de170fe9508de8fd53170c0b48adb37f19397ee8019b041ce29a16576", "0xad990e888d279ac4e8db90619d663d5ae027f994a3992c2fbc7d262b5990ae8a243e19157f3565671d1cb0de17fe6e55", "0x8d9d5adcdd94c5ba3be4d9a7428133b42e485f040a28d16ee2384758e87d35528f7f9868de9bd23d1a42a594ce50a567", "0x85a33ed75d514ece6ad78440e42f7fcdb59b6f4cff821188236d20edae9050b3a042ce9bc7d2054296e133d033e45022", "0x92afd2f49a124aaba90de59be85ff269457f982b54c91b06650c1b8055f9b4b0640fd378df02a00e4fc91f7d226ab980", "0x8c0ee09ec64bd831e544785e3d65418fe83ed9c920d9bb4d0bf6dd162c1264eb9d6652d2def0722e223915615931581c", "0x8369bedfa17b24e9ad48ebd9c5afea4b66b3296d5770e09b00446c5b0a8a373d39d300780c01dcc1c6752792bccf5fd0", "0x8b9e960782576a59b2eb2250d346030daa50bbbec114e95cdb9e4b1ba18c3d34525ae388f859708131984976ca439d94", "0xb682bface862008fea2b5a07812ca6a28a58fd151a1d54c708fc2f8572916e0d678a9cb8dc1c10c0470025c8a605249e", "0xa38d5e189bea540a824b36815fc41e3750760a52be0862c4cac68214febdc1a754fb194a7415a8fb7f96f6836196d82a", "0xb9e7fbda650f18c7eb8b40e42cc42273a7298e65e8be524292369581861075c55299ce69309710e5b843cb884de171bd", "0xb6657e5e31b3193874a1bace08f42faccbd3c502fb73ad87d15d18a1b6c2a146f1baa929e6f517db390a5a47b66c0acf", "0xae15487312f84ed6265e4c28327d24a8a0f4d2d17d4a5b7c29b974139cf93223435aaebe3af918f5b4bb20911799715f", "0x8bb4608beb06bc394e1a70739b872ce5a2a3ffc98c7547bf2698c893ca399d6c13686f6663f483894bccaabc3b9c56ad", "0xb58ac36bc6847077584308d952c5f3663e3001af5ecf2e19cb162e1c58bd6c49510205d453cffc876ca1dc6b8e04a578", "0x924f65ced61266a79a671ffb49b300f0ea44c50a0b4e3b02064faa99fcc3e4f6061ea8f38168ab118c5d47bd7804590e", "0x8d67d43b8a06b0ff4fafd7f0483fa9ed1a9e3e658a03fb49d9d9b74e2e24858dc1bed065c12392037b467f255d4e5643", "0xb4d4f87813125a6b355e4519a81657fa97c43a6115817b819a6caf4823f1d6a1169683fd68f8d025cdfa40ebf3069acb", "0xa7fd4d2c8e7b59b8eed3d4332ae94b77a89a2616347402f880bc81bde072220131e6dbec8a605be3a1c760b775375879", "0x8d4a7d8fa6f55a30df37bcf74952e2fa4fd6676a2e4606185cf154bdd84643fd01619f8fb8813a564f72e3f574f8ce30", "0x8086fb88e6260e9a9c42e9560fde76315ff5e5680ec7140f2a18438f15bc2cc7d7d43bfb5880b180b738c20a834e6134", "0x916c4c54721de03934fee6f43de50bb04c81f6f8dd4f6781e159e71c40c60408aa54251d457369d133d4ba3ed7c12cb4", "0x902e5bf468f11ed9954e2a4a595c27e34abe512f1d6dc08bbca1c2441063f9af3dc5a8075ab910a10ff6c05c1c644a35", "0xa1302953015e164bf4c15f7d4d35e3633425a78294406b861675667eec77765ff88472306531e5d3a4ec0a2ff0dd6a9e", "0x87874461df3c9aa6c0fa91325576c0590f367075f2f0ecfeb34afe162c04c14f8ce9d608c37ac1adc8b9985bc036e366", "0x84b50a8a61d3cc609bfb0417348133e698fe09a6d37357ce3358de189efcf35773d78c57635c2d26c3542b13cc371752", "0xacaed2cff8633d12c1d12bb7270c54d65b0b0733ab084fd47f81d0a6e1e9b6f300e615e79538239e6160c566d8bb8d29", "0x889e6a0e136372ca4bac90d1ab220d4e1cad425a710e8cdd48b400b73bb8137291ceb36a39440fa84305783b1d42c72f", "0x90952e5becec45b2b73719c228429a2c364991cf1d5a9d6845ae5b38018c2626f4308daa322cab1c72e0f6c621bb2b35", "0x8f5a97a801b6e9dcd66ccb80d337562c96f7914e7169e8ff0fda71534054c64bf2a9493bb830623d612cfe998789be65", "0x84f3df8b9847dcf1d63ca470dc623154898f83c25a6983e9b78c6d2d90a97bf5e622445be835f32c1e55e6a0a562ea78", "0x91d12095cd7a88e7f57f254f02fdb1a1ab18984871dead2f107404bcf8069fe68258c4e6f6ebd2477bddf738135400bb", "0xb771a28bc04baef68604d4723791d3712f82b5e4fe316d7adc2fc01b935d8e644c06d59b83bcb542afc40ebafbee0683", "0x872f6341476e387604a7e93ae6d6117e72d164e38ebc2b825bc6df4fcce815004d7516423c190c1575946b5de438c08d", "0x90d6b4aa7d40a020cdcd04e8b016d041795961a8e532a0e1f4041252131089114a251791bf57794cadb7d636342f5d1c", "0x899023ba6096a181448d927fed7a0fe858be4eac4082a42e30b3050ee065278d72fa9b9d5ce3bc1372d4cbd30a2f2976", "0xa28f176571e1a9124f95973f414d5bdbf5794d41c3839d8b917100902ac4e2171eb940431236cec93928a60a77ede793", "0x838dbe5bcd29c4e465d02350270fa0036cd46f8730b13d91e77afb7f5ed16525d0021d3b2ae173a76c378516a903e0cb", "0x8e105d012dd3f5d20f0f1c4a7e7f09f0fdd74ce554c3032e48da8cce0a77260d7d47a454851387770f5c256fa29bcb88", "0x8f4df0f9feeb7a487e1d138d13ea961459a6402fd8f8cabb226a92249a0d04ded5971f3242b9f90d08da5ff66da28af6", "0xad1cfda4f2122a20935aa32fb17c536a3653a18617a65c6836700b5537122af5a8206befe9eaea781c1244c43778e7f1", "0x832c6f01d6571964ea383292efc8c8fa11e61c0634a25fa180737cc7ab57bc77f25e614aac9a2a03d98f27b3c1c29de2", "0x903f89cc13ec6685ac7728521898781fecb300e9094ef913d530bf875c18bcc3ceed7ed51e7b482d45619ab4b025c2e9", "0xa03c474bb915aad94f171e8d96f46abb2a19c9470601f4c915512ec8b9e743c3938450a2a5b077b4618b9df8809e1dc1", "0x83536c8456f306045a5f38ae4be2e350878fa7e164ea408d467f8c3bc4c2ee396bd5868008c089183868e4dfad7aa50b", "0x88f26b4ea1b236cb326cd7ad7e2517ec8c4919598691474fe15d09cabcfc37a8d8b1b818f4d112432ee3a716b0f37871", "0xa44324e3fe96e9c12b40ded4f0f3397c8c7ee8ff5e96441118d8a6bfad712d3ac990b2a6a23231a8f691491ac1fd480f", "0xb0de4693b4b9f932191a21ee88629964878680152a82996c0019ffc39f8d9369bbe2fe5844b68d6d9589ace54af947e4", "0x8e5d8ba948aea5fd26035351a960e87f0d23efddd8e13236cc8e4545a3dda2e9a85e6521efb8577e03772d3637d213d9", "0x93efc82d2017e9c57834a1246463e64774e56183bb247c8fc9dd98c56817e878d97b05f5c8d900acf1fbbbca6f146556", "0x8731176363ad7658a2862426ee47a5dce9434216cef60e6045fa57c40bb3ce1e78dac4510ae40f1f31db5967022ced32", "0xb10c9a96745722c85bdb1a693100104d560433d45b9ac4add54c7646a7310d8e9b3ca9abd1039d473ae768a18e489845", "0xa2ac374dfbb464bf850b4a2caf15b112634a6428e8395f9c9243baefd2452b4b4c61b0cb2836d8eae2d57d4900bf407e", "0xb69fe3ded0c4f5d44a09a0e0f398221b6d1bf5dbb8bc4e338b93c64f1a3cac1e4b5f73c2b8117158030ec03787f4b452", "0x8852cdbaf7d0447a8c6f211b4830711b3b5c105c0f316e3a6a18dcfbb9be08bd6f4e5c8ae0c3692da08a2dfa532f9d5c", "0x93bbf6d7432a7d98ade3f94b57bf9f4da9bc221a180a370b113066dd42601bb9e09edd79e2e6e04e00423399339eebda", "0xa80941c391f1eeafc1451c59e4775d6a383946ff22997aeaadf806542ba451d3b0f0c6864eeba954174a296efe2c1550", "0xa045fe2bb011c2a2f71a0181a8f457a3078470fb74c628eab8b59aef69ffd0d649723bf74d6885af3f028bc5a104fb39", "0xb9d8c35911009c4c8cad64692139bf3fc16b78f5a19980790cb6a7aea650a25df4231a4437ae0c351676a7e42c16134f", "0x94c79501ded0cfcbab99e1841abe4a00a0252b3870e20774c3da16c982d74c501916ec28304e71194845be6e3113c7ab", "0x900a66418b082a24c6348d8644ddb1817df5b25cb33044a519ef47cc8e1f7f1e38d2465b7b96d32ed472d2d17f8414c6", "0xb26f45d393b8b2fcb29bdbb16323dc7f4b81c09618519ab3a39f8ee5bd148d0d9f3c0b5dfab55b5ce14a1cb9206d777b", "0xaa1a87735fc493a80a96a9a57ca40a6d9c32702bfcaa9869ce1a116ae65d69cefe2f3e79a12454b4590353e96f8912b4", "0xa922b188d3d0b69b4e4ea2a2aa076566962844637da12c0832105d7b31dea4a309eee15d12b7a336be3ea36fcbd3e3b7", "0x8f3841fcf4105131d8c4d9885e6e11a46c448226401cf99356c291fadb864da9fa9d30f3a73c327f23f9fd99a11d633e", "0x9791d1183fae270e226379af6c497e7da803ea854bb20afa74b253239b744c15f670ee808f708ede873e78d79a626c9a", "0xa4cad52e3369491ada61bf28ada9e85de4516d21c882e5f1cd845bea9c06e0b2887b0c5527fcff6fc28acd3c04f0a796", "0xb9ac86a900899603452bd11a7892a9bfed8054970bfcbeaa8c9d1930db891169e38d6977f5258c25734f96c8462eee3b", "0xa3a154c28e5580656a859f4efc2f5ebfa7eaa84ca40e3f134fa7865e8581586db74992dbfa4036aa252fba103773ddde", "0x95cc2a0c1885a029e094f5d737e3ecf4d26b99036453a8773c77e360101f9f98676ee246f6f732a377a996702d55691f", "0x842651bbe99720438d8d4b0218feb60481280c05beb17750e9ca0d8c0599a60f873b7fbdcc7d8835ba9a6d57b16eec03", "0x81ee54699da98f5620307893dcea8f64670609fa20e5622265d66283adeac122d458b3308c5898e6c57c298db2c8b24f", "0xb97868b0b2bc98032d68352a535a1b341b9ff3c7af4e3a7f3ebc82d3419daa1b5859d6aedc39994939623c7cd878bd9b", "0xb60325cd5d36461d07ef253d826f37f9ee6474a760f2fff80f9873d01fd2b57711543cdc8d7afa1c350aa753c2e33dea", "0x8c205326c11d25a46717b780c639d89714c7736c974ae71287e3f4b02e6605ac2d9b4928967b1684f12be040b7bf2dd3", "0x95a392d82db51e26ade6c2ccd3396d7e40aff68fa570b5951466580d6e56dda51775dce5cf3a74a7f28c3cb2eb551c4d", "0x8f2cc8071eb56dffb70bda6dd433b556221dc8bba21c53353c865f00e7d4d86c9e39f119ea9a8a12ef583e9a55d9a6b6", "0x9449a71af9672aaf8856896d7e3d788b22991a7103f75b08c0abbcc2bfe60fda4ed8ce502cea4511ff0ea52a93e81222", "0x857090ab9fdb7d59632d068f3cc8cf27e61f0d8322d30e6b38e780a1f05227199b4cd746aac1311c36c659ef20931f28", "0x98a891f4973e7d9aaf9ac70854608d4f7493dffc7e0987d7be9dd6029f6ea5636d24ef3a83205615ca1ff403750058e1", "0xa486e1365bbc278dd66a2a25d258dc82f46b911103cb16aab3945b9c95ae87b386313a12b566df5b22322ede0afe25ad", "0xa9a1eb399ed95d396dccd8d1ac718043446f8b979ec62bdce51c617c97a312f01376ab7fb87d27034e5f5570797b3c33", "0xb7abc3858d7a74bb446218d2f5a037e0fae11871ed9caf44b29b69c500c1fa1dcfad64c9cdccc9d80d5e584f06213deb", "0x8cfb09fe2e202faa4cebad932b1d35f5ca204e1c2a0c740a57812ac9a6792130d1312aabd9e9d4c58ca168bfebd4c177", "0xa90a305c2cd0f184787c6be596fa67f436afd1f9b93f30e875f817ac2aae8bdd2e6e656f6be809467e6b3ad84adb86b1", "0x80a9ef993c2b009ae172cc8f7ec036f5734cf4f4dfa06a7db4d54725e7fbfae5e3bc6f22687bdbb6961939d6f0c87537", "0x848ade1901931e72b955d7db1893f07003e1708ff5d93174bac5930b9a732640f0578839203e9b77eb27965c700032d3", "0x93fdf4697609c5ae9c33b9ca2f5f1af44abeb2b98dc4fdf732cf7388de086f410730dc384d9b7a7f447bb009653c8381", "0x89ce3fb805aea618b5715c0d22a9f46da696b6fa86794f56fdf1d44155a33d42daf1920bcbe36cbacf3cf4c92df9cbc7", "0x829ce2c342cf82aa469c65f724f308f7a750bd1494adc264609cd790c8718b8b25b5cab5858cf4ee2f8f651d569eea67", "0xaf2f0cee7bf413204be8b9df59b9e4991bc9009e0d6dbe6815181df0ec2ca93ab8f4f3135b1c14d8f53d74bff0bd6f27", "0xb87998cecf7b88cde93d1779f10a521edd5574a2fbd240102978639ec57433ba08cdb53849038a329cebbe74657268d2", "0xa64542a1261a6ed3d720c2c3a802303aad8c4c110c95d0f12e05c1065e66f42da494792b6bfc5b9272363f3b1d457f58", "0x86a6fd042e4f282fadf07a4bfee03fc96a3aea49f7a00f52bf249a20f1ec892326855410e61f37fbb27d9305eb2fc713", "0x967ea5bc403b6db269682f7fd0df90659350d7e1aa66bc4fab4c9dfcd75ed0bba4b52f1cebc5f34dc8ba810793727629", "0xa52990f9f3b8616ce3cdc2c74cd195029e6a969753dcf2d1630438700e7d6ebde36538532b3525ac516f5f2ce9dd27a3", "0xa64f7ff870bab4a8bf0d4ef6f5c744e9bf1021ed08b4c80903c7ad318e80ba1817c3180cc45cb5a1cae1170f0241655f", "0xb00f706fa4de1f663f021e8ad3d155e84ce6084a409374b6e6cd0f924a0a0b51bebaaaf1d228c77233a73b0a5a0df0e9", "0x8b882cc3bff3e42babdb96df95fb780faded84887a0a9bab896bef371cdcf169d909f5658649e93006aa3c6e1146d62e", "0x9332663ef1d1dcf805c3d0e4ce7a07d9863fb1731172e766b3cde030bf81682cc011e26b773fb9c68e0477b4ae2cfb79", "0xa8aa8151348dbd4ef40aaeb699b71b4c4bfd3218560c120d85036d14f678f6736f0ec68e80ce1459d3d35feccc575164", "0xa16cd8b729768f51881c213434aa28301fa78fcb554ddd5f9012ee1e4eae7b5cb3dd88d269d53146dea92d10790faf0b", "0x86844f0ef9d37142faf3b1e196e44fbe280a3ba4189aa05c356778cb9e3b388a2bff95eed305ada8769935c9974e4c57", "0xae2eec6b328fccf3b47bcdac32901ac2744a51beb410b04c81dea34dee4912b619466a4f5e2780d87ecefaebbe77b46d", "0x915df4c38d301c8a4eb2dc5b1ba0ffaad67cbb177e0a80095614e9c711f4ef24a4cef133f9d982a63d2a943ba6c8669d", "0xae6a2a4dedfc2d1811711a8946991fede972fdf2a389b282471280737536ffc0ac3a6d885b1f8bda0366eb0b229b9979", "0xa9b628c63d08b8aba6b1317f6e91c34b2382a6c85376e8ef2410a463c6796740ae936fc4e9e0737cb9455d1daa287bd8", "0x848e30bf7edf2546670b390d5cf9ab71f98fcb6add3c0b582cb34996c26a446dee5d1bde4fdcde4fc80c10936e117b29", "0x907d6096c7c8c087d1808dd995d5d2b9169b3768c3f433475b50c2e2bd4b082f4d543afd8b0b0ddffa9c66222a72d51d", "0xa59970a2493b07339124d763ac9d793c60a03354539ecbcf6035bc43d1ea6e35718202ae6d7060b7d388f483d971573c", "0xb9cfef2af9681b2318f119d8611ff6d9485a68d8044581b1959ab1840cbca576dbb53eec17863d2149966e9feb21122f", "0xad47271806161f61d3afa45cdfe2babceef5e90031a21779f83dc8562e6076680525b4970b2f11fe9b2b23c382768323", "0x8e425a99b71677b04fe044625d338811fbb8ee32368a424f6ab2381c52e86ee7a6cecedf777dc97181519d41c351bc22", "0x86b55b54d7adefc12954a9252ee23ae83efe8b5b4b9a7dc307904413e5d69868c7087a818b2833f9b004213d629be8ad", "0xa14fda6b93923dd11e564ae4457a66f397741527166e0b16a8eb91c6701c244fd1c4b63f9dd3515193ec88fa6c266b35", "0xa9b17c36ae6cd85a0ed7f6cabc5b47dc8f80ced605db327c47826476dc1fb8f8669aa7a7dc679fbd4ee3d8e8b4bd6a6f", "0x82a0829469c1458d959c821148f15dacae9ea94bf56c59a6ab2d4dd8b3d16d73e313b5a3912a6c1f131d73a8f06730c4", "0xb22d56d549a53eaef549595924bdb621ff807aa4513feedf3fdcbf7ba8b6b9cfa4481c2f67fc642db397a6b794a8b63a", "0x974c59c24392e2cb9294006cbe3c52163e255f3bd0c2b457bdc68a6338e6d5b6f87f716854492f8d880a6b896ccf757c", "0xb70d247ba7cad97c50b57f526c2ba915786e926a94e8f8c3eebc2e1be6f4255411b9670e382060049c8f4184302c40b2", "0xad80201fe75ef21c3ddbd98cf23591e0d7a3ba1036dfe77785c32f44755a212c31f0ceb0a0b6f5ee9b6dc81f358d30c3", "0x8c656e841f9bb90b9a42d425251f3fdbc022a604d75f5845f479ed4be23e02aaf9e6e56cde351dd7449c50574818a199", "0x8b88dd3fa209d3063b7c5b058f7249ee9900fbc2287d16da61a0704a0a1d71e45d9c96e1cda7fdf9654534ec44558b22", "0x961da00cc8750bd84d253c08f011970ae1b1158ad6778e8ed943d547bceaf52d6d5a212a7de3bf2706688c4389b827d2", "0xa5dd379922549a956033e3d51a986a4b1508e575042b8eaa1df007aa77cf0b8c2ab23212f9c075702788fa9c53696133", "0xac8fcfde3a349d1e93fc8cf450814e842005c545c4844c0401bc80e6b96cdb77f29285a14455e167c191d4f312e866cd", "0xac63d79c799783a8466617030c59dd5a8f92ee6c5204676fd8d881ce5f7f8663bdbeb0379e480ea9b6340ab0dc88e574", "0x805874fde19ce359041ae2bd52a39e2841acabfd31f965792f2737d7137f36d4e4722ede8340d8c95afa6af278af8acb", "0x8d2f323a228aa8ba7b7dc1399138f9e6b41df1a16a7069003ab8104b8b68506a45141bc5fe66acf430e23e13a545190b", "0xa1610c721a2d9af882bb6b39bea97cff1527a3aea041d25934de080214ae77c959e79957164440686d15ab301e897d4d", "0xaba16d29a47fc36f12b654fde513896723e2c700c4190f11b26aa4011da57737ad717daa02794aa3246e4ae5f0b0cc3a", "0xa406db2f15fdd135f346cc4846623c47edd195e80ba8c7cb447332095314d565e4040694ca924696bb5ee7f8996ea0ba", "0x8b30e2cd9b47d75ba57b83630e40f832249af6c058d4f490416562af451993eec46f3e1f90bc4d389e4c06abd1b32a46", "0xaacf9eb7036e248e209adbfc3dd7ce386569ea9b312caa4b240726549db3c68c4f1c8cbf8ed5ea9ea60c7e57c9df3b8e", "0xb20fcac63bf6f5ee638a42d7f89be847f348c085ddcbec3fa318f4323592d136c230495f188ef2022aa355cc2b0da6f9", "0x811eff750456a79ec1b1249d76d7c1547065b839d8d4aaad860f6d4528eb5b669473dcceeeea676cddbc3980b68461b7", "0xb52d14ae33f4ab422f953392ae76a19c618cc31afc96290bd3fe2fb44c954b5c92c4789f3f16e8793f2c0c1691ade444", "0xa7826dafeeba0db5b66c4dfcf2b17fd7b40507a5a53ac2e42942633a2cb30b95ba1739a6e9f3b7a0e0f1ec729bf274e2", "0x8acfd83ddf7c60dd7c8b20c706a3b972c65d336b8f9b3d907bdd8926ced271430479448100050b1ef17578a49c8fa616", "0xaf0c69f65184bb06868029ad46f8465d75c36814c621ac20a5c0b06a900d59305584f5a6709683d9c0e4b6cd08d650a6", "0xb6cc8588191e00680ee6c3339bd0f0a17ad8fd7f4be57d5d7075bede0ea593a19e67f3d7c1a20114894ee5bfcab71063", "0xa82fd4f58635129dbb6cc3eb9391cf2d28400018b105fc41500fbbd12bd890b918f97d3d359c29dd3b4c4e34391dfab0", "0x92fc544ed65b4a3625cf03c41ddff7c039bc22d22c0d59dcc00efd5438401f2606adb125a1d5de294cca216ec8ac35a3", "0x906f67e4a32582b71f15940523c0c7ce370336935e2646bdaea16a06995256d25e99df57297e39d6c39535e180456407", "0x97510337ea5bbd5977287339197db55c60533b2ec35c94d0a460a416ae9f60e85cee39be82abeeacd5813cf54df05862", "0x87e6894643815c0ea48cb96c607266c5ee4f1f82ba5fe352fb77f9b6ed14bfc2b8e09e80a99ac9047dfcf62b2ae26795", "0xb6fd55dd156622ad7d5d51b7dde75e47bd052d4e542dd6449e72411f68275775c846dde301e84613312be8c7bce58b07", "0xb98461ac71f554b2f03a94e429b255af89eec917e208a8e60edf5fc43b65f1d17a20de3f31d2ce9f0cb573c25f2f4d98", "0x96f0dea40ca61cefbee41c4e1fe9a7d81fbe1f49bb153d083ab70f5d0488a1f717fd28cedcf6aa18d07cce2c62801898", "0x8d7c3ab310184f7dc34b6ce4684e4d29a31e77b09940448ea4daac730b7eb308063125d4dd229046cf11bfd521b771e0", "0x96f0564898fe96687918bbf0a6adead99cf72e3a35ea3347e124af9d006221f8e82e5a9d2fe80094d5e8d48e610f415e", "0xad50fcb92c2675a398cf07d4c40a579e44bf8d35f27cc330b57e54d5ea59f7d898af0f75dccfe3726e5471133d70f92b", "0x828beed62020361689ae7481dd8f116902b522fb0c6c122678e7f949fdef70ead011e0e6bffd25678e388744e17cdb69", "0x8349decac1ca16599eee2efc95bcaabf67631107da1d34a2f917884bd70dfec9b4b08ab7bc4379d6c73b19c0b6e54fb8", "0xb2a6a2e50230c05613ace9e58bb2e98d94127f196f02d9dddc53c43fc68c184549ca12d713cb1b025d8260a41e947155", "0x94ff52181aadae832aed52fc3b7794536e2a31a21fc8be3ea312ca5c695750d37f08002f286b33f4023dba1e3253ecfa", "0xa21d56153c7e5972ee9a319501be4faff199fdf09bb821ea9ce64aa815289676c00f105e6f00311b3a5b627091b0d0fc", "0xa27a60d219f1f0c971db73a7f563b371b5c9fc3ed1f72883b2eac8a0df6698400c9954f4ca17d7e94e44bd4f95532afb", "0xa2fc56fae99b1f18ba5e4fe838402164ce82f8a7f3193d0bbd360c2bac07c46f9330c4c7681ffb47074c6f81ee6e7ac6", "0xb748e530cd3afb96d879b83e89c9f1a444f54e55372ab1dcd46a0872f95ce8f49cf2363fc61be82259e04f555937ed16", "0x8bf8993e81080c7cbba1e14a798504af1e4950b2f186ab3335b771d6acaee4ffe92131ae9c53d74379d957cb6344d9cd", "0x96774d0ef730d22d7ab6d9fb7f90b9ead44285219d076584a901960542756700a2a1603cdf72be4708b267200f6c36a9", "0xb47703c2ab17be1e823cc7bf3460db1d6760c0e33862c90ca058845b2ff234b0f9834ddba2efb2ee1770eb261e7d8ffd", "0x84319e67c37a9581f8b09b5e4d4ae88d0a7fb4cbb6908971ab5be28070c3830f040b1de83ee663c573e0f2f6198640e4", "0x96811875fa83133e0b3c0e0290f9e0e28bca6178b77fdf5350eb19344d453dbd0d71e55a0ef749025a5a2ca0ad251e81", "0x81a423423e9438343879f2bfd7ee9f1c74ebebe7ce3cfffc8a11da6f040cc4145c3b527bd3cf63f9137e714dbcb474ef", "0xb8c3535701ddbeec2db08e17a4fa99ba6752d32ece5331a0b8743676f421fcb14798afc7c783815484f14693d2f70db8", "0x81aee980c876949bf40782835eec8817d535f6f3f7e00bf402ddd61101fdcd60173961ae90a1cf7c5d060339a18c959d", "0x87e67b928d97b62c49dac321ce6cb680233f3a394d4c9a899ac2e8db8ccd8e00418e66cdfd68691aa3cb8559723b580c", "0x8eac204208d99a2b738648df96353bbb1b1065e33ee4f6bba174b540bbbd37d205855e1f1e69a6b7ff043ca377651126", "0x848e6e7a54ad64d18009300b93ea6f459ce855971dddb419b101f5ac4c159215626fadc20cc3b9ab1701d8f6dfaddd8b", "0x88aa123d9e0cf309d46dddb6acf634b1ade3b090a2826d6e5e78669fa1220d6df9a6697d7778cd9b627db17eea846126", "0x9200c2a629b9144d88a61151b661b6c4256cc5dadfd1e59a8ce17a013c2d8f7e754aabe61663c3b30f1bc47784c1f8cf", "0xb6e1a2827c3bdda91715b0e1b1f10dd363cef337e7c80cac1f34165fc0dea7c8b69747e310563db5818390146ce3e231", "0x92c333e694f89f0d306d54105b2a5dcc912dbe7654d9e733edab12e8537350815be472b063e56cfde5286df8922fdecb", "0xa6fac04b6d86091158ebb286586ccfec2a95c9786e14d91a9c743f5f05546073e5e3cc717635a0c602cad8334e922346", "0xa581b4af77feebc1fb897d49b5b507c6ad513d8f09b273328efbb24ef0d91eb740d01b4d398f2738125dacfe550330cd", "0x81c4860cccf76a34f8a2bc3f464b7bfd3e909e975cce0d28979f457738a56e60a4af8e68a3992cf273b5946e8d7f76e2", "0x8d1eaa09a3180d8af1cbaee673db5223363cc7229a69565f592fa38ba0f9d582cedf91e15dabd06ebbf2862fc0feba54", "0x9832f49b0147f4552402e54593cfa51f99540bffada12759b71fcb86734be8e500eea2d8b3d036710bdf04c901432de9", "0x8bdb0e8ec93b11e5718e8c13cb4f5de545d24829fd76161216340108098dfe5148ed25e3b57a89a516f09fa79043734d", "0xab96f06c4b9b0b2c0571740b24fca758e6976315053a7ecb20119150a9fa416db2d3a2e0f8168b390bb063f0c1caf785", "0xab777f5c52acd62ecf4d1f168b9cc8e1a9b45d4ec6a8ff52c583e867c2239aba98d7d3af977289b367edce03d9c2dfb1", "0xa09d3ce5e748da84802436951acc3d3ea5d8ec1d6933505ed724d6b4b0d69973ab0930daec9c6606960f6e541e4a3ce2", "0x8ef94f7be4d85d5ad3d779a5cf4d7b2fc3e65c52fb8e1c3c112509a4af77a0b5be994f251e5e40fabeeb1f7d5615c22b", "0xa7406a5bf5708d9e10922d3c5c45c03ef891b8d0d74ec9f28328a72be4cdc05b4f2703fa99366426659dfca25d007535", "0xb7f52709669bf92a2e070bfe740f422f0b7127392c5589c7f0af71bb5a8428697c762d3c0d74532899da24ea7d8695c2", "0xb9dfb0c8df84104dbf9239ccefa4672ef95ddabb8801b74997935d1b81a78a6a5669a3c553767ec19a1281f6e570f4ff", "0xae4d5c872156061ce9195ac640190d8d71dd406055ee43ffa6f9893eb24b870075b74c94d65bc1d5a07a6573282b5520", "0xafe6bd3eb72266d333f1807164900dcfa02a7eb5b1744bb3c86b34b3ee91e3f05e38fa52a50dc64eeb4bdb1dd62874b8", "0x948043cf1bc2ef3c01105f6a78dc06487f57548a3e6ef30e6ebc51c94b71e4bf3ff6d0058c72b6f3ecc37efd7c7fa8c0", "0xa22fd17c2f7ffe552bb0f23fa135584e8d2d8d75e3f742d94d04aded2a79e22a00dfe7acbb57d44e1cdb962fb22ae170", "0x8cd0f4e9e4fb4a37c02c1bde0f69359c43ab012eb662d346487be0c3758293f1ca560122b059b091fddce626383c3a8f", "0x90499e45f5b9c81426f3d735a52a564cafbed72711d9279fdd88de8038e953bc48c57b58cba85c3b2e4ce56f1ddb0e11", "0x8c30e4c034c02958384564cac4f85022ef36ab5697a3d2feaf6bf105049675bbf23d01b4b6814711d3d9271abff04cac", "0x81f7999e7eeea30f3e1075e6780bbf054f2fb6f27628a2afa4d41872a385b4216dd5f549da7ce6cf39049b2251f27fb7", "0xb36a7191f82fc39c283ffe53fc1f5a9a00b4c64eee7792a8443475da9a4d226cf257f226ea9d66e329af15d8f04984ec", "0xaad4da528fdbb4db504f3041c747455baff5fcd459a2efd78f15bdf3aea0bdb808343e49df88fe7a7c8620009b7964a3", "0x99ebd8c6dd5dd299517fb6381cfc2a7f443e6e04a351440260dd7c2aee3f1d8ef06eb6c18820b394366ecdfd2a3ce264", "0x8873725b81871db72e4ec3643084b1cdce3cbf80b40b834b092767728605825c19b6847ad3dcf328438607e8f88b4410", "0xb008ee2f895daa6abd35bd39b6f7901ae4611a11a3271194e19da1cdcc7f1e1ea008fe5c5440e50d2c273784541ad9c5", "0x9036feafb4218d1f576ef89d0e99124e45dacaa6d816988e34d80f454d10e96809791d5b78f7fd65f569e90d4d7238c5", "0x92073c1d11b168e4fa50988b0288638b4868e48bbc668c5a6dddf5499875d53be23a285acb5e4bad60114f6cf6c556e9", "0x88c87dfcb8ba6cbfe7e1be081ccfadbd589301db2cb7c99f9ee5d7db90aa297ed1538d5a867678a763f2deede5fd219a", "0xb42a562805c661a50f5dea63108002c0f27c0da113da6a9864c9feb5552225417c0356c4209e8e012d9bcc9d182c7611", "0x8e6317d00a504e3b79cd47feb4c60f9df186467fe9ca0f35b55c0364db30528f5ff071109dabb2fc80bb9cd4949f0c24", "0xb7b1ea6a88694f8d2f539e52a47466695e39e43a5eb9c6f23bca15305fe52939d8755cc3ac9d6725e60f82f994a3772f", "0xa3cd55161befe795af93a38d33290fb642b8d80da8b786c6e6fb02d393ea308fbe87f486994039cbd7c7b390414594b6", "0xb416d2d45b44ead3b1424e92c73c2cf510801897b05d1724ff31cbd741920cd858282fb5d6040fe1f0aa97a65bc49424", "0x950ee01291754feace97c2e933e4681e7ddfbc4fcd079eb6ff830b0e481d929c93d0c7fb479c9939c28ca1945c40da09", "0x869bd916aee8d86efe362a49010382674825d49195b413b4b4018e88ce43fe091b475d0b863ff0ba2259400f280c2b23", "0x9782f38cd9c9d3385ec286ebbc7cba5b718d2e65a5890b0a5906b10a89dc8ed80d417d71d7c213bf52f2af1a1f513ea7", "0x91cd33bc2628d096269b23faf47ee15e14cb7fdc6a8e3a98b55e1031ea0b68d10ba30d97e660f7e967d24436d40fad73", "0x8becc978129cc96737034c577ae7225372dd855da8811ae4e46328e020c803833b5bdbc4a20a93270e2b8bd1a2feae52", "0xa36b1d8076783a9522476ce17f799d78008967728ce920531fdaf88303321bcaf97ecaa08e0c01f77bc32e53c5f09525", "0xb4720e744943f70467983aa34499e76de6d59aa6fadf86f6b787fdce32a2f5b535b55db38fe2da95825c51002cfe142d", "0x91ad21fc502eda3945f6de874d1b6bf9a9a7711f4d61354f9e5634fc73f9c06ada848de15ab0a75811d3250be862827d", "0x84f78e2ebf5fc077d78635f981712daf17e2475e14c2a96d187913006ad69e234746184a51a06ef510c9455b38acb0d7", "0x960aa7906e9a2f11db64a26b5892ac45f20d2ccb5480f4888d89973beb6fa0dfdc06d68d241ff5ffc7f1b82b1aac242d", "0xa99365dcd1a00c66c9db6924b97c920f5c723380e823b250db85c07631b320ec4e92e586f7319e67a522a0578f7b6d6c", "0xa25d92d7f70cf6a88ff317cfec071e13774516da664f5fac0d4ecaa65b8bf4eb87a64a4d5ef2bd97dfae98d388dbf5cc", "0xa7af47cd0041295798f9779020a44653007444e8b4ef0712982b06d0dcdd434ec4e1f7c5f7a049326602cb605c9105b7", "0xaefe172eac5568369a05980931cc476bebd9dea573ba276d59b9d8c4420784299df5a910033b7e324a6c2dfc62e3ef05", "0xb69bc9d22ffa645baa55e3e02522e9892bb2daa7fff7c15846f13517d0799766883ee09ae0869df4139150c5b843ca8a", "0x95a10856140e493354fdd12722c7fdded21b6a2ffbc78aa2697104af8ad0c8e2206f44b0bfee077ef3949d46bbf7c16b", "0x891f2fcd2c47cbea36b7fa715968540c233313f05333f09d29aba23c193f462ed490dd4d00969656e89c53155fdfe710", "0xa6c33e18115e64e385c843dde34e8a228222795c7ca90bc2cc085705d609025f3351d9be61822c69035a49fb3e48f2d5", "0xb87fb12f12c0533b005adad0487f03393ff682e13575e3cb57280c3873b2c38ba96a63c49eef7a442753d26b7005230b", "0xb905c02ba451bfd411c135036d92c27af3b0b1c9c2f1309d6948544a264b125f39dd41afeff4666b12146c545adc168a", "0x8b29c513f43a78951cf742231cf5457a6d9d55edf45df5481a0f299a418d94effef561b15d2c1a01d1b8067e7153fda9", "0xb9941cccd51dc645920d2781c81a317e5a33cb7cf76427b60396735912cb6d2ca9292bb4d36b6392467d390d2c58d9f3", "0xa8546b627c76b6ef5c93c6a98538d8593dbe21cb7673fd383d5401b0c935eea0bdeeefeb1af6ad41bad8464fb87bbc48", "0xaa286b27de2812de63108a1aec29d171775b69538dc6198640ac1e96767c2b83a50391f49259195957d457b493b667c9", "0xa932fb229f641e9abbd8eb2bd874015d97b6658ab6d29769fc23b7db9e41dd4f850382d4c1f08af8f156c5937d524473", "0xa1412840fcc86e2aeec175526f2fb36e8b3b8d21a78412b7266daf81e51b3f68584ed8bd42a66a43afdd8c297b320520", "0x89c78be9efb624c97ebca4fe04c7704fa52311d183ffd87737f76b7dadc187c12c982bd8e9ed7cd8beb48cdaafd2fd01", "0xa3f5ddec412a5bec0ce15e3bcb41c6214c2b05d4e9135a0d33c8e50a78eaba71e0a5a6ea8b45854dec5c2ed300971fc2", "0x9721f9cec7a68b7758e3887548790de49fa6a442d0396739efa20c2f50352a7f91d300867556d11a703866def2d5f7b5", "0xa23764e140a87e5991573521af039630dd28128bf56eed2edbed130fd4278e090b60cf5a1dca9de2910603d44b9f6d45", "0xa1a6494a994215e48ab55c70efa8ffdddce6e92403c38ae7e8dd2f8288cad460c6c7db526bbdf578e96ca04d9fe12797", "0xb1705ea4cb7e074efe0405fc7b8ee2ec789af0426142f3ec81241cacd4f7edcd88e39435e4e4d8e7b1df64f3880d6613", "0x85595d061d677116089a6064418b93eb44ff79e68d12bd9625078d3bbc440a60d0b02944eff6054433ee34710ae6fbb4", "0x9978d5e30bedb7526734f9a1febd973a70bfa20890490e7cc6f2f9328feab1e24f991285dbc3711d892514e2d7d005ad", "0xaf30243c66ea43b9f87a061f947f7bce745f09194f6e95f379c7582b9fead920e5d6957eaf05c12ae1282ada4670652f", "0xa1930efb473f88001e47aa0b2b2a7566848cccf295792e4544096ecd14ee5d7927c173a8576b405bfa2eec551cd67eb5", "0xb0446d1c590ee5a45f7e22d269c044f3848c97aec1d226b44bfd0e94d9729c28a38bccddc3a1006cc5fe4e3c24f001f2", "0xb8a8380172df3d84b06176df916cf557966d4f2f716d3e9437e415d75b646810f79f2b2b71d857181b7fc944018883a3", "0xa563afec25b7817bfa26e19dc9908bc00aa8fc3d19be7d6de23648701659009d10e3e4486c28e9c6b13d48231ae29ac5", "0xa5a8e80579de886fb7d6408f542791876885947b27ad6fa99a8a26e381f052598d7b4e647b0115d4b5c64297e00ce28e", "0x8f87afcc7ad33c51ac719bade3cd92da671a37a82c14446b0a2073f4a0a23085e2c8d31913ed2d0be928f053297de8f6", "0xa43c455ce377e0bc434386c53c752880687e017b2f5ae7f8a15c044895b242dffde4c92fb8f8bb50b18470b17351b156", "0x8368f8b12a5bceb1dba25adb3a2e9c7dc9b1a77a1f328e5a693f5aec195cd1e06b0fe9476b554c1c25dac6c4a5b640a3", "0x919878b27f3671fc78396f11531c032f3e2bd132d04cc234fa4858676b15fb1db3051c0b1db9b4fc49038216f11321ce", "0xb48cd67fb7f1242696c1f877da4bdf188eac676cd0e561fbac1a537f7b8229aff5a043922441d603a26aae56a15faee4", "0xa3e0fdfd4d29ea996517a16f0370b54787fefe543c2fe73bfc6f9e560c1fd30dad8409859e2d7fa2d44316f24746c712", "0x8bb156ade8faf149df7bea02c140c7e392a4742ae6d0394d880a849127943e6f26312033336d3b9fdc0092d71b5efe87", "0x8845e5d5cc555ca3e0523244300f2c8d7e4d02aaebcb5bd749d791208856c209a6f84dd99fd55968c9f0ab5f82916707", "0xa3e90bb5c97b07789c2f32dff1aec61d0a2220928202f5ad5355ae71f8249237799d6c8a22602e32e572cb12eabe0c17", "0xb150bcc391884c996149dc3779ce71f15dda63a759ee9cc05871f5a8379dcb62b047098922c0f26c7bd04deb394c33f9", "0x95cd4ad88d51f0f2efcfd0c2df802fe252bb9704d1afbf9c26a248df22d55da87bdfaf41d7bc6e5df38bd848f0b13f42", "0xa05a49a31e91dff6a52ac8b9c2cfdd646a43f0d488253f9e3cfbce52f26667166bbb9b608fc358763a65cbf066cd6d05", "0xa59c3c1227fdd7c2e81f5e11ef5c406da44662987bac33caed72314081e2eed66055d38137e01b2268e58ec85dd986c0", "0xb7020ec3bd73a99861f0f1d88cf5a19abab1cbe14b7de77c9868398c84bb8e18dbbe9831838a96b6d6ca06e82451c67b", "0x98d1ff2525e9718ee59a21d8900621636fcd873d9a564b8dceb4be80a194a0148daf1232742730b3341514b2e5a5436c", "0x886d97b635975fc638c1b6afc493e5998ca139edba131b75b65cfe5a8e814f11bb678e0eeee5e6e5cd913ad3f2fefdfc", "0x8fb9fd928d38d5d813b671c924edd56601dd7163b686c13f158645c2f869d9250f3859aa5463a39258c90fef0f41190a", "0xaac35e1cd655c94dec3580bb3800bd9c2946c4a9856f7d725af15fbea6a2d8ca51c8ad2772abed60ee0e3fb9cb24046b", "0xb8d71fa0fa05ac9e443c9b4929df9e7f09a919be679692682e614d24227e04894bfc14a5c73a62fb927fedff4a0e4aa7", "0xa45a19f11fbbb531a704badbb813ed8088ab827c884ee4e4ebf363fa1132ff7cfa9d28be9c85b143e4f7cdbc94e7cf1a", "0x82b54703a4f295f5471b255ab59dce00f0fe90c9fb6e06b9ee48b15c91d43f4e2ef4a96c3118aeb03b08767be58181bb", "0x8283264c8e6d2a36558f0d145c18576b6600ff45ff99cc93eca54b6c6422993cf392668633e5df396b9331e873d457e5", "0x8c549c03131ead601bc30eb6b9537b5d3beb7472f5bb1bcbbfd1e9f3704477f7840ab3ab7f7dc13bbbbcdff886a462d4", "0xafbb0c520ac1b5486513587700ad53e314cb74bfbc12e0b5fbdcfdaac36d342e8b59856196a0d84a25cff6e6e1d17e76", "0x89e4c22ffb51f2829061b3c7c1983c5c750cad158e3a825d46f7cf875677da5d63f653d8a297022b5db5845c9271b32b", "0xafb27a86c4c2373088c96b9adf4433f2ebfc78ac5c526e9f0510670b6e4e5e0057c0a4f75b185e1a30331b9e805c1c15", "0xa18e16b57445f88730fc5d3567bf5a176861dc14c7a08ed2996fe80eed27a0e7628501bcb78a1727c5e9ac55f29c12c4", "0x93d61bf88b192d6825cf4e1120af1c17aa0f994d158b405e25437eaeefae049f7b721a206e7cc8a04fdc29d3c42580a1", "0xa99f2995a2e3ed2fd1228d64166112038de2f516410aa439f4c507044e2017ea388604e2d0f7121256fadf7fbe7023d1", "0x914fd91cffc23c32f1c6d0e98bf660925090d873367d543034654389916f65f552e445b0300b71b61b721a72e9a5983c", "0xb42a578a7787b71f924e7def425d849c1c777156b1d4170a8ee7709a4a914e816935131afd9a0412c4cb952957b20828", "0x82fb30590e84b9e45db1ec475a39971cf554dc01bcc7050bc89265740725c02e2be5a972168c5170c86ae83e5b0ad2c0", "0xb14f8d8e1e93a84976289e0cf0dfa6f3a1809e98da16ee5c4932d0e1ed6bf8a07697fdd4dd86a3df84fb0003353cdcc0", "0x85d7a2f4bda31aa2cb208b771fe03291a4ebdaf6f1dc944c27775af5caec412584c1f45bc741fca2a6a85acb3f26ad7d", "0xaf02e56ce886ff2253bc0a68faad76f25ead84b2144e5364f3fb9b648f03a50ee9dc0b2c33ebacf7c61e9e43201ef9ef", "0x87e025558c8a0b0abd06dfc350016847ea5ced7af2d135a5c9eec9324a4858c4b21510fb0992ec52a73447f24945058e", "0x80fff0bafcd058118f5e7a4d4f1ae0912efeb281d2cbe4d34ba8945cc3dbe5d8baf47fb077343b90b8d895c90b297aca", "0xb6edcf3a40e7b1c3c0148f47a263cd819e585a51ef31c2e35a29ce6f04c53e413f743034c0d998d9c00a08ba00166f31", "0xabb87ed86098c0c70a76e557262a494ff51a30fb193f1c1a32f8e35eafa34a43fcc07aa93a3b7a077d9e35afa07b1a3d", "0xa280214cd3bb0fb7ecd2d8bcf518cbd9078417f2b91d2533ec2717563f090fb84f2a5fcfdbbeb2a2a1f8a71cc5aa5941", "0xa63083ca7238ea2b57d15a475963cf1d4f550d8cd76db290014a0461b90351f1f26a67d674c837b0b773b330c7c3d534", "0xa8fa39064cb585ece5263e2f42f430206476bf261bd50f18d2b694889bd79d04d56410664cecad62690e5c5a20b3f6ff", "0x85ba52ce9d700a5dcf6c5b00559acbe599d671ce5512467ff4b6179d7fad550567ce2a9c126a50964e3096458ea87920", "0xb913501e1008f076e5eac6d883105174f88b248e1c9801e568fefaffa1558e4909364fc6d9512aa4d125cbd7cc895f05", "0x8eb33b5266c8f2ed4725a6ad147a322e44c9264cf261c933cbbe230a43d47fca0f29ec39756b20561dabafadd5796494", "0x850ebc8b661a04318c9db5a0515066e6454fa73865aa4908767a837857ecd717387f614acb614a88e075d4edc53a2f5a", "0xa08d6b92d866270f29f4ce23a3f5d99b36b1e241a01271ede02817c8ec3f552a5c562db400766c07b104a331835c0c64", "0x8131804c89bb3e74e9718bfc4afa547c1005ff676bd4db9604335032b203390cfa54478d45c6c78d1fe31a436ed4be9f", "0x9106d94f23cc1eacec8316f16d6f0a1cc160967c886f51981fdb9f3f12ee1182407d2bb24e5b873de58cb1a3ee915a6b", "0xa13806bfc3eae7a7000c9d9f1bd25e10218d4e67f59ae798b145b098bca3edad2b1040e3fc1e6310e612fb8818f459ac", "0x8c69fbca502046cb5f6db99900a47b34117aef3f4b241690cdb3b84ca2a2fc7833e149361995dc41fa78892525bce746", "0x852c473150c91912d58ecb05769222fa18312800c3f56605ad29eec9e2d8667b0b81c379048d3d29100ed2773bb1f3c5", "0xb1767f6074426a00e01095dbb1795beb4e4050c6411792cbad6537bc444c3165d1058bafd1487451f9c5ddd209e0ae7e", "0x80c600a5fe99354ce59ff0f84c760923dc8ff66a30bf47dc0a086181785ceb01f9b951c4e66df800ea6d705e8bc47055", "0xb5cf19002fbc88a0764865b82afcb4d64a50196ea361e5c71dff7de084f4dcbbc34ec94a45cc9e0247bd51da565981aa", "0x93e67a254ea8ce25e112d93cc927fadaa814152a2c4ec7d9a56eaa1ed47aec99b7e9916b02e64452cc724a6641729bbb", "0xace70b32491bda18eee4a4d041c3bc9effae9340fe7e6c2f5ad975ee0874c17f1a7da7c96bd85fccff9312c518fac6e9", "0xab4cfa02065017dd7f1aadc66f2c92f78f0f11b8597c03a5d69d82cb2eaf95a4476a836ac102908f137662472c8d914b", "0xa40b8cd8deb8ae503d20364d64cab7c2801b7728a9646ed19c65edea6a842756a2f636283494299584ad57f4bb12cd0b", "0x8594e11d5fc2396bcd9dbf5509ce4816dbb2b7305168021c426171fb444d111da5a152d6835ad8034542277011c26c0e", "0x8024de98c26b4c994a66628dc304bb737f4b6859c86ded552c5abb81fd4c6c2e19d5a30beed398a694b9b2fdea1dd06a", "0x8843f5872f33f54df8d0e06166c1857d733995f67bc54abb8dfa94ad92407cf0179bc91b0a50bbb56cdc2b350d950329", "0xb8bab44c7dd53ef9edf497dcb228e2a41282c90f00ba052fc52d57e87b5c8ab132d227af1fcdff9a12713d1f980bcaae", "0x982b4d7b29aff22d527fd82d2a52601d95549bfb000429bb20789ed45e5abf1f4b7416c7b7c4b79431eb3574b29be658", "0x8eb1f571b6a1878e11e8c1c757e0bc084bab5e82e897ca9be9b7f4b47b91679a8190bf0fc8f799d9b487da5442415857", "0xa6e74b588e5af935c8b243e888582ef7718f8714569dd4992920740227518305eb35fab674d21a5551cca44b3e511ef2", "0xa30fc2f3a4cb4f50566e82307de73cd7bd8fe2c1184e9293c136a9b9e926a018d57c6e4f308c95b9eb8299e94d90a2a1", "0xa50c5869ca5d2b40722c056a32f918d47e0b65ca9d7863ca7d2fb4a7b64fe523fe9365cf0573733ceaadebf20b48fff8", "0x83bbdd32c04d17581418cf360749c7a169b55d54f2427390defd9f751f100897b2d800ce6636c5bbc046c47508d60c8c", "0xa82904bdf614de5d8deaff688c8a5e7ac5b3431687acbcda8fa53960b7c417a39c8b2e462d7af91ce6d79260f412db8e", "0xa4362e31ff4b05d278b033cf5eebea20de01714ae16d4115d04c1da4754269873afc8171a6f56c5104bfd7b0db93c3e7", "0xb5b8daa63a3735581e74a021b684a1038cea77168fdb7fdf83c670c2cfabcfc3ab2fc7359069b5f9048188351aef26b5", "0xb48d723894b7782d96ac8433c48faca1bdfa5238019c451a7f47d958097cce3ae599b876cf274269236b9d6ff8b6d7ca", "0x98ffff6a61a3a6205c7820a91ca2e7176fab5dba02bc194c4d14942ac421cb254183c705506ab279e4f8db066f941c6c", "0xae7db24731da2eaa6efc4f7fcba2ecc26940ddd68038dce43acf2cee15b72dc4ef42a7bfdd32946d1ed78786dd7696b3", "0xa656db14f1de9a7eb84f6301b4acb2fbf78bfe867f48a270e416c974ab92821eb4df1cb881b2d600cfed0034ac784641", "0xaa315f8ecba85a5535e9a49e558b15f39520fce5d4bf43131bfbf2e2c9dfccc829074f9083e8d49f405fb221d0bc4c3c", "0x90bffba5d9ff40a62f6c8e9fc402d5b95f6077ed58d030c93e321b8081b77d6b8dac3f63a92a7ddc01585cf2c127d66c", "0xabdd733a36e0e0f05a570d0504e73801bf9b5a25ff2c78786f8b805704997acb2e6069af342538c581144d53149fa6d3", "0xb4a723bb19e8c18a01bd449b1bb3440ddb2017f10bb153da27deb7a6a60e9bb37619d6d5435fbb1ba617687838e01dd0", "0x870016b4678bab3375516db0187a2108b2e840bae4d264b9f4f27dbbc7cc9cac1d7dc582d7a04d6fd1ed588238e5e513", "0x80d33d2e20e8fc170aa3cb4f69fffb72aeafb3b5bb4ea0bc79ab55da14142ca19b2d8b617a6b24d537366e3b49cb67c3", "0xa7ee76aec273aaae03b3b87015789289551969fb175c11557da3ab77e39ab49d24634726f92affae9f4d24003050d974", "0x8415ea4ab69d779ebd42d0fe0c6aef531d6a465a5739e429b1fcf433ec45aa8296c527e965a20f0ec9f340c9273ea3cf", "0x8c7662520794e8b4405d0b33b5cac839784bc86a5868766c06cbc1fa306dbe334978177417b31baf90ce7b0052a29c56", "0x902b2abecc053a3dbdea9897ee21e74821f3a1b98b2d560a514a35799f4680322550fd3a728d4f6d64e1de98033c32b8", "0xa05e84ed9ecab8d508d670c39f2db61ad6e08d2795ec32a3c9d0d3737ef3801618f4fc2a95f90ec2f068606131e076c5", "0x8b9208ff4d5af0c2e3f53c9375da666773ac57197dfabb0d25b1c8d0588ba7f3c15ee9661bb001297f322ea2fbf6928b", "0xa3c827741b34a03254d4451b5ab74a96f2b9f7fb069e2f5adaf54fd97cc7a4d516d378db5ca07da87d8566d6eef13726", "0x8509d8a3f4a0ed378e0a1e28ea02f6bf1d7f6c819c6c2f5297c7df54c895b848f841653e32ba2a2c22c2ff739571acb8", "0xa0ce988b7d3c40b4e496aa83a09e4b5472a2d98679622f32bea23e6d607bc7de1a5374fb162bce0549a67dad948519be", "0xaa8a3dd12bd60e3d2e05f9c683cdcb8eab17fc59134815f8d197681b1bcf65108cba63ac5c58ee632b1e5ed6bba5d474", "0x8b955f1d894b3aefd883fb4b65f14cd37fc2b9db77db79273f1700bef9973bf3fd123897ea2b7989f50003733f8f7f21", "0xac79c00ddac47f5daf8d9418d798d8af89fc6f1682e7e451f71ea3a405b0d36af35388dd2a332af790bc83ca7b819328", "0xa0d44dd2a4438b809522b130d0938c3fe7c5c46379365dbd1810a170a9aa5818e1c783470dd5d0b6d4ac7edbb7330910", "0xa30b69e39ad43dd540a43c521f05b51b5f1b9c4eed54b8162374ae11eac25da4f5756e7b70ce9f3c92c2eeceee7431ed", "0xac43220b762c299c7951222ea19761ab938bf38e4972deef58ed84f4f9c68c230647cf7506d7cbfc08562fcca55f0485", "0xb28233b46a8fb424cfa386a845a3b5399d8489ceb83c8f3e05c22c934798d639c93718b7b68ab3ce24c5358339e41cbb", "0xac30d50ee8ce59a10d4b37a3a35e62cdb2273e5e52232e202ca7d7b8d09d28958ee667fae41a7bb6cdc6fe8f6e6c9c85", "0xb199842d9141ad169f35cc7ff782b274cbaa645fdb727761e0a89edbf0d781a15f8218b4bf4eead326f2903dd88a9cc1", "0x85e018c7ddcad34bb8285a737c578bf741ccd547e68c734bdb3808380e12c5d4ef60fc896b497a87d443ff9abd063b38", "0x8c856e6ba4a815bdb891e1276f93545b7072f6cb1a9aa6aa5cf240976f29f4dee01878638500a6bf1daf677b96b54343", "0xb8a47555fa8710534150e1a3f13eab33666017be6b41005397afa647ea49708565f2b86b77ad4964d140d9ced6b4d585", "0x8cd1f1db1b2f4c85a3f46211599caf512d5439e2d8e184663d7d50166fd3008f0e9253272f898d81007988435f715881", "0xb1f34b14612c973a3eceb716dc102b82ab18afef9de7630172c2780776679a7706a4874e1df3eaadf541fb009731807f", "0xb25464af9cff883b55be2ff8daf610052c02df9a5e147a2cf4df6ce63edcdee6dc535c533590084cc177da85c5dc0baa", "0x91c3c4b658b42d8d3448ae1415d4541d02379a40dc51e36a59bd6e7b9ba3ea51533f480c7c6e8405250ee9b96a466c29", "0x86dc027b95deb74c36a58a1333a03e63cb5ae22d3b29d114cfd2271badb05268c9d0c819a977f5e0c6014b00c1512e3a", "0xae0e6ff58eb5fa35da5107ebeacf222ab8f52a22bb1e13504247c1dfa65320f40d97b0e6b201cb6613476687cb2f0681", "0x8f13415d960b9d7a1d93ef28afc2223e926639b63bdefce0f85e945dfc81670a55df288893a0d8b3abe13c5708f82f91", "0x956f67ca49ad27c1e3a68c1faad5e7baf0160c459094bf6b7baf36b112de935fdfd79fa4a9ea87ea8de0ac07272969f4", "0x835e45e4a67df9fb51b645d37840b3a15c171d571a10b03a406dd69d3c2f22df3aa9c5cbe1e73f8d767ce01c4914ea9a", "0x919b938e56d4b32e2667469d0bdccb95d9dda3341aa907683ee70a14bbbe623035014511c261f4f59b318b610ac90aa3", "0x96b48182121ccd9d689bf1dfdc228175564cd68dc904a99c808a7f0053a6f636c9d953e12198bdf2ea49ea92772f2e18", "0xac5e5a941d567fa38fdbcfa8cf7f85bb304e3401c52d88752bcd516d1fa9bac4572534ea2205e38423c1df065990790f", "0xac0bd594fb85a8d4fc26d6df0fa81f11919401f1ecf9168b891ec7f061a2d9368af99f7fd8d9b43b2ce361e7b8482159", "0x83d92c69ca540d298fe80d8162a1c7af3fa9b49dfb69e85c1d136a3ec39fe419c9fa78e0bb6d96878771fbd37fe92e40", "0xb35443ae8aa66c763c2db9273f908552fe458e96696b90e41dd509c17a5c04ee178e3490d9c6ba2dc0b8f793c433c134", "0x923b2d25aa45b2e580ffd94cbb37dc8110f340f0f011217ee1bd81afb0714c0b1d5fb4db86006cdd2457563276f59c59", "0x96c9125d38fca1a61ac21257b696f8ac3dae78def50285e44d90ea293d591d1c58f703540a7e4e99e070afe4646bbe15", "0xb57946b2332077fbcdcb406b811779aefd54473b5559a163cd65cb8310679b7e2028aa55c12a1401fdcfcac0e6fae29a", "0x845daedc5cf972883835d7e13c937b63753c2200324a3b8082a6c4abb4be06c5f7c629d4abe4bfaf1d80a1f073eb6ce6", "0x91a55dfd0efefcd03dc6dacc64ec93b8d296cb83c0ee72400a36f27246e7f2a60e73b7b70ba65819e9cfb73edb7bd297", "0x8874606b93266455fe8fdd25df9f8d2994e927460af06f2e97dd4d2d90db1e6b06d441b72c2e76504d753badca87fb37", "0x8ee99e6d231274ff9252c0f4e84549da173041299ad1230929c3e3d32399731c4f20a502b4a307642cac9306ccd49d3c", "0x8836497714a525118e20849d6933bb8535fb6f72b96337d49e3133d936999c90a398a740f42e772353b5f1c63581df6d", "0xa6916945e10628f7497a6cdc5e2de113d25f7ade3e41e74d3de48ccd4fce9f2fa9ab69645275002e6f49399b798c40af", "0x9597706983107eb23883e0812e1a2c58af7f3499d50c6e29b455946cb9812fde1aa323d9ed30d1c0ffd455abe32303cd", "0xa24ee89f7f515cc33bdbdb822e7d5c1877d337f3b2162303cfc2dae028011c3a267c5cb4194afa63a4856a6e1c213448", "0x8cd25315e4318801c2776824ae6e7d543cb85ed3bc2498ba5752df2e8142b37653cf9e60104d674be3aeb0a66912e97a", "0xb5085ecbe793180b40dbeb879f4c976eaaccaca3a5246807dced5890e0ed24d35f3f86955e2460e14fb44ff5081c07ba", "0x960188cc0b4f908633a6840963a6fa2205fc42c511c6c309685234911c5304ef4c304e3ae9c9c69daa2fb6a73560c256", "0xa32d0a70bf15d569b4cda5aebe3e41e03c28bf99cdd34ffa6c5d58a097f322772acca904b3a47addb6c7492a7126ebac", "0x977f72d06ad72d4aa4765e0f1f9f4a3231d9f030501f320fe7714cc5d329d08112789fa918c60dd7fdb5837d56bb7fc6", "0x99fa038bb0470d45852bb871620d8d88520adb701712fcb1f278fed2882722b9e729e6cdce44c82caafad95e37d0e6f7", "0xb855e8f4fc7634ada07e83b6c719a1e37acb06394bc8c7dcab7747a8c54e5df3943915f021364bd019fdea103864e55f", "0x88bc2cd7458532e98c596ef59ea2cf640d7cc31b4c33cef9ed065c078d1d4eb49677a67de8e6229cc17ea48bace8ee5a", "0xaaa78a3feaa836d944d987d813f9b9741afb076e6aca1ffa42682ab06d46d66e0c07b8f40b9dbd63e75e81efa1ef7b08", "0xb7b080420cc4d808723b98b2a5b7b59c81e624ab568ecdfdeb8bf3aa151a581b6f56e983ef1b6f909661e25db40b0c69", "0xabee85c462ac9a2c58e54f06c91b3e5cd8c5f9ab5b5deb602b53763c54826ed6deb0d6db315a8d7ad88733407e8d35e2", "0x994d075c1527407547590df53e9d72dd31f037c763848d1662eebd4cefec93a24328c986802efa80e038cb760a5300f5", "0xab8777640116dfb6678e8c7d5b36d01265dfb16321abbfc277da71556a34bb3be04bc4ae90124ed9c55386d2bfb3bda0", "0x967e3a828bc59409144463bcf883a3a276b5f24bf3cbfdd7a42343348cba91e00b46ac285835a9b91eef171202974204", "0x875a9f0c4ffe5bb1d8da5e3c8e41d0397aa6248422a628bd60bfae536a651417d4e8a7d2fb98e13f2dad3680f7bd86d3", "0xacaa330c3e8f95d46b1880126572b238dbb6d04484d2cd4f257ab9642d8c9fc7b212188b9c7ac9e0fd135c520d46b1bf", "0xaceb762edbb0f0c43dfcdb01ea7a1ac5918ca3882b1e7ebc4373521742f1ed5250d8966b498c00b2b0f4d13212e6dd0b", "0x81d072b4ad258b3646f52f399bced97c613b22e7ad76373453d80b1650c0ca87edb291a041f8253b649b6e5429bb4cff", "0x980a47d27416ac39c7c3a0ebe50c492f8c776ea1de44d5159ac7d889b6d554357f0a77f0e5d9d0ff41aae4369eba1fc2", "0x8b4dfd5ef5573db1476d5e43aacfb5941e45d6297794508f29c454fe50ea622e6f068b28b3debe8635cf6036007de2e3", "0xa60831559d6305839515b68f8c3bc7abbd8212cc4083502e19dd682d56ca37c9780fc3ce4ec2eae81ab23b221452dc57", "0x951f6b2c1848ced9e8a2339c65918e00d3d22d3e59a0a660b1eca667d18f8430d737884e9805865ef3ed0fe1638a22d9", "0xb02e38fe790b492aa5e89257c4986c9033a8b67010fa2add9787de857d53759170fdd67715ca658220b4e14b0ca48124", "0xa51007e4346060746e6b0e4797fc08ef17f04a34fe24f307f6b6817edbb8ce2b176f40771d4ae8a60d6152cbebe62653", "0xa510005b05c0b305075b27b243c9d64bcdce85146b6ed0e75a3178b5ff9608213f08c8c9246f2ca6035a0c3e31619860", "0xaaff4ef27a7a23be3419d22197e13676d6e3810ceb06a9e920d38125745dc68a930f1741c9c2d9d5c875968e30f34ab5", "0x864522a9af9857de9814e61383bebad1ba9a881696925a0ea6bfc6eff520d42c506bbe5685a9946ed710e889765be4a0", "0xb63258c080d13f3b7d5b9f3ca9929f8982a6960bdb1b0f8676f4dca823971601672f15e653917bf5d3746bb220504913", "0xb51ce0cb10869121ae310c7159ee1f3e3a9f8ad498827f72c3d56864808c1f21fa2881788f19ece884d3f705cd7bd0c5", "0x95d9cecfc018c6ed510e441cf84c712d9909c778c16734706c93222257f64dcd2a9f1bd0b400ca271e22c9c487014274", "0x8beff4d7d0140b86380ff4842a9bda94c2d2be638e20ac68a4912cb47dbe01a261857536375208040c0554929ced1ddc", "0x891ff49258749e2b57c1e9b8e04b12c77d79c3308b1fb615a081f2aacdfb4b39e32d53e069ed136fdbd43c53b87418fa", "0x9625cad224e163d387738825982d1e40eeff35fe816d10d7541d15fdc4d3eee48009090f3faef4024b249205b0b28f72", "0x8f3947433d9bd01aa335895484b540a9025a19481a1c40b4f72dd676bfcf332713714fd4010bde936eaf9470fd239ed0", "0xa00ec2d67789a7054b53f0e858a8a232706ccc29a9f3e389df7455f1a51a2e75801fd78469a13dbc25d28399ae4c6182", "0xa3f65884506d4a62b8775a0ea0e3d78f5f46bc07910a93cd604022154eabdf1d73591e304d61edc869e91462951975e1", "0xa14eef4fd5dfac311713f0faa9a60415e3d30b95a4590cbf95f2033dffb4d16c02e7ceff3dcd42148a4e3bc49cce2dd4", "0x8afa11c0eef3c540e1e3460bc759bb2b6ea90743623f88e62950c94e370fe4fd01c22b6729beba4dcd4d581198d9358f", "0xafb05548a69f0845ffcc5f5dc63e3cdb93cd270f5655173b9a950394b0583663f2b7164ba6df8d60c2e775c1d9f120af", "0x97f179e01a947a906e1cbeafa083960bc9f1bade45742a3afee488dfb6011c1c6e2db09a355d77f5228a42ccaa7bdf8e", "0x8447fca4d35f74b3efcbd96774f41874ca376bf85b79b6e66c92fa3f14bdd6e743a051f12a7fbfd87f319d1c6a5ce217", "0xa57ca39c23617cd2cf32ff93b02161bd7baf52c4effb4679d9d5166406e103bc8f3c6b5209e17c37dbb02deb8bc72ddd", "0x9667c7300ff80f0140be002b0e36caab07aaee7cce72679197c64d355e20d96196acaf54e06e1382167d081fe6f739c1", "0x828126bb0559ce748809b622677267ca896fa2ee76360fd2c02990e6477e06a667241379ca7e65d61a5b64b96d7867de", "0x8b8835dea6ba8cf61c91f01a4b3d2f8150b687a4ee09b45f2e5fc8f80f208ae5d142d8e3a18153f0722b90214e60c5a7", "0xa98e8ff02049b4da386e3ee93db23bbb13dfeb72f1cfde72587c7e6d962780b7671c63e8ac3fbaeb1a6605e8d79e2f29", "0x87a4892a0026d7e39ef3af632172b88337cb03669dea564bcdb70653b52d744730ebb5d642e20cb627acc9dbb547a26b", "0x877352a22fc8052878a57effc159dac4d75fe08c84d3d5324c0bab6d564cdf868f33ceee515eee747e5856b62cfa0cc7", "0x8b801ba8e2ff019ee62f64b8cb8a5f601fc35423eb0f9494b401050103e1307dc584e4e4b21249cd2c686e32475e96c3", "0xa9e7338d6d4d9bfec91b2af28a8ed13b09415f57a3a00e5e777c93d768fdb3f8e4456ae48a2c6626b264226e911a0e28", "0x99c05fedf40ac4726ed585d7c1544c6e79619a0d3fb6bda75a08c7f3c0008e8d5e19ed4da48de3216135f34a15eba17c", "0xa61cce8a1a8b13a4a650fdbec0eeea8297c352a8238fb7cac95a0df18ed16ee02a3daa2de108fa122aca733bd8ad7855", "0xb97f37da9005b440b4cb05870dd881bf8491fe735844f2d5c8281818583b38e02286e653d9f2e7fa5e74c3c3eb616540", "0xa72164a8554da8e103f692ac5ebb4aece55d5194302b9f74b6f2a05335b6e39beede0bf7bf8c5bfd4d324a784c5fb08c", "0xb87e8221c5341cd9cc8bb99c10fe730bc105550f25ed4b96c0d45e6142193a1b2e72f1b3857373a659b8c09be17b3d91", "0xa41fb1f327ef91dcb7ac0787918376584890dd9a9675c297c45796e32d6e5985b12f9b80be47fc3a8596c245f419d395", "0x90dafa3592bdbb3465c92e2a54c2531822ba0459d45d3e7a7092fa6b823f55af28357cb51896d4ec2d66029c82f08e26", "0xa0a9adc872ebc396557f484f1dd21954d4f4a21c4aa5eec543f5fa386fe590839735c01f236574f7ff95407cd12de103", "0xb8c5c940d58be7538acf8672852b5da3af34f82405ef2ce8e4c923f1362f97fc50921568d0fd2fe846edfb0823e62979", "0x85aaf06a8b2d0dac89dafd00c28533f35dbd074978c2aaa5bef75db44a7b12aeb222e724f395513b9a535809a275e30b", "0x81f3cbe82fbc7028c26a6c1808c604c63ba023a30c9f78a4c581340008dbda5ec07497ee849a2183fcd9124f7936af32", "0xa11ac738de75fd60f15a34209d3825d5e23385796a4c7fc5931822f3f380af977dd0f7b59fbd58eed7777a071e21b680", "0x85a279c493de03db6fa6c3e3c1b1b29adc9a8c4effc12400ae1128da8421954fa8b75ad19e5388fe4543b76fb0812813", "0x83a217b395d59ab20db6c4adb1e9713fc9267f5f31a6c936042fe051ce8b541f579442f3dcf0fa16b9e6de9fd3518191", "0x83a0b86e7d4ed8f9ccdc6dfc8ff1484509a6378fa6f09ed908e6ab9d1073f03011dc497e14304e4e3d181b57de06a5ab", "0xa63ad69c9d25704ce1cc8e74f67818e5ed985f8f851afa8412248b2df5f833f83b95b27180e9e7273833ed0d07113d3b", "0x99b1bc2021e63b561fe44ddd0af81fcc8627a91bfeecbbc989b642bc859abc0c8d636399701aad7bbaf6a385d5f27d61", "0xb53434adb66f4a807a6ad917c6e856321753e559b1add70824e5c1e88191bf6993fccb9b8b911fc0f473fb11743acacd", "0x97ed3b9e6fb99bf5f945d4a41f198161294866aa23f2327818cdd55cb5dc4c1a8eff29dd8b8d04902d6cd43a71835c82", "0xb1e808260e368a18d9d10bdea5d60223ba1713b948c782285a27a99ae50cc5fc2c53d407de07155ecc16fb8a36d744a0", "0xa3eb4665f18f71833fec43802730e56b3ee5a357ea30a888ad482725b169d6f1f6ade6e208ee081b2e2633079b82ba7d", "0xab8beb2c8353fc9f571c18fdd02bdb977fc883313469e1277b0372fbbb33b80dcff354ca41de436d98d2ed710faa467e", "0xaa9071cfa971e4a335a91ad634c98f2be51544cb21f040f2471d01bb97e1df2277ae1646e1ea8f55b7ba9f5c8c599b39", "0x80b7dbfdcaf40f0678012acc634eba44ea51181475180d9deb2050dc4f2de395289edd0223018c81057ec79b04b04c49", "0x89623d7f6cb17aa877af14de842c2d4ab7fd576d61ddd7518b5878620a01ded40b6010de0da3cdf31d837eecf30e9847", "0xa773bb024ae74dd24761f266d4fb27d6fd366a8634febe8235376b1ae9065c2fe12c769f1d0407867dfbe9f5272c352f", "0x8455a561c3aaa6ba64c881a5e13921c592b3a02e968f4fb24a2243c36202795d0366d9cc1a24e916f84d6e158b7aeac7", "0x81d8bfc4b283cf702a40b87a2b96b275bdbf0def17e67d04842598610b67ea08c804d400c3e69fa09ea001eaf345b276", "0xb8f8f82cb11fea1c99467013d7e167ff03deb0c65a677fab76ded58826d1ba29aa7cf9fcd7763615735ea3ad38e28719", "0x89a6a04baf9cccc1db55179e1650b1a195dd91fb0aebc197a25143f0f393524d2589975e3fbfc2547126f0bced7fd6f2", "0xb81b2162df045390f04df07cbd0962e6b6ca94275a63edded58001a2f28b2ae2af2c7a6cba4ecd753869684e77e7e799", "0xa3757f722776e50de45c62d9c4a2ee0f5655a512344c4cbec542d8045332806568dd626a719ef21a4eb06792ca70f204", "0x8c5590df96ec22179a4e8786de41beb44f987a1dcc508eb341eecbc0b39236fdfad47f108f852e87179ccf4e10091e59", "0x87502f026ed4e10167419130b88c3737635c5b9074c364e1dd247cef5ef0fc064b4ae99b187e33301e438bbd2fe7d032", "0xaf925a2165e980ced620ff12289129fe17670a90ae0f4db9d4b39bd887ccb1f5d2514ac9ecf910f6390a8fc66bd5be17", "0x857fca899828cf5c65d26e3e8a6e658542782fc72762b3b9c73514919f83259e0f849a9d4838b40dc905fe43024d0d23", "0x87ffebdbfb69a9e1007ebac4ffcb4090ff13705967b73937063719aa97908986effcb7262fdadc1ae0f95c3690e3245d", "0xa9ff6c347ac6f4c6ab993b748802e96982eaf489dc69032269568412fc9a79e7c2850dfc991b28211b3522ee4454344b", "0xa65b3159df4ec48bebb67cb3663cd744027ad98d970d620e05bf6c48f230fa45bf17527fe726fdf705419bb7a1bb913e", "0x84b97b1e6408b6791831997b03cd91f027e7660fd492a93d95daafe61f02427371c0e237c75706412f442991dfdff989", "0xab761c26527439b209af0ae6afccd9340bbed5fbe098734c3145b76c5d2cd7115d9227b2eb523882b7317fbb09180498", "0xa0479a8da06d7a69c0b0fee60df4e691c19c551f5e7da286dab430bfbcabf31726508e20d26ea48c53365a7f00a3ad34", "0xa732dfc9baa0f4f40b5756d2e8d8937742999623477458e0bc81431a7b633eefc6f53b3b7939fe0a020018549c954054", "0x901502436a1169ba51dc479a5abe7c8d84e0943b16bc3c6a627b49b92cd46263c0005bc324c67509edd693f28e612af1", "0xb627aee83474e7f84d1bab9b7f6b605e33b26297ac6bbf52d110d38ba10749032bd551641e73a383a303882367af429b", "0x95108866745760baef4a46ef56f82da6de7e81c58b10126ebd2ba2cd13d339f91303bf2fb4dd104a6956aa3b13739503", "0x899ed2ade37236cec90056f3569bc50f984f2247792defafcceb49ad0ca5f6f8a2f06573705300e07f0de0c759289ff5", "0xa9f5eee196d608efe4bcef9bf71c646d27feb615e21252cf839a44a49fd89da8d26a758419e0085a05b1d59600e2dc42", "0xb36c6f68fed6e6c85f1f4a162485f24817f2843ec5cbee45a1ebfa367d44892e464949c6669f7972dc7167af08d55d25", "0xaaaede243a9a1b6162afbc8f571a52671a5a4519b4062e3f26777664e245ba873ed13b0492c5dbf0258c788c397a0e9e", "0x972b4fb39c31cbe127bf9a32a5cc10d621ebdd9411df5e5da3d457f03b2ab2cd1f6372d8284a4a9400f0b06ecdbfd38e", "0x8f6ca1e110e959a4b1d9a5ce5f212893cec21db40d64d5ac4d524f352d72198f923416a850bf845bc5a22a79c0ea2619", "0xa0f3c93b22134f66f04b2553a53b738644d1665ceb196b8494b315a4c28236fb492017e4a0de4224827c78e42f9908b7", "0x807fb5ee74f6c8735b0b5ca07e28506214fe4047dbeb00045d7c24f7849e98706aea79771241224939cb749cf1366c7d", "0x915eb1ff034224c0b645442cdb7d669303fdc00ca464f91aaf0b6fde0b220a3a74ff0cb043c26c9f3a5667b3fdaa9420", "0x8fda6cef56ed33fefffa9e6ac8e6f76b1af379f89761945c63dd448801f7bb8ca970504a7105fac2f74f652ccff32327", "0x87380cffdcffb1d0820fa36b63cc081e72187f86d487315177d4d04da4533eb19a0e2ff6115ceab528887819c44a5164", "0x8cd89e03411a18e7f16f968b89fb500c36d47d229f6487b99e62403a980058db5925ce249206743333538adfad168330", "0x974451b1df33522ce7056de9f03e10c70bf302c44b0741a59df3d6877d53d61a7394dcee1dd46e013d7cb9d73419c092", "0x98c35ddf645940260c490f384a49496a7352bb8e3f686feed815b1d38f59ded17b1ad6e84a209e773ed08f7b8ff1e4c2", "0x963f386cf944bb9b2ddebb97171b64253ea0a2894ac40049bdd86cda392292315f3a3d490ca5d9628c890cfb669f0acb", "0x8d507712152babd6d142ee682638da8495a6f3838136088df9424ef50d5ec28d815a198c9a4963610b22e49b4cdf95e9", "0x83d4bc6b0be87c8a4f1e9c53f257719de0c73d85b490a41f7420e777311640937320557ff2f1d9bafd1daaa54f932356", "0x82f5381c965b7a0718441131c4d13999f4cdce637698989a17ed97c8ea2e5bdb5d07719c5f7be8688edb081b23ede0f4", "0xa6ebecab0b72a49dfd01d69fa37a7f74d34fb1d4fef0aa10e3d6fceb9eccd671225c230af89f6eb514250e41a5f91f52", "0x846d185bdad6e11e604df7f753b7a08a28b643674221f0e750ebdb6b86ec584a29c869e131bca868972a507e61403f6a", "0x85a98332292acb744bd1c0fd6fdcf1f889a78a2c9624d79413ffa194cc8dfa7821a4b60cde8081d4b5f71f51168dd67f", "0x8f7d97c3b4597880d73200d074eb813d95432306e82dafc70b580b8e08cb8098b70f2d07b4b3ac6a4d77e92d57035031", "0x8185439c8751e595825d7053518cbe121f191846a38d4dbcb558c3f9d7a3104f3153401adaaaf27843bbe2edb504bfe3", "0xb3c00d8ece1518fca6b1215a139b0a0e26d9cba1b3a424f7ee59f30ce800a5db967279ed60958dd1f3ee69cf4dd1b204", "0xa2e6cb6978e883f9719c3c0d44cfe8de0cc6f644b98f98858433bea8bbe7b612c8aca5952fccce4f195f9d54f9722dc2", "0x99663087e3d5000abbec0fbda4e7342ec38846cc6a1505191fb3f1a337cb369455b7f8531a6eb8b0f7b2c4baf83cbe2b", "0xab0836c6377a4dbc7ca6a4d6cf021d4cd60013877314dd05f351706b128d4af6337711ed3443cb6ca976f40d74070a9a", "0x87abfd5126152fd3bac3c56230579b489436755ea89e0566aa349490b36a5d7b85028e9fb0710907042bcde6a6f5d7e3", "0x974ba1033f75f60e0cf7c718a57ae1da3721cf9d0fb925714c46f027632bdd84cd9e6de4cf4d00bc55465b1c5ebb7384", "0xa607b49d73689ac64f25cec71221d30d53e781e1100d19a2114a21da6507a60166166369d860bd314acb226596525670", "0xa7c2b0b915d7beba94954f2aa7dd08ec075813661e2a3ecca5d28a0733e59583247fed9528eb28aba55b972cdbaf06eb", "0xb8b3123e44128cc8efbe3270f2f94e50ca214a4294c71c3b851f8cbb70cb67fe9536cf07d04bf7fe380e5e3a29dd3c15", "0xa59a07e343b62ad6445a0859a32b58c21a593f9ddbfe52049650f59628c93715aa1f4e1f45b109321756d0eeec8a5429", "0x94f51f8a4ed18a6030d0aaa8899056744bd0e9dc9ac68f62b00355cddab11da5da16798db75f0bfbce0e5bdfe750c0b6", "0x97460a97ca1e1fa5ce243b81425edc0ec19b7448e93f0b55bc9785eedeeafe194a3c8b33a61a5c72990edf375f122777", "0x8fa859a089bc17d698a7ee381f37ce9beadf4e5b44fce5f6f29762bc04f96faff5d58c48c73631290325f05e9a1ecf49", "0xabdf38f3b20fc95eff31de5aa9ef1031abfa48f1305ee57e4d507594570401503476d3bcc493838fc24d6967a3082c7f", "0xb8914bfb82815abb86da35c64d39ab838581bc0bf08967192697d9663877825f2b9d6fbdcf9b410463482b3731361aef", "0xa8187f9d22b193a5f578999954d6ec9aa9b32338ccadb8a3e1ce5bad5ea361d69016e1cdfac44e9d6c54e49dd88561b9", "0xaac262cb7cba7fd62c14daa7b39677cabc1ef0947dd06dd89cac8570006a200f90d5f0353e84f5ff03179e3bebe14231", "0xa630ef5ece9733b8c46c0a2df14a0f37647a85e69c63148e79ffdcc145707053f9f9d305c3f1cf3c7915cb46d33abd07", "0xb102c237cb2e254588b6d53350dfda6901bd99493a3fbddb4121d45e0b475cf2663a40d7b9a75325eda83e4ba1e68cb3", "0x86a930dd1ddcc16d1dfa00aa292cb6c2607d42c367e470aa920964b7c17ab6232a7108d1c2c11fc40fb7496547d0bbf8", "0xa832fdc4500683e72a96cce61e62ac9ee812c37fe03527ad4cf893915ca1962cee80e72d4f82b20c8fc0b764376635a1", "0x88ad985f448dabb04f8808efd90f273f11f5e6d0468b5489a1a6a3d77de342992a73eb842d419034968d733f101ff683", "0x98a8538145f0d86f7fbf9a81c9140f6095c5bdd8960b1c6f3a1716428cd9cca1bf8322e6d0af24e6169abcf7df2b0ff6", "0x9048c6eba5e062519011e177e955a200b2c00b3a0b8615bdecdebc217559d41058d3315f6d05617be531ef0f6aef0e51", "0x833bf225ab6fc68cdcacf1ec1b50f9d05f5410e6cdcd8d56a3081dc2be8a8d07b81534d1ec93a25c2e270313dfb99e3b", "0xa84bcd24c3da5e537e64a811b93c91bfc84d7729b9ead7f79078989a6eb76717d620c1fad17466a0519208651e92f5ff", "0xb7cdd0a3fbd79aed93e1b5a44ca44a94e7af5ed911e4492f332e3a5ed146c7286bde01b52276a2fcc02780d2109874dd", "0x8a19a09854e627cb95750d83c20c67442b66b35896a476358f993ba9ac114d32c59c1b3d0b8787ee3224cf3888b56c64", "0xa9abd5afb8659ee52ada8fa5d57e7dd355f0a7350276f6160bec5fbf70d5f99234dd179eb221c913e22a49ec6d267846", "0x8c13c4274c0d30d184e73eaf812200094bbbd57293780bdadbceb262e34dee5b453991e7f37c7333a654fc71c69d6445", "0xa4320d73296ff8176ce0127ca1921c450e2a9c06eff936681ebaffb5a0b05b17fded24e548454de89aca2dcf6d7a9de4", "0xb2b8b3e15c1f645f07783e5628aba614e60157889db41d8161d977606788842b67f83f361eae91815dc0abd84e09abd5", "0xad26c3aa35ddfddc15719b8bb6c264aaec7065e88ac29ba820eb61f220fef451609a7bb037f3722d022e6c86e4f1dc88", "0xb8615bf43e13ae5d7b8dd903ce37190800cd490f441c09b22aa29d7a29ed2c0417b7a08ead417868f1de2589deaadd80", "0x8d3425e1482cd1e76750a76239d33c06b3554c3c3c87c15cb7ab58b1cee86a4c5c4178b44e23f36928365a1b484bde02", "0x806893a62e38c941a7dd6f249c83af16596f69877cc737d8f73f6b8cd93cbc01177a7a276b2b8c6b0e5f2ad864db5994", "0x86618f17fa4b0d65496b661bbb5ba3bc3a87129d30a4b7d4f515b904f4206ca5253a41f49fd52095861e5e065ec54f21", "0x9551915da1304051e55717f4c31db761dcdcf3a1366c89a4af800a9e99aca93a357bf928307f098e62b44a02cb689a46", "0x8f79c4ec0ec1146cb2a523b52fe33def90d7b5652a0cb9c2d1c8808a32293e00aec6969f5b1538e3a94cd1efa3937f86", "0xa0c03e329a707300081780f1e310671315b4c6a4cedcb29697aedfabb07a9d5df83f27b20e9c44cf6b16e39d9ded5b98", "0x86a7cfa7c8e7ce2c01dd0baec2139e97e8e090ad4e7b5f51518f83d564765003c65968f85481bbb97cb18f005ccc7d9f", "0xa33811770c6dfda3f7f74e6ad0107a187fe622d61b444bbd84fd7ef6e03302e693b093df76f6ab39bb4e02afd84a575a", "0x85480f5c10d4162a8e6702b5e04f801874d572a62a130be94b0c02b58c3c59bdcd48cd05f0a1c2839f88f06b6e3cd337", "0x8e181011564b17f7d787fe0e7f3c87f6b62da9083c54c74fd6c357a1f464c123c1d3d8ade3cf72475000b464b14e2be3", "0x8ee178937294b8c991337e0621ab37e9ffa4ca2bdb3284065c5e9c08aad6785d50cf156270ff9daf9a9127289710f55b", "0x8bd1e8e2d37379d4b172f1aec96f2e41a6e1393158d7a3dbd9a95c8dd4f8e0b05336a42efc11a732e5f22b47fc5c271d", "0x8f3da353cd487c13136a85677de8cedf306faae0edec733cf4f0046f82fa4639db4745b0095ff33a9766aba50de0cbcf", "0x8d187c1e97638df0e4792b78e8c23967dac43d98ea268ca4aabea4e0fa06cb93183fd92d4c9df74118d7cc27bf54415e", "0xa4c992f08c2f8bac0b74b3702fb0c75c9838d2ce90b28812019553d47613c14d8ce514d15443159d700b218c5a312c49", "0xa6fd1874034a34c3ea962a316c018d9493d2b3719bb0ec4edbc7c56b240802b2228ab49bee6f04c8a3e9f6f24a48c1c2", "0xb2efed8e799f8a15999020900dc2c58ece5a3641c90811b86a5198e593d7318b9d53b167818ccdfbe7df2414c9c34011", "0x995ff7de6181ddf95e3ead746089c6148da3508e4e7a2323c81785718b754d356789b902e7e78e2edc6b0cbd4ff22c78", "0x944073d24750a9068cbd020b834afc72d2dde87efac04482b3287b40678ad07588519a4176b10f2172a2c463d063a5cd", "0x99db4b1bb76475a6fd75289986ef40367960279524378cc917525fb6ba02a145a218c1e9caeb99332332ab486a125ac0", "0x89fce4ecd420f8e477af4353b16faabb39e063f3f3c98fde2858b1f2d1ef6eed46f0975a7c08f233b97899bf60ccd60a", "0x8c09a4f07a02b80654798bc63aada39fd638d3e3c4236ccd8a5ca280350c31e4a89e5f4c9aafb34116e71da18c1226b8", "0x85325cfa7ded346cc51a2894257eab56e7488dbff504f10f99f4cd2b630d913003761a50f175ed167e8073f1b6b63fb0", "0xb678b4fbec09a8cc794dcbca185f133578f29e354e99c05f6d07ac323be20aecb11f781d12898168e86f2e0f09aca15e", "0xa249cfcbca4d9ba0a13b5f6aac72bf9b899adf582f9746bb2ad043742b28915607467eb794fca3704278f9136f7642be", "0x9438e036c836a990c5e17af3d78367a75b23c37f807228362b4d13e3ddcb9e431348a7b552d09d11a2e9680704a4514f", "0x925ab70450af28c21a488bfb5d38ac994f784cf249d7fd9ad251bb7fd897a23e23d2528308c03415074d43330dc37ef4", "0xa290563904d5a8c0058fc8330120365bdd2ba1fdbaef7a14bc65d4961bb4217acfaed11ab82669e359531f8bf589b8db", "0xa7e07a7801b871fc9b981a71e195a3b4ba6b6313bc132b04796a125157e78fe5c11a3a46cf731a255ac2d78a4ae78cd0", "0xb26cd2501ee72718b0eebab6fb24d955a71f363f36e0f6dff0ab1d2d7836dab88474c0cef43a2cc32701fca7e82f7df3", "0xa1dc3b6c968f3de00f11275092290afab65b2200afbcfa8ddc70e751fa19dbbc300445d6d479a81bda3880729007e496", "0xa9bc213e28b630889476a095947d323b9ac6461dea726f2dc9084473ae8e196d66fb792a21905ad4ec52a6d757863e7d", "0xb25d178df8c2df8051e7c888e9fa677fde5922e602a95e966db9e4a3d6b23ce043d7dc48a5b375c6b7c78e966893e8c3", "0xa1c8d88d72303692eaa7adf68ea41de4febec40cc14ae551bb4012afd786d7b6444a3196b5d9d5040655a3366d96b7cd", "0xb22bd44f9235a47118a9bbe2ba5a2ba9ec62476061be2e8e57806c1a17a02f9a51403e849e2e589520b759abd0117683", "0xb8add766050c0d69fe81d8d9ea73e1ed05f0135d093ff01debd7247e42dbb86ad950aceb3b50b9af6cdc14ab443b238f", "0xaf2cf95f30ef478f018cf81d70d47d742120b09193d8bb77f0d41a5d2e1a80bfb467793d9e2471b4e0ad0cb2c3b42271", "0x8af5ef2107ad284e246bb56e20fef2a255954f72de791cbdfd3be09f825298d8466064f3c98a50496c7277af32b5c0bc", "0x85dc19558572844c2849e729395a0c125096476388bd1b14fa7f54a7c38008fc93e578da3aac6a52ff1504d6ca82db05", "0xae8c9b43c49572e2e166d704caf5b4b621a3b47827bb2a3bcd71cdc599bba90396fd9a405261b13e831bb5d44c0827d7", "0xa7ba7efede25f02e88f6f4cbf70643e76784a03d97e0fbd5d9437c2485283ad7ca3abb638a5f826cd9f6193e5dec0b6c", "0x94a9d122f2f06ef709fd8016fd4b712d88052245a65a301f5f177ce22992f74ad05552b1f1af4e70d1eac62cef309752", "0x82d999b3e7cf563833b8bc028ff63a6b26eb357dfdb3fd5f10e33a1f80a9b2cfa7814d871b32a7ebfbaa09e753e37c02", "0xaec6edcde234df502a3268dd2c26f4a36a2e0db730afa83173f9c78fcb2b2f75510a02b80194327b792811caefda2725", "0x94c0bfa66c9f91d462e9194144fdd12d96f9bbe745737e73bab8130607ee6ea9d740e2cfcbbd00a195746edb6369ee61", "0xab7573dab8c9d46d339e3f491cb2826cabe8b49f85f1ede78d845fc3995537d1b4ab85140b7d0238d9c24daf0e5e2a7e", "0x87e8b16832843251fe952dadfd01d41890ed4bb4b8fa0254550d92c8cced44368225eca83a6c3ad47a7f81ff8a80c984", "0x9189d2d9a7c64791b19c0773ad4f0564ce6bea94aa275a917f78ad987f150fdb3e5e26e7fef9982ac184897ecc04683f", "0xb3661bf19e2da41415396ae4dd051a9272e8a2580b06f1a1118f57b901fa237616a9f8075af1129af4eabfefedbe2f1c", "0xaf43c86661fb15daf5d910a4e06837225e100fb5680bd3e4b10f79a2144c6ec48b1f8d6e6b98e067d36609a5d038889a", "0x82ac0c7acaa83ddc86c5b4249aae12f28155989c7c6b91e5137a4ce05113c6cbc16f6c44948b0efd8665362d3162f16a", "0x8f268d1195ab465beeeb112cd7ffd5d5548559a8bc01261106d3555533fc1971081b25558d884d552df0db1cddda89d8", "0x8ef7caa5521f3e037586ce8ac872a4182ee20c7921c0065ed9986c047e3dda08294da1165f385d008b40d500f07d895f", "0x8c2f98f6880550573fad46075d3eba26634b5b025ce25a0b4d6e0193352c8a1f0661064027a70fe8190b522405f9f4e3", "0xb7653f353564feb164f0f89ec7949da475b8dad4a4d396d252fc2a884f6932d027b7eb2dc4d280702c74569319ed701a", "0xa026904f4066333befd9b87a8fad791d014096af60cdd668ef919c24dbe295ff31f7a790e1e721ba40cf5105abca67f4", "0x988f982004ada07a22dd345f2412a228d7a96b9cae2c487de42e392afe1e35c2655f829ce07a14629148ce7079a1f142", "0x9616add009067ed135295fb74d5b223b006b312bf14663e547a0d306694ff3a8a7bb9cfc466986707192a26c0bce599f", "0xad4c425de9855f6968a17ee9ae5b15e0a5b596411388cf976df62ecc6c847a6e2ddb2cea792a5f6e9113c2445dba3e5c", "0xb698ac9d86afa3dc69ff8375061f88e3b0cff92ff6dfe747cebaf142e813c011851e7a2830c10993b715e7fd594604a9", "0xa386fa189847bb3b798efca917461e38ead61a08b101948def0f82cd258b945ed4d45b53774b400af500670149e601b7", "0x905c95abda2c68a6559d8a39b6db081c68cef1e1b4be63498004e1b2f408409be9350b5b5d86a30fd443e2b3e445640a", "0x9116dade969e7ce8954afcdd43e5cab64dc15f6c1b8da9d2d69de3f02ba79e6c4f6c7f54d6bf586d30256ae405cd1e41", "0xa3084d173eacd08c9b5084a196719b57e47a0179826fda73466758235d7ecdb87cbcf097bd6b510517d163a85a7c7edd", "0x85bb00415ad3c9be99ff9ba83672cc59fdd24356b661ab93713a3c8eab34e125d8867f628a3c3891b8dc056e69cd0e83", "0x8d58541f9f39ed2ee4478acce5d58d124031338ec11b0d55551f00a5a9a6351faa903a5d7c132dc5e4bb026e9cbd18e4", "0xa622adf72dc250e54f672e14e128c700166168dbe0474cecb340da175346e89917c400677b1bc1c11fcc4cc26591d9db", "0xb3f865014754b688ca8372e8448114fff87bf3ca99856ab9168894d0c4679782c1ced703f5b74e851b370630f5e6ee86", "0xa7e490b2c40c2446fcd91861c020da9742c326a81180e38110558bb5d9f2341f1c1885e79b364e6419023d1cbdc47380", "0xb3748d472b1062e54572badbb8e87ac36534407f74932e7fc5b8392d008e8e89758f1671d1e4d30ab0fa40551b13bb5e", "0x89898a5c5ec4313aabc607b0049fd1ebad0e0c074920cf503c9275b564d91916c2c446d3096491c950b7af3ac5e4b0ed", "0x8eb8c83fef2c9dd30ea44e286e9599ec5c20aba983f702e5438afe2e5b921884327ad8d1566c72395587efac79ca7d56", "0xb92479599e806516ce21fb0bd422a1d1d925335ebe2b4a0a7e044dd275f30985a72b97292477053ac5f00e081430da80", "0xa34ae450a324fe8a3c25a4d653a654f9580ed56bbea213b8096987bbad0f5701d809a17076435e18017fea4d69f414bc", "0x81381afe6433d62faf62ea488f39675e0091835892ecc238e02acf1662669c6d3962a71a3db652f6fe3bc5f42a0e5dc5", "0xa430d475bf8580c59111103316fe1aa79c523ea12f1d47a976bbfae76894717c20220e31cf259f08e84a693da6688d70", "0xb842814c359754ece614deb7d184d679d05d16f18a14b288a401cef5dad2cf0d5ee90bad487b80923fc5573779d4e4e8", "0x971d9a2627ff2a6d0dcf2af3d895dfbafca28b1c09610c466e4e2bff2746f8369de7f40d65b70aed135fe1d72564aa88", "0x8f4ce1c59e22b1ce7a0664caaa7e53735b154cfba8d2c5cc4159f2385843de82ab58ed901be876c6f7fce69cb4130950", "0x86cc9dc321b6264297987000d344fa297ef45bcc2a4df04e458fe2d907ad304c0ea2318e32c3179af639a9a56f3263cf", "0x8229e0876dfe8f665c3fb19b250bd89d40f039bbf1b331468b403655be7be2e104c2fd07b9983580c742d5462ca39a43", "0x99299d73066e8eb128f698e56a9f8506dfe4bd014931e86b6b487d6195d2198c6c5bf15cccb40ccf1f8ddb57e9da44a2", "0xa3a3be37ac554c574b393b2f33d0a32a116c1a7cfeaf88c54299a4da2267149a5ecca71f94e6c0ef6e2f472b802f5189", "0xa91700d1a00387502cdba98c90f75fbc4066fefe7cc221c8f0e660994c936badd7d2695893fde2260c8c11d5bdcdd951", "0x8e03cae725b7f9562c5c5ab6361644b976a68bada3d7ca508abca8dfc80a469975689af1fba1abcf21bc2a190dab397d", "0xb01461ad23b2a8fa8a6d241e1675855d23bc977dbf4714add8c4b4b7469ccf2375cec20e80cedfe49361d1a30414ac5b", "0xa2673bf9bc621e3892c3d7dd4f1a9497f369add8cbaa3472409f4f86bd21ac67cfac357604828adfee6ada1835365029", "0xa042dff4bf0dfc33c178ba1b335e798e6308915128de91b12e5dbbab7c4ac8d60a01f6aea028c3a6d87b9b01e4e74c01", "0x86339e8a75293e4b3ae66b5630d375736b6e6b6b05c5cda5e73fbf7b2f2bd34c18a1d6cefede08625ce3046e77905cb8", "0xaf2ebe1b7d073d03e3d98bc61af83bf26f7a8c130fd607aa92b75db22d14d016481b8aa231e2c9757695f55b7224a27f", "0xa00ee882c9685e978041fd74a2c465f06e2a42ffd3db659053519925be5b454d6f401e3c12c746e49d910e4c5c9c5e8c", "0x978a781c0e4e264e0dad57e438f1097d447d891a1e2aa0d5928f79a9d5c3faae6f258bc94fdc530b7b2fa6a9932bb193", "0xaa4b7ce2e0c2c9e9655bf21e3e5651c8503bce27483017b0bf476be743ba06db10228b3a4c721219c0779747f11ca282", "0xb003d1c459dacbcf1a715551311e45d7dbca83a185a65748ac74d1800bbeaba37765d9f5a1a221805c571910b34ebca8", "0x95b6e531b38648049f0d19de09b881baa1f7ea3b2130816b006ad5703901a05da57467d1a3d9d2e7c73fb3f2e409363c", "0xa6cf9c06593432d8eba23a4f131bb7f72b9bd51ab6b4b772a749fe03ed72b5ced835a349c6d9920dba2a39669cb7c684", "0xaa3d59f6e2e96fbb66195bc58c8704e139fa76cd15e4d61035470bd6e305db9f98bcbf61ac1b95e95b69ba330454c1b3", "0xb57f97959c208361de6d7e86dff2b873068adb0f158066e646f42ae90e650079798f165b5cd713141cd3a2a90a961d9a", "0xa76ee8ed9052f6a7a8c69774bb2597be182942f08115baba03bf8faaeaee526feba86120039fe8ca7b9354c3b6e0a8e6", "0x95689d78c867724823f564627d22d25010f278674c6d2d0cdb10329169a47580818995d1d727ce46c38a1e47943ebb89", "0xab676d2256c6288a88e044b3d9ffd43eb9d5aaee00e8fc60ac921395fb835044c71a26ca948e557fed770f52d711e057", "0x96351c72785c32e5d004b6f4a1259fb8153d631f0c93fed172f18e8ba438fbc5585c1618deeabd0d6d0b82173c2e6170", "0x93dd8d3db576418e22536eba45ab7f56967c6c97c64260d6cddf38fb19c88f2ec5cd0e0156f50e70855eee8a2b879ffd", "0xad6ff16f40f6de3d7a737f8e6cebd8416920c4ff89dbdcd75eabab414af9a6087f83ceb9aff7680aa86bff98bd09c8cc", "0x84de53b11671abc9c38710e19540c5c403817562aeb22a88404cdaff792c1180f717dbdfe8f54940c062c4d032897429", "0x872231b9efa1cdd447b312099a5c164c560440a9441d904e70f5abfc3b2a0d16be9a01aca5e0a2599a61e19407587e3d", "0x88f44ac27094a2aa14e9dc40b099ee6d68f97385950f303969d889ee93d4635e34dff9239103bdf66a4b7cbba3e7eb7a", "0xa59afebadf0260e832f6f44468443562f53fbaf7bcb5e46e1462d3f328ac437ce56edbca617659ac9883f9e13261fad7", "0xb1990e42743a88de4deeacfd55fafeab3bc380cb95de43ed623d021a4f2353530bcab9594389c1844b1c5ea6634c4555", "0x85051e841149a10e83f56764e042182208591396d0ce78c762c4a413e6836906df67f38c69793e158d64fef111407ba3", "0x9778172bbd9b1f2ec6bbdd61829d7b39a7df494a818e31c654bf7f6a30139899c4822c1bf418dd4f923243067759ce63", "0x9355005b4878c87804fc966e7d24f3e4b02bed35b4a77369d01f25a3dcbff7621b08306b1ac85b76fe7b4a3eb5f839b1", "0x8f9dc6a54fac052e236f8f0e1f571ac4b5308a43acbe4cc8183bce26262ddaf7994e41cf3034a4cbeca2c505a151e3b1", "0x8cc59c17307111723fe313046a09e0e32ea0cce62c13814ab7c6408c142d6a0311d801be4af53fc9240523f12045f9ef", "0x8e6057975ed40a1932e47dd3ac778f72ee2a868d8540271301b1aa6858de1a5450f596466494a3e0488be4fbeb41c840", "0x812145efbd6559ae13325d56a15940ca4253b17e72a9728986b563bb5acc13ec86453796506ac1a8f12bd6f9e4a288c3", "0x911da0a6d6489eb3dab2ec4a16e36127e8a291ae68a6c2c9de33e97f3a9b1f00da57a94e270a0de79ecc5ecb45d19e83", "0xb72ea85973f4b2a7e6e71962b0502024e979a73c18a9111130e158541fa47bbaaf53940c8f846913a517dc69982ba9e1", "0xa7a56ad1dbdc55f177a7ad1d0af78447dc2673291e34e8ab74b26e2e2e7d8c5fe5dc89e7ef60f04a9508847b5b3a8188", "0xb52503f6e5411db5d1e70f5fb72ccd6463fa0f197b3e51ca79c7b5a8ab2e894f0030476ada72534fa4eb4e06c3880f90", "0xb51c7957a3d18c4e38f6358f2237b3904618d58b1de5dec53387d25a63772e675a5b714ad35a38185409931157d4b529", "0xb86b4266e719d29c043d7ec091547aa6f65bbf2d8d831d1515957c5c06513b72aa82113e9645ad38a7bc3f5383504fa6", "0xb95b547357e6601667b0f5f61f261800a44c2879cf94e879def6a105b1ad2bbf1795c3b98a90d588388e81789bd02681", "0xa58fd4c5ae4673fa350da6777e13313d5d37ed1dafeeb8f4f171549765b84c895875d9d3ae6a9741f3d51006ef81d962", "0x9398dc348d078a604aadc154e6eef2c0be1a93bb93ba7fe8976edc2840a3a318941338cc4d5f743310e539d9b46613d2", "0x902c9f0095014c4a2f0dccaaab543debba6f4cc82c345a10aaf4e72511725dbed7a34cd393a5f4e48a3e5142b7be84ed", "0xa7c0447849bb44d04a0393a680f6cd390093484a79a147dd238f5d878030d1c26646d88211108e59fe08b58ad20c6fbd", "0x80db045535d6e67a422519f5c89699e37098449d249698a7cc173a26ccd06f60238ae6cc7242eb780a340705c906790c", "0x8e52b451a299f30124505de2e74d5341e1b5597bdd13301cc39b05536c96e4380e7f1b5c7ef076f5b3005a868657f17c", "0x824499e89701036037571761e977654d2760b8ce21f184f2879fda55d3cda1e7a95306b8abacf1caa79d3cc075b9d27f", "0x9049b956b77f8453d2070607610b79db795588c0cec12943a0f5fe76f358dea81e4f57a4692112afda0e2c05c142b26f", "0x81911647d818a4b5f4990bfd4bc13bf7be7b0059afcf1b6839333e8569cdb0172fd2945410d88879349f677abaed5eb3", "0xad4048f19b8194ed45b6317d9492b71a89a66928353072659f5ce6c816d8f21e69b9d1817d793effe49ca1874daa1096", "0x8d22f7b2ddb31458661abd34b65819a374a1f68c01fc6c9887edeba8b80c65bceadb8f57a3eb686374004b836261ef67", "0x92637280c259bc6842884db3d6e32602a62252811ae9b019b3c1df664e8809ffe86db88cfdeb8af9f46435c9ee790267", "0xa2f416379e52e3f5edc21641ea73dc76c99f7e29ea75b487e18bd233856f4c0183429f378d2bfc6cd736d29d6cadfa49", "0x882cb6b76dbdc188615dcf1a8439eba05ffca637dd25197508156e03c930b17b9fed2938506fdd7b77567cb488f96222", "0xb68b621bb198a763fb0634eddb93ed4b5156e59b96c88ca2246fd1aea3e6b77ed651e112ac41b30cd361fadc011d385e", "0xa3cb22f6b675a29b2d1f827cacd30df14d463c93c3502ef965166f20d046af7f9ab7b2586a9c64f4eae4fad2d808a164", "0x8302d9ce4403f48ca217079762ce42cee8bc30168686bb8d3a945fbd5acd53b39f028dce757b825eb63af2d5ae41169d", "0xb2eef1fbd1a176f1f4cd10f2988c7329abe4eb16c7405099fb92baa724ab397bc98734ef7d4b24c0f53dd90f57520d04", "0xa1bbef0bd684a3f0364a66bde9b29326bac7aa3dde4caed67f14fb84fed3de45c55e406702f1495a3e2864d4ee975030", "0x976acdb0efb73e3a3b65633197692dedc2adaed674291ae3df76b827fc866d214e9cac9ca46baefc4405ff13f953d936", "0xb9fbf71cc7b6690f601f0b1c74a19b7d14254183a2daaafec7dc3830cba5ae173d854bbfebeca985d1d908abe5ef0cda", "0x90591d7b483598c94e38969c4dbb92710a1a894bcf147807f1bcbd8aa3ac210b9f2be65519aa829f8e1ccdc83ad9b8cf", "0xa30568577c91866b9c40f0719d46b7b3b2e0b4a95e56196ac80898a2d89cc67880e1229933f2cd28ee3286f8d03414d7", "0x97589a88c3850556b359ec5e891f0937f922a751ac7c95949d3bbc7058c172c387611c0f4cb06351ef02e5178b3dd9e4", "0x98e7bbe27a1711f4545df742f17e3233fbcc63659d7419e1ca633f104cb02a32c84f2fac23ca2b84145c2672f68077ab", "0xa7ddb91636e4506d8b7e92aa9f4720491bb71a72dadc47c7f4410e15f93e43d07d2b371951a0e6a18d1bd087aa96a5c4", "0xa7c006692227a06db40bceac3d5b1daae60b5692dd9b54772bedb5fea0bcc91cbcdb530cac31900ffc70c5b3ffadc969", "0x8d3ec6032778420dfa8be52066ba0e623467df33e4e1901dbadd586c5d750f4ccde499b5197e26b9ea43931214060f69", "0x8d9a8410518ea64f89df319bfd1fc97a0971cdb9ad9b11d1f8fe834042ea7f8dce4db56eeaf179ff8dda93b6db93e5ce", "0xa3c533e9b3aa04df20b9ff635cb1154ce303e045278fcf3f10f609064a5445552a1f93989c52ce852fd0bbd6e2b6c22e", "0x81934f3a7f8c1ae60ec6e4f212986bcc316118c760a74155d06ce0a8c00a9b9669ec4e143ca214e1b995e41271774fd9", "0xab8e2d01a71192093ef8fafa7485e795567cc9db95a93fb7cc4cf63a391ef89af5e2bfad4b827fffe02b89271300407f", "0x83064a1eaa937a84e392226f1a60b7cfad4efaa802f66de5df7498962f7b2649924f63cd9962d47906380b97b9fe80e1", "0xb4f5e64a15c6672e4b55417ee5dc292dcf93d7ea99965a888b1cc4f5474a11e5b6520eacbcf066840b343f4ceeb6bf33", "0xa63d278b842456ef15c278b37a6ea0f27c7b3ffffefca77c7a66d2ea06c33c4631eb242bbb064d730e70a8262a7b848a", "0x83a41a83dbcdf0d22dc049de082296204e848c453c5ab1ba75aa4067984e053acf6f8b6909a2e1f0009ed051a828a73b", "0x819485b036b7958508f15f3c19436da069cbe635b0318ebe8c014cf1ef9ab2df038c81161b7027475bcfa6fff8dd9faf", "0xaa40e38172806e1e045e167f3d1677ef12d5dcdc89b43639a170f68054bd196c4fae34c675c1644d198907a03f76ba57", "0x969bae484883a9ed1fbed53b26b3d4ee4b0e39a6c93ece5b3a49daa01444a1c25727dabe62518546f36b047b311b177c", "0x80a9e73a65da99664988b238096a090d313a0ee8e4235bc102fa79bb337b51bb08c4507814eb5baec22103ec512eaab0", "0x86604379aec5bddda6cbe3ef99c0ac3a3c285b0b1a15b50451c7242cd42ae6b6c8acb717dcca7917838432df93a28502", "0xa23407ee02a495bed06aa7e15f94cfb05c83e6d6fba64456a9bbabfa76b2b68c5c47de00ba169e710681f6a29bb41a22", "0x98cff5ecc73b366c6a01b34ac9066cb34f7eeaf4f38a5429bad2d07e84a237047e2a065c7e8a0a6581017dadb4695deb", "0x8de9f68a938f441f3b7ab84bb1f473c5f9e5c9e139e42b7ccee1d254bd57d0e99c2ccda0f3198f1fc5737f6023dd204e", "0xb0ce48d815c2768fb472a315cad86aa033d0e9ca506f146656e2941829e0acb735590b4fbc713c2d18d3676db0a954ac", "0x82f485cdefd5642a6af58ac6817991c49fac9c10ace60f90b27f1788cc026c2fe8afc83cf499b3444118f9f0103598a8", "0x82c24550ed512a0d53fc56f64cc36b553823ae8766d75d772dacf038c460f16f108f87a39ceef7c66389790f799dbab3", "0x859ffcf1fe9166388316149b9acc35694c0ea534d43f09dae9b86f4aa00a23b27144dda6a352e74b9516e8c8d6fc809c", "0xb8f7f353eec45da77fb27742405e5ad08d95ec0f5b6842025be9def3d9892f85eb5dd0921b41e6eff373618dba215bca", "0x8ccca4436f9017e426229290f5cd05eac3f16571a4713141a7461acfe8ae99cd5a95bf5b6df129148693c533966145da", "0xa2c67ecc19c0178b2994846fea4c34c327a5d786ac4b09d1d13549d5be5996d8a89021d63d65cb814923388f47cc3a03", "0xaa0ff87d676b418ec08f5cbf577ac7e744d1d0e9ebd14615b550eb86931eafd2a36d4732cc5d6fab1713fd7ab2f6f7c0", "0x8aef4730bb65e44efd6bb9441c0ae897363a2f3054867590a2c2ecf4f0224e578c7a67f10b40f8453d9f492ac15a9b2d", "0x86a187e13d8fba5addcfdd5b0410cedd352016c930f913addd769ee09faa6be5ca3e4b1bdb417a965c643a99bd92be42", "0xa0a4e9632a7a094b14b29b78cd9c894218cdf6783e61671e0203865dc2a835350f465fbaf86168f28af7c478ca17bc89", "0xa8c7b02d8deff2cd657d8447689a9c5e2cd74ef57c1314ac4d69084ac24a7471954d9ff43fe0907d875dcb65fd0d3ce5", "0x97ded38760aa7be6b6960b5b50e83b618fe413cbf2bcc1da64c05140bcc32f5e0e709cd05bf8007949953fac5716bad9", "0xb0d293835a24d64c2ae48ce26e550b71a8c94a0883103757fb6b07e30747f1a871707d23389ba2b2065fa6bafe220095", "0x8f9e291bf849feaa575592e28e3c8d4b7283f733d41827262367ea1c40f298c7bcc16505255a906b62bf15d9f1ba85fb", "0x998f4e2d12708b4fd85a61597ca2eddd750f73c9e0c9b3cf0825d8f8e01f1628fd19797dcaed3b16dc50331fc6b8b821", "0xb30d1f8c115d0e63bf48f595dd10908416774c78b3bbb3194192995154d80ea042d2e94d858de5f8aa0261b093c401fd", "0xb5d9c75bb41f964cbff3f00e96d9f1480c91df8913f139f0d385d27a19f57a820f838eb728e46823cbff00e21c660996", "0xa6edec90b5d25350e2f5f0518777634f9e661ec9d30674cf5b156c4801746d62517751d90074830ac0f4b09911c262f1", "0x82f98da1264b6b75b8fbeb6a4d96d6a05b25c24db0d57ba3a38efe3a82d0d4e331b9fc4237d6494ccfe4727206457519", "0xb89511843453cf4ecd24669572d6371b1e529c8e284300c43e0d5bb6b3aaf35aeb634b3cb5c0a2868f0d5e959c1d0772", "0xa82bf065676583e5c1d3b81987aaae5542f522ba39538263a944bb33ea5b514c649344a96c0205a3b197a3f930fcda6c", "0xa37b47ea527b7e06c460776aa662d9a49ff4149d3993f1a974b0dd165f7171770d189b0e2ea54fd5fccb6a14b116e68a", "0xa1017677f97dda818274d47556d09d0e4ccacb23a252f82a6cfe78c630ad46fb9806307445a59fb61262182de3a2b29c", "0xb01e9fcac239ba270e6877b79273ddd768bf8a51d2ed8a051b1c11e18eff3de5920e2fcbfbd26f06d381eddd3b1f1e1b", "0x82fcd53d803b1c8e4ed76adc339b7f3a5962d37042b9683aabac7513ac68775d4a566a9460183926a6a95dbe7d551a1f", "0xa763e78995d55cd21cdb7ef75d9642d6e1c72453945e346ab6690c20a4e1eeec61bb848ef830ae4b56182535e3c71d8f", "0xb769f4db602251d4b0a1186782799bdcef66de33c110999a5775c50b349666ffd83d4c89714c4e376f2efe021a5cfdb2", "0xa59cbd1b785efcfa6e83fc3b1d8cf638820bc0c119726b5368f3fba9dce8e3414204fb1f1a88f6c1ff52e87961252f97", "0x95c8c458fd01aa23ecf120481a9c6332ebec2e8bb70a308d0576926a858457021c277958cf79017ddd86a56cacc2d7db", "0x82eb41390800287ae56e77f2e87709de5b871c8bdb67c10a80fc65f3acb9f7c29e8fa43047436e8933f27449ea61d94d", "0xb3ec25e3545eb83aed2a1f3558d1a31c7edde4be145ecc13b33802654b77dc049b4f0065069dd9047b051e52ab11dcdd", "0xb78a0c715738f56f0dc459ab99e252e3b579b208142836b3c416b704ca1de640ca082f29ebbcee648c8c127df06f6b1e", "0xa4083149432eaaf9520188ebf4607d09cf664acd1f471d4fb654476e77a9eaae2251424ffda78d09b6cb880df35c1219", "0x8c52857d68d6e9672df3db2df2dbf46b516a21a0e8a18eec09a6ae13c1ef8f369d03233320dd1c2c0bbe00abfc1ea18b", "0x8c856089488803066bff3f8d8e09afb9baf20cecc33c8823c1c0836c3d45498c3de37e87c016b705207f60d2b00f8609", "0x831a3df39be959047b2aead06b4dcd3012d7b29417f642b83c9e8ce8de24a3dbbd29c6fdf55e2db3f7ea04636c94e403", "0xaed84d009f66544addabe404bf6d65af7779ce140dc561ff0c86a4078557b96b2053b7b8a43432ffb18cd814f143b9da", "0x93282e4d72b0aa85212a77b336007d8ba071eea17492da19860f1ad16c1ea8867ccc27ef5c37c74b052465cc11ea4f52", "0xa7b78b8c8d057194e8d68767f1488363f77c77bddd56c3da2bc70b6354c7aa76247c86d51f7371aa38a4aa7f7e3c0bb7", "0xb1c77283d01dcd1bde649b5b044eac26befc98ff57cbee379fb5b8e420134a88f2fc7f0bf04d15e1fbd45d29e7590fe6", "0xa4aa8de70330a73b2c6458f20a1067eed4b3474829b36970a8df125d53bbdda4f4a2c60063b7cccb0c80fc155527652f", "0x948a6c79ba1b8ad7e0bed2fae2f0481c4e41b4d9bbdd9b58164e28e9065700e83f210c8d5351d0212e0b0b68b345b3a5", "0x86a48c31dcbbf7b082c92d28e1f613a2378a910677d7db3a349dc089e4a1e24b12eee8e8206777a3a8c64748840b7387", "0x976adb1af21e0fc34148917cf43d933d7bfd3fd12ed6c37039dcd5a4520e3c6cf5868539ba5bf082326430deb8a4458d", "0xb93e1a4476f2c51864bb4037e7145f0635eb2827ab91732b98d49b6c07f6ac443111aa1f1da76d1888665cb897c3834e", "0x8afd46fb23bf869999fa19784b18a432a1f252d09506b8dbb756af900518d3f5f244989b3d7c823d9029218c655d3dc6", "0x83f1e59e3abeed18cdc632921672673f1cb6e330326e11c4e600e13e0d5bc11bdc970ae12952e15103a706fe720bf4d6", "0x90ce4cc660714b0b673d48010641c09c00fc92a2c596208f65c46073d7f349dd8e6e077ba7dcef9403084971c3295b76", "0x8b09b0f431a7c796561ecf1549b85048564de428dac0474522e9558b6065fede231886bc108539c104ce88ebd9b5d1b0", "0x85d6e742e2fb16a7b0ba0df64bc2c0dbff9549be691f46a6669bca05e89c884af16822b85faefefb604ec48c8705a309", "0xa87989ee231e468a712c66513746fcf03c14f103aadca0eac28e9732487deb56d7532e407953ab87a4bf8961588ef7b0", "0xb00da10efe1c29ee03c9d37d5918e391ae30e48304e294696b81b434f65cf8c8b95b9d1758c64c25e534d045ba28696f", "0x91c0e1fb49afe46c7056400baa06dbb5f6e479db78ee37e2d76c1f4e88994357e257b83b78624c4ef6091a6c0eb8254d", "0x883fb797c498297ccbf9411a3e727c3614af4eccde41619b773dc7f3259950835ee79453debf178e11dec4d3ada687a0", "0xa14703347e44eb5059070b2759297fcfcfc60e6893c0373eea069388eba3950aa06f1c57cd2c30984a2d6f9e9c92c79e", "0xafebc7585b304ceba9a769634adff35940e89cd32682c78002822aab25eec3edc29342b7f5a42a56a1fec67821172ad5", "0xaea3ff3822d09dba1425084ca95fd359718d856f6c133c5fabe2b2eed8303b6e0ba0d8698b48b93136a673baac174fd9", "0xaf2456a09aa777d9e67aa6c7c49a1845ea5cdda2e39f4c935c34a5f8280d69d4eec570446998cbbe31ede69a91e90b06", "0x82cada19fed16b891ef3442bafd49e1f07c00c2f57b2492dd4ee36af2bd6fd877d6cb41188a4d6ce9ec8d48e8133d697", "0x82a21034c832287f616619a37c122cee265cc34ae75e881fcaea4ea7f689f3c2bc8150bbf7dbcfd123522bfb7f7b1d68", "0x86877217105f5d0ec3eeff0289fc2a70d505c9fdf7862e8159553ef60908fb1a27bdaf899381356a4ef4649072a9796c", "0x82b196e49c6e861089a427c0b4671d464e9d15555ffb90954cd0d630d7ae02eb3d98ceb529d00719c2526cd96481355a", "0xa29b41d0d43d26ce76d4358e0db2b77df11f56e389f3b084d8af70a636218bd3ac86b36a9fe46ec9058c26a490f887f7", "0xa4311c4c20c4d7dd943765099c50f2fd423e203ccfe98ff00087d205467a7873762510cac5fdce7a308913ed07991ed7", "0xb1f040fc5cc51550cb2c25cf1fd418ecdd961635a11f365515f0cb4ffb31da71f48128c233e9cc7c0cf3978d757ec84e", "0xa9ebae46f86d3bd543c5f207ed0d1aed94b8375dc991161d7a271f01592912072e083e2daf30c146430894e37325a1b9", "0x826418c8e17ad902b5fe88736323a47e0ca7a44bce4cbe27846ec8fe81de1e8942455dda6d30e192cdcc73e11df31256", "0x85199db563427c5edcbac21f3d39fec2357be91fb571982ddcdc4646b446ad5ced84410de008cb47b3477ee0d532daf8", "0xb7eed9cd400b2ca12bf1d9ae008214b8561fb09c8ad9ff959e626ffde00fee5ff2f5b6612e231f2a1a9b1646fcc575e3", "0x8b40bf12501dcbac78f5a314941326bfcddf7907c83d8d887d0bb149207f85d80cd4dfbd7935439ea7b14ea39a3fded7", "0x83e3041af302485399ba6cd5120e17af61043977083887e8d26b15feec4a6b11171ac5c06e6ad0971d4b58a81ff12af3", "0x8f5b9a0eecc589dbf8c35a65d5e996a659277ef6ea509739c0cb7b3e2da9895e8c8012de662e5b23c5fa85d4a8f48904", "0x835d71ed5e919d89d8e6455f234f3ff215462c4e3720c371ac8c75e83b19dfe3ae15a81547e4dc1138e5f5997f413cc9", "0x8b7d2e4614716b1db18e9370176ea483e6abe8acdcc3dcdf5fb1f4d22ca55d652feebdccc171c6de38398d9f7bfdec7a", "0x93eace72036fe57d019676a02acf3d224cf376f166658c1bf705db4f24295881d477d6fdd7916efcfceff8c7a063deda", "0xb1ac460b3d516879a84bc886c54f020a9d799e7c49af3e4d7de5bf0d2793c852254c5d8fe5616147e6659512e5ccb012", "0xacd0947a35cb167a48bcd9667620464b54ac0e78f9316b4aa92dcaab5422d7a732087e52e1c827faa847c6b2fe6e7766", "0x94ac33d21c3d12ff762d32557860e911cd94d666609ddcc42161b9c16f28d24a526e8b10bb03137257a92cec25ae637d", "0x832e02058b6b994eadd8702921486241f9a19e68ed1406dad545e000a491ae510f525ccf9d10a4bba91c68f2c53a0f58", "0x9471035d14f78ff8f463b9901dd476b587bb07225c351161915c2e9c6114c3c78a501379ab6fb4eb03194c457cbd22bf", "0xab64593e034c6241d357fcbc32d8ea5593445a5e7c24cac81ad12bd2ef01843d477a36dc1ba21dbe63b440750d72096a", "0x9850f3b30045e927ad3ec4123a32ed2eb4c911f572b6abb79121873f91016f0d80268de8b12e2093a4904f6e6cab7642", "0x987212c36b4722fe2e54fa30c52b1e54474439f9f35ca6ad33c5130cd305b8b54b532dd80ffd2c274105f20ce6d79f6e", "0x8b4d0c6abcb239b5ed47bef63bc17efe558a27462c8208fa652b056e9eae9665787cd1aee34fbb55beb045c8bfdb882b", "0xa9f3483c6fee2fe41312d89dd4355d5b2193ac413258993805c5cbbf0a59221f879386d3e7a28e73014f10e65dd503d9", "0xa2225da3119b9b7c83d514b9f3aeb9a6d9e32d9cbf9309cbb971fd53c4b2c001d10d880a8ad8a7c281b21d85ceca0b7c", "0xa050be52e54e676c151f7a54453bbb707232f849beab4f3bf504b4d620f59ed214409d7c2bd3000f3ff13184ccda1c35", "0xadbccf681e15b3edb6455a68d292b0a1d0f5a4cb135613f5e6db9943f02181341d5755875db6ee474e19ace1c0634a28", "0x8b6eff675632a6fad0111ec72aacc61c7387380eb87933fd1d098856387d418bd38e77d897e65d6fe35951d0627c550b", "0xaabe2328ddf90989b15e409b91ef055cb02757d34987849ae6d60bef2c902bf8251ed21ab30acf39e500d1d511e90845", "0x92ba4eb1f796bc3d8b03515f65c045b66e2734c2da3fc507fdd9d6b5d1e19ab3893726816a32141db7a31099ca817d96", "0x8a98b3cf353138a1810beb60e946183803ef1d39ac4ea92f5a1e03060d35a4774a6e52b14ead54f6794d5f4022b8685c", "0x909f8a5c13ec4a59b649ed3bee9f5d13b21d7f3e2636fd2bb3413c0646573fdf9243d63083356f12f5147545339fcd55", "0x9359d914d1267633141328ed0790d81c695fea3ddd2d406c0df3d81d0c64931cf316fe4d92f4353c99ff63e2aefc4e34", "0xb88302031681b54415fe8fbfa161c032ea345c6af63d2fb8ad97615103fd4d4281c5a9cae5b0794c4657b97571a81d3b", "0x992c80192a519038082446b1fb947323005b275e25f2c14c33cc7269e0ec038581cc43705894f94bad62ae33a8b7f965", "0xa78253e3e3eece124bef84a0a8807ce76573509f6861d0b6f70d0aa35a30a123a9da5e01e84969708c40b0669eb70aa6", "0x8d5724de45270ca91c94792e8584e676547d7ac1ac816a6bb9982ee854eb5df071d20545cdfd3771cd40f90e5ba04c8e", "0x825a6f586726c68d45f00ad0f5a4436523317939a47713f78fd4fe81cd74236fdac1b04ecd97c2d0267d6f4981d7beb1" ], "g2_monomial": [ "0x93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8", "0xb5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2", "0xb5337ba0ce5d37224290916e268e2060e5c14f3f9fc9e1ec3af5a958e7a0303122500ce18f1a4640bf66525bd10e763501fe986d86649d8d45143c08c3209db3411802c226e9fe9a55716ac4a0c14f9dcef9e70b2bb309553880dc5025eab3cc", "0xb3c1dcdc1f62046c786f0b82242ef283e7ed8f5626f72542aa2c7a40f14d9094dd1ebdbd7457ffdcdac45fd7da7e16c51200b06d791e5e43e257e45efdf0bd5b06cd2333beca2a3a84354eb48662d83aef5ecf4e67658c851c10b13d8d87c874", "0x954d91c7688983382609fca9e211e461f488a5971fd4e40d7e2892037268eacdfd495cfa0a7ed6eb0eb11ac3ae6f651716757e7526abe1e06c64649d80996fd3105c20c4c94bc2b22d97045356fe9d791f21ea6428ac48db6f9e68e30d875280", "0x88a6b6bb26c51cf9812260795523973bb90ce80f6820b6c9048ab366f0fb96e48437a7f7cb62aedf64b11eb4dfefebb0147608793133d32003cb1f2dc47b13b5ff45f1bb1b2408ea45770a08dbfaec60961acb8119c47b139a13b8641e2c9487", "0x85cd7be9728bd925d12f47fb04b32d9fad7cab88788b559f053e69ca18e463113ecc8bbb6dbfb024835f901b3a957d3108d6770fb26d4c8be0a9a619f6e3a4bf15cbfd48e61593490885f6cee30e4300c5f9cf5e1c08e60a2d5b023ee94fcad0", "0x80477dba360f04399821a48ca388c0fa81102dd15687fea792ee8c1114e00d1bc4839ad37ac58900a118d863723acfbe08126ea883be87f50e4eabe3b5e72f5d9e041db8d9b186409fd4df4a7dde38c0e0a3b1ae29b098e5697e7f110b6b27e4", "0xb7a6aec08715a9f8672a2b8c367e407be37e59514ac19dd4f0942a68007bba3923df22da48702c63c0d6b3efd3c2d04e0fe042d8b5a54d562f9f33afc4865dcbcc16e99029e25925580e87920c399e710d438ac1ce3a6dc9b0d76c064a01f6f7", "0xac1b001edcea02c8258aeffbf9203114c1c874ad88dae1184fadd7d94cd09053649efd0ca413400e6e9b5fa4eac33261000af88b6bd0d2abf877a4f0355d2fb4d6007adb181695201c5432e50b850b51b3969f893bddf82126c5a71b042b7686", "0x90043fda4de53fb364fab2c04be5296c215599105ecff0c12e4917c549257125775c29f2507124d15f56e30447f367db0596c33237242c02d83dfd058735f1e3c1ff99069af55773b6d51d32a68bf75763f59ec4ee7267932ae426522b8aaab6", "0xa8660ce853e9dc08271bf882e29cd53397d63b739584dda5263da4c7cc1878d0cf6f3e403557885f557e184700575fee016ee8542dec22c97befe1d10f414d22e84560741cdb3e74c30dda9b42eeaaf53e27822de2ee06e24e912bf764a9a533", "0x8fe3921a96d0d065e8aa8fce9aa42c8e1461ca0470688c137be89396dd05103606dab6cdd2a4591efd6addf72026c12e065da7be276dee27a7e30afa2bd81c18f1516e7f068f324d0bad9570b95f6bd02c727cd2343e26db0887c3e4e26dceda", "0x8ae1ad97dcb9c192c9a3933541b40447d1dc4eebf380151440bbaae1e120cc5cdf1bcea55180b128d8e180e3af623815191d063cc0d7a47d55fb7687b9d87040bf7bc1a7546b07c61db5ccf1841372d7c2fe4a5431ffff829f3c2eb590b0b710", "0x8c2fa96870a88150f7876c931e2d3cc2adeaaaf5c73ef5fa1cf9dfa0991ae4819f9321af7e916e5057d87338e630a2f21242c29d76963cf26035b548d2a63d8ad7bd6efefa01c1df502cbdfdfe0334fb21ceb9f686887440f713bf17a89b8081", "0xb9aa98e2f02bb616e22ee5dd74c7d1049321ac9214d093a738159850a1dbcc7138cb8d26ce09d8296368fd5b291d74fa17ac7cc1b80840fdd4ee35e111501e3fa8485b508baecda7c1ab7bd703872b7d64a2a40b3210b6a70e8a6ffe0e5127e3", "0x9292db67f8771cdc86854a3f614a73805bf3012b48f1541e704ea4015d2b6b9c9aaed36419769c87c49f9e3165f03edb159c23b3a49c4390951f78e1d9b0ad997129b17cdb57ea1a6638794c0cca7d239f229e589c5ae4f9fe6979f7f8cba1d7", "0x91cd9e86550f230d128664f7312591fee6a84c34f5fc7aed557bcf986a409a6de722c4330453a305f06911d2728626e611acfdf81284f77f60a3a1595053a9479964fd713117e27c0222cc679674b03bc8001501aaf9b506196c56de29429b46", "0xa9516b73f605cc31b89c68b7675dc451e6364595243d235339437f556cf22d745d4250c1376182273be2d99e02c10eee047410a43eff634d051aeb784e76cb3605d8e079b9eb6ad1957dfdf77e1cd32ce4a573c9dfcc207ca65af6eb187f6c3d", "0xa9667271f7d191935cc8ad59ef3ec50229945faea85bfdfb0d582090f524436b348aaa0183b16a6231c00332fdac2826125b8c857a2ed9ec66821cfe02b3a2279be2412441bc2e369b255eb98614e4be8490799c4df22f18d47d24ec70bba5f7", "0xa4371144d2aa44d70d3cb9789096d3aa411149a6f800cb46f506461ee8363c8724667974252f28aea61b6030c05930ac039c1ee64bb4bd56532a685cae182bf2ab935eee34718cffcb46cae214c77aaca11dbb1320faf23c47247db1da04d8dc", "0x89a7eb441892260b7e81168c386899cd84ffc4a2c5cad2eae0d1ab9e8b5524662e6f660fe3f8bfe4c92f60b060811bc605b14c5631d16709266886d7885a5eb5930097127ec6fb2ebbaf2df65909cf48f253b3d5e22ae48d3e9a2fd2b01f447e", "0x9648c42ca97665b5eccb49580d8532df05eb5a68db07f391a2340769b55119eaf4c52fe4f650c09250fa78a76c3a1e271799b8333cc2628e3d4b4a6a3e03da1f771ecf6516dd63236574a7864ff07e319a6f11f153406280d63af9e2b5713283", "0x9663bf6dd446ea7a90658ee458578d4196dc0b175ef7fcfa75f44d41670850774c2e46c5a6be132a2c072a3c0180a24f0305d1acac49d2d79878e5cda80c57feda3d01a6af12e78b5874e2a4b3717f11c97503b41a4474e2e95b179113726199", "0xb212aeb4814e0915b432711b317923ed2b09e076aaf558c3ae8ef83f9e15a83f9ea3f47805b2750ab9e8106cb4dc6ad003522c84b03dc02829978a097899c773f6fb31f7fe6b8f2d836d96580f216fec20158f1590c3e0d7850622e15194db05", "0x925f005059bf07e9ceccbe66c711b048e236ade775720d0fe479aebe6e23e8af281225ad18e62458dc1b03b42ad4ca290d4aa176260604a7aad0d9791337006fbdebe23746f8060d42876f45e4c83c3643931392fde1cd13ff8bddf8111ef974", "0x9553edb22b4330c568e156a59ef03b26f5c326424f830fe3e8c0b602f08c124730ffc40bc745bec1a22417adb22a1a960243a10565c2be3066bfdb841d1cd14c624cd06e0008f4beb83f972ce6182a303bee3fcbcabc6cfe48ec5ae4b7941bfc", "0x935f5a404f0a78bdcce709899eda0631169b366a669e9b58eacbbd86d7b5016d044b8dfc59ce7ed8de743ae16c2343b50e2f925e88ba6319e33c3fc76b314043abad7813677b4615c8a97eb83cc79de4fedf6ccbcfa4d4cbf759a5a84e4d9742", "0xa5b014ab936eb4be113204490e8b61cd38d71da0dec7215125bcd131bf3ab22d0a32ce645bca93e7b3637cf0c2db3d6601a0ddd330dc46f9fae82abe864ffc12d656c88eb50c20782e5bb6f75d18760666f43943abb644b881639083e122f557", "0x935b7298ae52862fa22bf03bfc1795b34c70b181679ae27de08a9f5b4b884f824ef1b276b7600efa0d2f1d79e4a470d51692fd565c5cf8343dd80e5d3336968fc21c09ba9348590f6206d4424eb229e767547daefa98bc3aa9f421158dee3f2a", "0x9830f92446e708a8f6b091cc3c38b653505414f8b6507504010a96ffda3bcf763d5331eb749301e2a1437f00e2415efb01b799ad4c03f4b02de077569626255ac1165f96ea408915d4cf7955047620da573e5c439671d1fa5c833fb11de7afe6", "0x840dcc44f673fff3e387af2bb41e89640f2a70bcd2b92544876daa92143f67c7512faf5f90a04b7191de01f3e2b1bde00622a20dc62ca23bbbfaa6ad220613deff43908382642d4d6a86999f662efd64b1df448b68c847cfa87630a3ffd2ec76", "0x92950c895ed54f7f876b2fda17ecc9c41b7accfbdd42c210cc5b475e0737a7279f558148531b5c916e310604a1de25a80940c94fe5389ae5d6a5e9c371be67bceea1877f5401725a6595bcf77ece60905151b6dfcb68b75ed2e708c73632f4fd", "0x8010246bf8e94c25fd029b346b5fbadb404ef6f44a58fd9dd75acf62433d8cc6db66974f139a76e0c26dddc1f329a88214dbb63276516cf325c7869e855d07e0852d622c332ac55609ba1ec9258c45746a2aeb1af0800141ee011da80af175d4", "0xb0f1bad257ebd187bdc3f37b23f33c6a5d6a8e1f2de586080d6ada19087b0e2bf23b79c1b6da1ee82271323f5bdf3e1b018586b54a5b92ab6a1a16bb3315190a3584a05e6c37d5ca1e05d702b9869e27f513472bcdd00f4d0502a107773097da", "0x9636d24f1ede773ce919f309448dd7ce023f424afd6b4b69cb98c2a988d849a283646dc3e469879daa1b1edae91ae41f009887518e7eb5578f88469321117303cd3ac2d7aee4d9cb5f82ab9ae3458e796dfe7c24284b05815acfcaa270ff22e2", "0xb373feb5d7012fd60578d7d00834c5c81df2a23d42794fed91aa9535a4771fde0341c4da882261785e0caca40bf83405143085e7f17e55b64f6c5c809680c20b050409bf3702c574769127c854d27388b144b05624a0e24a1cbcc4d08467005b", "0xb15680648949ce69f82526e9b67d9b55ce5c537dc6ab7f3089091a9a19a6b90df7656794f6edc87fb387d21573ffc847062623685931c2790a508cbc8c6b231dd2c34f4d37d4706237b1407673605a604bcf6a50cc0b1a2db20485e22b02c17e", "0x8817e46672d40c8f748081567b038a3165f87994788ec77ee8daea8587f5540df3422f9e120e94339be67f186f50952504cb44f61e30a5241f1827e501b2de53c4c64473bcc79ab887dd277f282fbfe47997a930dd140ac08b03efac88d81075", "0xa6e4ef6c1d1098f95aae119905f87eb49b909d17f9c41bcfe51127aa25fee20782ea884a7fdf7d5e9c245b5a5b32230b07e0dbf7c6743bf52ee20e2acc0b269422bd6cf3c07115df4aa85b11b2c16630a07c974492d9cdd0ec325a3fabd95044", "0x8634aa7c3d00e7f17150009698ce440d8e1b0f13042b624a722ace68ead870c3d2212fbee549a2c190e384d7d6ac37ce14ab962c299ea1218ef1b1489c98906c91323b94c587f1d205a6edd5e9d05b42d591c26494a6f6a029a2aadb5f8b6f67", "0x821a58092900bdb73decf48e13e7a5012a3f88b06288a97b855ef51306406e7d867d613d9ec738ebacfa6db344b677d21509d93f3b55c2ebf3a2f2a6356f875150554c6fff52e62e3e46f7859be971bf7dd9d5b3e1d799749c8a97c2e04325df", "0x8dba356577a3a388f782e90edb1a7f3619759f4de314ad5d95c7cc6e197211446819c4955f99c5fc67f79450d2934e3c09adefc91b724887e005c5190362245eec48ce117d0a94d6fa6db12eda4ba8dde608fbbd0051f54dcf3bb057adfb2493", "0xa32a690dc95c23ed9fb46443d9b7d4c2e27053a7fcc216d2b0020a8cf279729c46114d2cda5772fd60a97016a07d6c5a0a7eb085a18307d34194596f5b541cdf01b2ceb31d62d6b55515acfd2b9eec92b27d082fbc4dc59fc63b551eccdb8468", "0xa040f7f4be67eaf0a1d658a3175d65df21a7dbde99bfa893469b9b43b9d150fc2e333148b1cb88cfd0447d88fa1a501d126987e9fdccb2852ecf1ba907c2ca3d6f97b055e354a9789854a64ecc8c2e928382cf09dda9abde42bbdf92280cdd96", "0x864baff97fa60164f91f334e0c9be00a152a416556b462f96d7c43b59fe1ebaff42f0471d0bf264976f8aa6431176eb905bd875024cf4f76c13a70bede51dc3e47e10b9d5652d30d2663b3af3f08d5d11b9709a0321aba371d2ef13174dcfcaf", "0x95a46f32c994133ecc22db49bad2c36a281d6b574c83cfee6680b8c8100466ca034b815cfaedfbf54f4e75188e661df901abd089524e1e0eb0bf48d48caa9dd97482d2e8c1253e7e8ac250a32fd066d5b5cb08a8641bdd64ecfa48289dca83a3", "0xa2cce2be4d12144138cb91066e0cd0542c80b478bf467867ebef9ddaf3bd64e918294043500bf5a9f45ee089a8d6ace917108d9ce9e4f41e7e860cbce19ac52e791db3b6dde1c4b0367377b581f999f340e1d6814d724edc94cb07f9c4730774", "0xb145f203eee1ac0a1a1731113ffa7a8b0b694ef2312dabc4d431660f5e0645ef5838e3e624cfe1228cfa248d48b5760501f93e6ab13d3159fc241427116c4b90359599a4cb0a86d0bb9190aa7fabff482c812db966fd2ce0a1b48cb8ac8b3bca", "0xadabe5d215c608696e03861cbd5f7401869c756b3a5aadc55f41745ad9478145d44393fec8bb6dfc4ad9236dc62b9ada0f7ca57fe2bae1b71565dbf9536d33a68b8e2090b233422313cc96afc7f1f7e0907dc7787806671541d6de8ce47c4cd0", "0xae7845fa6b06db53201c1080e01e629781817f421f28956589c6df3091ec33754f8a4bd4647a6bb1c141ac22731e3c1014865d13f3ed538dcb0f7b7576435133d9d03be655f8fbb4c9f7d83e06d1210aedd45128c2b0c9bab45a9ddde1c862a5", "0x9159eaa826a24adfa7adf6e8d2832120ebb6eccbeb3d0459ffdc338548813a2d239d22b26451fda98cc0c204d8e1ac69150b5498e0be3045300e789bcb4e210d5cd431da4bdd915a21f407ea296c20c96608ded0b70d07188e96e6c1a7b9b86b", "0xa9fc6281e2d54b46458ef564ffaed6944bff71e389d0acc11fa35d3fcd8e10c1066e0dde5b9b6516f691bb478e81c6b20865281104dcb640e29dc116daae2e884f1fe6730d639dbe0e19a532be4fb337bf52ae8408446deb393d224eee7cfa50", "0x84291a42f991bfb36358eedead3699d9176a38f6f63757742fdbb7f631f2c70178b1aedef4912fed7b6cf27e88ddc7eb0e2a6aa4b999f3eb4b662b93f386c8d78e9ac9929e21f4c5e63b12991fcde93aa64a735b75b535e730ff8dd2abb16e04", "0xa1b7fcacae181495d91765dfddf26581e8e39421579c9cbd0dd27a40ea4c54af3444a36bf85a11dda2114246eaddbdd619397424bb1eb41b5a15004b902a590ede5742cd850cf312555be24d2df8becf48f5afba5a8cd087cb7be0a521728386", "0x92feaaf540dbd84719a4889a87cdd125b7e995a6782911931fef26da9afcfbe6f86aaf5328fe1f77631491ce6239c5470f44c7791506c6ef1626803a5794e76d2be0af92f7052c29ac6264b7b9b51f267ad820afc6f881460521428496c6a5f1", "0xa525c925bfae1b89320a5054acc1fa11820f73d0cf28d273092b305467b2831fab53b6daf75fb926f332782d50e2522a19edcd85be5eb72f1497193c952d8cd0bcc5d43b39363b206eae4cb1e61668bde28a3fb2fc1e0d3d113f6dfadb799717", "0x98752bb6f5a44213f40eda6aa4ff124057c1b13b6529ab42fe575b9afa66e59b9c0ed563fb20dff62130c436c3e905ee17dd8433ba02c445b1d67182ab6504a90bbe12c26a754bbf734665c622f76c62fe2e11dd43ce04fd2b91a8463679058b", "0xa9aa9a84729f7c44219ff9e00e651e50ddea3735ef2a73fdf8ed8cd271961d8ed7af5cd724b713a89a097a3fe65a3c0202f69458a8b4c157c62a85668b12fc0d3957774bc9b35f86c184dd03bfefd5c325da717d74192cc9751c2073fe9d170e", "0xb221c1fd335a4362eff504cd95145f122bf93ea02ae162a3fb39c75583fc13a932d26050e164da97cff3e91f9a7f6ff80302c19dd1916f24acf6b93b62f36e9665a8785413b0c7d930c7f1668549910f849bca319b00e59dd01e5dec8d2edacc", "0xa71e2b1e0b16d754b848f05eda90f67bedab37709550171551050c94efba0bfc282f72aeaaa1f0330041461f5e6aa4d11537237e955e1609a469d38ed17f5c2a35a1752f546db89bfeff9eab78ec944266f1cb94c1db3334ab48df716ce408ef", "0xb990ae72768779ba0b2e66df4dd29b3dbd00f901c23b2b4a53419226ef9232acedeb498b0d0687c463e3f1eead58b20b09efcefa566fbfdfe1c6e48d32367936142d0a734143e5e63cdf86be7457723535b787a9cfcfa32fe1d61ad5a2617220", "0x8d27e7fbff77d5b9b9bbc864d5231fecf817238a6433db668d5a62a2c1ee1e5694fdd90c3293c06cc0cb15f7cbeab44d0d42be632cb9ff41fc3f6628b4b62897797d7b56126d65b694dcf3e298e3561ac8813fbd7296593ced33850426df42db", "0xa92039a08b5502d5b211a7744099c9f93fa8c90cedcb1d05e92f01886219dd464eb5fb0337496ad96ed09c987da4e5f019035c5b01cc09b2a18b8a8dd419bc5895388a07e26958f6bd26751929c25f89b8eb4a299d822e2d26fec9ef350e0d3c", "0x92dcc5a1c8c3e1b28b1524e3dd6dbecd63017c9201da9dbe077f1b82adc08c50169f56fc7b5a3b28ec6b89254de3e2fd12838a761053437883c3e01ba616670cea843754548ef84bcc397de2369adcca2ab54cd73c55dc68d87aec3fc2fe4f10" ] } ================================================ FILE: testing/networks/80069/spec.toml ================================================ # Bepolia Chain Spec Configuration # Gwei value constants max-effective-balance = 10_000_000_000_000_000 effective-balance-increment = 10_000_000_000_000 # Hysteresis parameters hysteresis-quotient = 4 hysteresis-downward-multiplier = 1 hysteresis-upward-multiplier = 5 # Time parameters slots-per-epoch = 192 slots-per-historical-root = 8 min-epochs-to-inactivity-penalty = 4 # Signature domains (each will be interpreted as a numeric value) domain-type-beacon-proposer = 0 domain-type-beacon-attester = 1 domain-type-randao = 2 domain-type-deposit = 3 domain-type-voluntary-exit = 4 domain-type-selection-proof = 5 domain-type-aggregate-and-proof = 6 domain-type-application-mask = 16777216 # Eth1-related values deposit-contract-address = "0x4242424242424242424242424242424242424242" max-deposits-per-block = 16 deposit-eth1-chain-id = 80069 eth1-follow-distance = 1 target-seconds-per-eth1-block = 2 # Fork-related values genesis-time = 1_739_976_735 deneb-one-fork-time = 1_740_090_694 electra-fork-time = 1_746_633_600 electra-one-fork-time = 1_754_496_000 fulu-fork-time = 9_999_999_999_999_999 # State list lengths epochs-per-historical-vector = 8 epochs-per-slashings-vector = 8 historical-roots-limit = 8 validator-registry-limit = 1_099_511_627_776 # Capella values max-withdrawals-per-payload = 16 max-validators-per-withdrawals-sweep = 31 # Deneb values min-epochs-for-blobs-sidecars-request = 4096 max-blob-commitments-per-block = 4096 max-blobs-per-block = 6 field-elements-per-blob = 4096 bytes-per-blob = 131072 # Berachain genesis values validator-set-cap = 69 evm-inflation-address = "0x0000000000000000000000000000000000000000" evm-inflation-per-block = 0 # Deneb1 value changes evm-inflation-address-deneb-one = "0x656b95E550C07a9ffe548bd4085c72418Ceb1dba" evm-inflation-per-block-deneb-one = 5_750_000_000 # Electra values min-activation-balance = 250_000_000_000_000 min-validator-withdrawability-delay = 256 # Fulu values (BRIP-0008 hysteresis + PoL vNext -- TODO: update values) hysteresis-quotient-fulu = 100 hysteresis-upward-multiplier-fulu = 10 evm-inflation-address-fulu = "0x0000000000000000000000000000000000000000" evm-inflation-per-block-fulu = 0 [block-delay-configuration] max-block-delay = 300_000_000_000 target-block-time = 2_000_000_000 const-block-delay = 500_000_000 consensus-update-height = 7_768_334 consensus-enable-height = 7_768_335 ================================================ FILE: testing/networks/80094/app.toml ================================================ # This is a TOML config file. # For more information, see https://github.com/toml-lang/toml ############################################################################### ### Base Configuration ### ############################################################################### # default: the last 362880 states are kept, pruning at 10 block intervals # nothing: all historic states will be saved, nothing will be deleted (i.e. archiving node) # everything: 2 latest states will be kept; pruning at 10 block intervals. # custom: allow pruning options to be manually specified through 'pruning-keep-recent', and 'pruning-interval' pruning = "everything" # These are applied if and only if the pruning strategy is custom. pruning-keep-recent = "0" pruning-interval = "0" # HaltHeight contains a non-zero block height at which a node will gracefully # halt and shutdown that can be used to assist upgrades and testing. # # Note: Commitment of state will be attempted on the corresponding block. halt-height = 0 # HaltTime contains a non-zero minimum block time (in Unix seconds) at which # a node will gracefully halt and shutdown that can be used to assist upgrades # and testing. # # Note: Commitment of state will be attempted on the corresponding block. halt-time = 0 # MinRetainBlocks defines the minimum block height offset from the current # block being committed, such that all blocks past this offset are pruned # from CometBFT. It is used as part of the process of determining the # ResponseCommit.RetainHeight value during ABCI Commit. A value of 0 indicates # that no blocks should be pruned. # # This configuration value is only responsible for pruning CometBFT blocks. # It has no bearing on application state pruning which is determined by the # "pruning-*" configurations. # # Note: CometBFT block pruning is dependant on this parameter in conjunction # with the unbonding (safety threshold) period, state pruning and state sync # snapshot parameters to determine the correct minimum value of # ResponseCommit.RetainHeight. min-retain-blocks = 0 # InterBlockCache enables inter-block caching. inter-block-cache = true # IndexEvents defines the set of events in the form {eventType}.{attributeKey}, # which informs CometBFT what to index. If empty, all events will be indexed. # # Example: # ["message.sender", "message.recipient"] index-events = [] # IavlCacheSize set the size of the iavl tree cache (in number of nodes). iavl-cache-size = 781250 # IAVLDisableFastNode enables or disables the fast node feature of IAVL. # Default is false. iavl-disable-fastnode = true # AppDBBackend defines the database backend type to use for the application and snapshots DBs. # An empty string indicates that a fallback will be used. # The fallback is the db_backend value set in CometBFT's config.toml. app-db-backend = "pebbledb" ############################################################################### ### Telemetry Configuration ### ############################################################################### [telemetry] # Prefixed with keys to separate services. service-name = "beacond_node" # Enabled enables the application telemetry functionality. When enabled, # an in-memory sink is also enabled by default. Operators may also enabled # other sinks such as Prometheus. enabled = true # Enable prefixing gauge values with hostname. enable-hostname = true # Enable adding hostname to labels. enable-hostname-label = true # Enable adding service to labels. enable-service-label = true # PrometheusRetentionTime, when positive, enables a Prometheus metrics sink. prometheus-retention-time = 60 # GlobalLabels defines a global set of name/value label tuples applied to all # metrics emitted using the wrapper functions defined in telemetry package. # # Example: # [["chain_id", "cosmoshub-1"]] global-labels = [] # MetricsSink defines the type of metrics sink to use. metrics-sink = "" # StatsdAddr defines the address of a statsd server to send metrics to. # Only utilized if MetricsSink is set to "statsd" or "dogstatsd". statsd-addr = "" # DatadogHostname defines the hostname to use when emitting metrics to # Datadog. Only utilized if MetricsSink is set to "dogstatsd". datadog-hostname = "my_beacond_node" ############################################################################### ### BeaconKit ### ############################################################################### [beacon-kit] # ChainSpec is the type of chain spec to use. chain-spec = "mainnet" # ChainSpecFilePath is the path to the chain spec file to use. chain-spec-file = "" # ShutdownTimeout is the maximum time to wait for the node to gracefully # shutdown before forcing an exit. shutdown-timeout = "5m0s" [beacon-kit.engine] # HTTP url of the execution client JSON-RPC endpoint. rpc-dial-url = "http://localhost:8551" # RPC timeout for execution client requests. rpc-timeout = "2s" # RPC retry interval for execution client requests. rpc-retry-interval = "100ms" # RPC max retry interval for execution client requests. rpc-max-retry-interval = "10s" # Interval for the startup check. rpc-startup-check-interval = "3s" # Interval for the JWT refresh. rpc-jwt-refresh-interval = "30s" # Path to the execution client JWT-secret jwt-secret-path = "~/.beacond/config/jwt.hex" [beacon-kit.logger] # TimeFormat is a string that defines the format of the time in the logger. time-format = "RFC3339" # LogLevel is the level of logging. Logger will log messages with verbosity up # to LogLevel. log-level = "info" # Style is the style of the logger. style = "pretty" [beacon-kit.kzg] # Path to the trusted setup path. trusted-setup-path = "~/.beacond/config/kzg-trusted-setup.json" # KZG implementation to use. # Options are "crate-crypto/go-kzg-4844". implementation = "crate-crypto/go-kzg-4844" [beacon-kit.payload-builder] # Enabled determines if the local payload builder is enabled. # It should be enabled for validators, but it can be disabled # for full nodes. enabled = true # Post bellatrix, this address will receive the transaction fees produced by any blocks # from this node. suggested-fee-recipient = "0x0000000000000000000000000000000000000000" # The timeout for local build payload. This should match, or be slightly less # than the configured timeout on your execution client. It also must be less than # timeout_proposal in the CometBFT configuration. payload-timeout = "850ms" [beacon-kit.validator] # Graffiti string that will be included in the graffiti field of the beacon block. graffiti = "" # AvailabilityWindow is the number of slots to keep in the store. # Setting AvailabilityWindow to 0 disables block store and does not allow the node # to serve proof or namespace apis from beacon node-api. availability-window = "8192" [beacon-kit.node-api] # Enabled determines if the node API is enabled. enabled = "false" # Address is the address to bind the node API to. address = "0.0.0.0:3500" # Logging determines if the node API logging is enabled. logging = "false" ================================================ FILE: testing/networks/80094/client.toml ================================================ # This is a TOML config file. # For more information, see https://github.com/toml-lang/toml ############################################################################### ### Client Configuration ### ############################################################################### # The network chain ID chain-id = "mainnet-beacon-80094" # The keyring's backend, where the keys are stored (os|file|kwallet|pass|test|memory) keyring-backend = "test" # CLI output format (text|json) output = "text" # : to Tendermint RPC interface for this chain node = "tcp://localhost:26657" # Transaction broadcasting mode (sync|async) broadcast-mode = "sync" ================================================ FILE: testing/networks/80094/config.toml ================================================ # This is a TOML config file. # For more information, see https://github.com/toml-lang/toml # NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or # relative to the home directory (e.g. "data"). The home directory is # "$HOME/.cometbft" by default, but could be changed via $CMTHOME env variable # or --home cmd flag. # The version of the CometBFT binary that created or # last modified the config file. Do not modify this. version = "1.0.0" ####################################################################### ### Main Base Config Options ### ####################################################################### # TCP or UNIX socket address of the ABCI application, # or the name of an ABCI application compiled in with the CometBFT binary proxy_app = "tcp://127.0.0.1:26658" # A custom human readable name for this node moniker = "oogabooga" # Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb # * goleveldb (github.com/syndtr/goleveldb - most popular implementation) # - pure go # - stable # * cleveldb (uses levigo wrapper) # - fast # - requires gcc # - use cleveldb build tag (go build -tags cleveldb) # * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt) # - EXPERIMENTAL # - may be faster is some use-cases (random reads - indexer) # - use boltdb build tag (go build -tags boltdb) # * rocksdb (uses github.com/tecbot/gorocksdb) # - EXPERIMENTAL # - requires gcc # - use rocksdb build tag (go build -tags rocksdb) # * badgerdb (uses github.com/dgraph-io/badger) # - EXPERIMENTAL # - use badgerdb build tag (go build -tags badgerdb) db_backend = "pebbledb" # Database directory db_dir = "data" # Output level for logging, including package level options log_level = "info" # Output format: 'plain' (colored text) or 'json' log_format = "plain" ##### additional base config options ##### # Path to the JSON file containing the initial validator set and other meta data genesis_file = "config/genesis.json" # Path to the JSON file containing the private key to use as a validator in the consensus protocol priv_validator_key_file = "config/priv_validator_key.json" # Path to the JSON file containing the last sign state of a validator priv_validator_state_file = "data/priv_validator_state.json" # TCP or UNIX socket address for CometBFT to listen on for # connections from an external PrivValidator process priv_validator_laddr = "" # Path to the JSON file containing the private key to use for node authentication in the p2p protocol node_key_file = "config/node_key.json" # Mechanism to connect to the ABCI application: socket | grpc abci = "socket" # If true, query the ABCI app on connecting to a new peer # so the app can decide if we should keep the connection or not filter_peers = false ####################################################################### ### Advanced Configuration Options ### ####################################################################### ####################################################### ### RPC Server Configuration Options ### ####################################################### [rpc] # TCP or UNIX socket address for the RPC server to listen on laddr = "tcp://127.0.0.1:26657" # A list of origins a cross-domain request can be executed from # Default value '[]' disables cors support # Use '["*"]' to allow any origin cors_allowed_origins = [] # A list of methods the client is allowed to use with cross-domain requests cors_allowed_methods = ['HEAD', 'GET', 'POST'] # A list of non simple headers the client is allowed to use with cross-domain requests cors_allowed_headers = ['Origin', 'Accept', 'Content-Type', 'X-Requested-With', 'X-Server-Time'] # Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool unsafe = false # Maximum number of simultaneous connections (including WebSocket). # Does not include gRPC connections. See grpc_max_open_connections # If you want to accept a larger number than the default, make sure # you increase your OS limits. # 0 - unlimited. # Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} # 1024 - 40 - 10 - 50 = 924 = ~900 max_open_connections = 900 # Maximum number of unique clientIDs that can /subscribe # If you're using /broadcast_tx_commit, set to the estimated maximum number # of broadcast_tx_commit calls per block. max_subscription_clients = 100 # Maximum number of unique queries a given client can /subscribe to # If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to # the estimated # maximum number of broadcast_tx_commit calls per block. max_subscriptions_per_client = 5 # Experimental parameter to specify the maximum number of events a node will # buffer, per subscription, before returning an error and closing the # subscription. Must be set to at least 100, but higher values will accommodate # higher event throughput rates (and will use more memory). experimental_subscription_buffer_size = 200 # Experimental parameter to specify the maximum number of RPC responses that # can be buffered per WebSocket client. If clients cannot read from the # WebSocket endpoint fast enough, they will be disconnected, so increasing this # parameter may reduce the chances of them being disconnected (but will cause # the node to use more memory). # # Must be at least the same as "experimental_subscription_buffer_size", # otherwise connections could be dropped unnecessarily. This value should # ideally be somewhat higher than "experimental_subscription_buffer_size" to # accommodate non-subscription-related RPC responses. experimental_websocket_write_buffer_size = 200 # If a WebSocket client cannot read fast enough, at present we may # silently drop events instead of generating an error or disconnecting the # client. # # Enabling this experimental parameter will cause the WebSocket connection to # be closed instead if it cannot read fast enough, allowing for greater # predictability in subscription behavior. experimental_close_on_slow_client = false # How long to wait for a tx to be committed during /broadcast_tx_commit. # WARNING: Using a value larger than 10s will result in increasing the # global HTTP write timeout, which applies to all connections and endpoints. # See https://github.com/tendermint/tendermint/issues/3435 timeout_broadcast_tx_commit = "10s" # Maximum size of request body, in bytes max_body_bytes = 1000000 # Maximum size of request header, in bytes max_header_bytes = 1048576 # The path to a file containing certificate that is used to create the HTTPS server. # Might be either absolute path or path related to CometBFT's config directory. # If the certificate is signed by a certificate authority, # the certFile should be the concatenation of the server's certificate, any intermediates, # and the CA's certificate. # NOTE: both tls_cert_file and tls_key_file must be present for CometBFT to create HTTPS server. # Otherwise, HTTP server is run. tls_cert_file = "" # The path to a file containing matching private key that is used to create the HTTPS server. # Might be either absolute path or path related to CometBFT's config directory. # NOTE: both tls-cert-file and tls-key-file must be present for CometBFT to create HTTPS server. # Otherwise, HTTP server is run. tls_key_file = "" # pprof listen address (https://golang.org/pkg/net/http/pprof) #pprof_laddr = "0.0.0.0:6060" pprof_laddr = "" ####################################################### ### P2P Configuration Options ### ####################################################### [p2p] # Address to listen for incoming connections laddr = "tcp://0.0.0.0:26656" # Address to advertise to peers for them to dial. If empty, will use the same # port as the laddr, and will introspect on the listener to figure out the # address. IP and port are required. Example: 159.89.10.97:26656 external_address = "" # Comma separated list of seed nodes to connect to seeds = "1af8f82739bf4031302d9ec5a21508e09245a75d@34.159.172.173:26656,9551cfb45e5220e28b397da58b022841cc4fd258@35.198.184.184:26656,da82fec973bb65b2dce04f5824ce27b5510adce1@35.198.137.87:26656,6aadbeb00cde44d3fef065d58e1a59b3a211b5ca@34.141.37.10:26656,19ebee0c648cdf45b4933335b27d98f4acfa2f56@34.159.32.171:26656,7aa92c3227155390ce9a4cd0135c46a1ee9d5a80@34.159.140.231:26656,2784663b1c3fa2984b18cba3cffcd9af6c6ecef5@35.203.60.135:26656,157a420b52213bdc6f8169f2a3283b43d4851a23@34.118.176.138:26656,7b525992c6d6a882aeba3e7a6659c47549d46654@35.203.45.113:26656,ce5a29ac97e0ceb3a255cb991775fbfde80c52a3@34.47.19.7:26656,2bce8d3a4cd4b67b00d9595d38c4929fab76ada5@34.95.41.91:26656,c6b73f0a3621ac84c8b56af643134bea6d8acc72@34.47.62.196:26656,90071ab5ecc7c83e974bc2cc32739926d9b8a34d@34.95.19.199:26656,6f121dafe50e3c9bd9716a950e70ded165e686a9@34.95.32.61:26656,335a9a6b41338fb4dd6f819e7525c2316a33d593@64.34.94.91:26656,44aaf5938d5d06f42722ed73f41403620fbdc77d@64.34.94.87:26656" # Comma separated list of nodes to keep persistent connections to persistent_peers = "" # Path to address book addr_book_file = "config/addrbook.json" # Set true for strict address routability rules # Set false for private or local networks addr_book_strict = true # Maximum number of inbound peers max_num_inbound_peers = 40 # Maximum number of outbound peers to connect to, excluding persistent peers max_num_outbound_peers = 10 # List of node IDs, to which a connection will be (re)established ignoring any existing limits unconditional_peer_ids = "" # Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) persistent_peers_max_dial_period = "0s" # Time to wait before flushing messages out on the connection flush_throttle_timeout = "10ms" # Maximum size of a message packet payload, in bytes max_packet_msg_payload_size = 1024 # Rate at which packets can be sent, in bytes/second send_rate = 5120000 # Rate at which packets can be received, in bytes/second recv_rate = 5120000 # Set true to enable the peer-exchange reactor pex = true # Seed mode, in which node constantly crawls the network and looks for # peers. If another node asks it for addresses, it responds and disconnects. # # Does not work if the peer-exchange reactor is disabled. seed_mode = false # Comma separated list of peer IDs to keep private (will not be gossiped to other peers) private_peer_ids = "" # Toggle to disable guard against peers connecting from the same ip. allow_duplicate_ip = false # Peer connection configuration. handshake_timeout = "20s" dial_timeout = "3s" ####################################################### ### Mempool Configuration Option ### ####################################################### [mempool] # The type of mempool for this node to use. # # Possible types: # - "flood" : concurrent linked list mempool with flooding gossip protocol # (default) # - "nop" : nop-mempool (short for no operation; the ABCI app is responsible # for storing, disseminating and proposing txs). "create_empty_blocks=false" is # not supported. type = "nop" # Recheck (default: true) defines whether CometBFT should recheck the # validity for all remaining transaction in the mempool after a block. # Since a block affects the application state, some transactions in the # mempool may become invalid. If this does not apply to your application, # you can disable rechecking. recheck = false # recheck_timeout is the time the application has during the rechecking process # to return CheckTx responses, once all requests have been sent. Responses that # arrive after the timeout expires are discarded. It only applies to # non-local ABCI clients and when recheck is enabled. recheck_timeout = "0s" # Broadcast (default: true) defines whether the mempool should relay # transactions to other peers. Setting this to false will stop the mempool # from relaying transactions to other peers until they are included in a # block. In other words, if Broadcast is disabled, only the peer you send # the tx to will see it until it is included in a block. broadcast = false # WalPath (default: "") configures the location of the Write Ahead Log # (WAL) for the mempool. The WAL is disabled by default. To enable, set # WalPath to where you want the WAL to be written (e.g. # "data/mempool.wal"). wal_dir = "" # Maximum number of transactions in the mempool size = 0 # Limit the total size of all txs in the mempool. # This only accounts for raw transactions (e.g. given 1MB transactions and # max_txs_bytes=5MB, mempool will only accept 5 transactions). max_txs_bytes = 0 # Size of the cache (used to filter transactions we saw earlier) in transactions cache_size = 0 # Do not remove invalid transactions from the cache (default: false) # Set to true if it's not possible for any invalid transaction to become valid # again in the future. keep-invalid-txs-in-cache = false # Maximum size of a single transaction. # NOTE: the max size of a tx transmitted over the network is {max_tx_bytes}. max_tx_bytes = 1048576 # Maximum size of a batch of transactions to send to a peer # Including space needed by encoding (one varint per transaction). # XXX: Unused due to https://github.com/tendermint/tendermint/issues/5796 max_batch_size = 0 # Experimental parameters to limit gossiping txs to up to the specified number of peers. # We use two independent upper values for persistent and non-persistent peers. # Unconditional peers are not affected by this feature. # If we are connected to more than the specified number of persistent peers, only send txs to # ExperimentalMaxGossipConnectionsToPersistentPeers of them. If one of those # persistent peers disconnects, activate another persistent peer. # Similarly for non-persistent peers, with an upper limit of # ExperimentalMaxGossipConnectionsToNonPersistentPeers. # If set to 0, the feature is disabled for the corresponding group of peers, that is, the # number of active connections to that group of peers is not bounded. # For non-persistent peers, if enabled, a value of 10 is recommended based on experimental # performance results using the default P2P configuration. experimental_max_gossip_connections_to_persistent_peers = 0 experimental_max_gossip_connections_to_non_persistent_peers = 0 ####################################################### ### State Sync Configuration Options ### ####################################################### [statesync] # State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine # snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in # the network to take and serve state machine snapshots. State sync is not attempted if the node # has any local state (LastBlockHeight > 0). The node will have a truncated block history, # starting from the height of the snapshot. enable = false # RPC servers (comma-separated) for light client verification of the synced state machine and # retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding # header hash obtained from a trusted source, and a period during which validators can be trusted. # # For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2 # weeks) during which they can be financially punished (slashed) for misbehavior. rpc_servers = "" trust_height = 0 trust_hash = "" trust_period = "168h0m0s" # Time to spend discovering snapshots before initiating a restore. discovery_time = "15s" # Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). # Will create a new, randomly named directory within, and remove it when done. temp_dir = "" # The timeout duration before re-requesting a chunk, possibly from a different # peer (default: 1 minute). chunk_request_timeout = "10s" # The number of concurrent chunk fetchers to run (default: 1). chunk_fetchers = "4" ####################################################### ### Block Sync Configuration Options ### ####################################################### [blocksync] # Block Sync version to use: # # In v0.37, v1 and v2 of the block sync protocols were deprecated. # Please use v0 instead. # # 1) "v0" - the default block sync implementation version = "v0" ####################################################### ### Consensus Configuration Options ### ####################################################### [consensus] wal_file = "data/cs.wal/wal" # How long we wait for a proposal block before prevoting nil timeout_propose = "2s" # How much timeout_propose increases with each round timeout_propose_delta = "500ms" # How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) timeout_prevote = "2s" # How much the timeout_prevote increases with each round timeout_prevote_delta = "500ms" # How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) timeout_precommit = "2s" # How much the timeout_precommit increases with each round timeout_precommit_delta = "500ms" # How long we wait after committing a block, before starting on the new # height (this gives us a chance to receive some more precommits, even # though we already have +2/3). # Set to 0 if you want to make progress as soon as the node has all the precommits. timeout_commit = "500ms" # Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) skip_timeout_commit = false # How many blocks to look back to check existence of the node's consensus votes before joining consensus # When non-zero, the node will panic upon restart # if the same consensus key was used to sign {double_sign_check_height} last blocks. # So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. double_sign_check_height = 0 # EmptyBlocks mode and possible interval between empty blocks create_empty_blocks = true create_empty_blocks_interval = "0s" # Reactor sleep duration parameters peer_gossip_sleep_duration = "300ms" peer_gossip_intraloop_sleep_duration = "0s" peer_query_maj23_sleep_duration = "2s" ####################################################### ### Storage Configuration Options ### ####################################################### [storage] # Set to true to discard ABCI responses from the state store, which can save a # considerable amount of disk space. Set to false to ensure ABCI responses are # persisted. ABCI responses are required for /block_results RPC queries, and to # reindex events in the command-line tool. discard_abci_responses = true # The representation of keys in the database. # The current representation of keys in Comet's stores is considered to be v1 # Users can experiment with a different layout by setting this field to v2. # Note that this is an experimental feature and switching back from v2 to v1 # is not supported by CometBFT. # If the database was initially created with v1, it is necessary to migrate the DB # before switching to v2. The migration is not done automatically. # v1 - the legacy layout existing in Comet prior to v1. # v2 - Order preserving representation ordering entries by height. experimental_db_key_layout = "v1" # If set to true, CometBFT will force compaction to happen for databases that support this feature. # and save on storage space. Setting this to true is most benefits when used in combination # with pruning as it will physically delete the entries marked for deletion. # false by default (forcing compaction is disabled). compact = false # To avoid forcing compaction every time, this parameter instructs CometBFT to wait # the given amount of blocks to be pruned before triggering compaction. # It should be tuned depending on the number of items. If your retain height is 1 block, # it is too much of an overhead to try compaction every block. But it should also not be a very # large multiple of your retain height as it might occur bigger overheads. compaction_interval = "1000" [storage.pruning] # The time period between automated background pruning operations. interval = "10s" # # Storage pruning configuration relating only to the data companion. # [storage.pruning.data_companion] # Whether automatic pruning respects values set by the data companion. Disabled # by default. All other parameters in this section are ignored when this is # disabled. # # If disabled, only the application retain height will influence block pruning # (but not block results pruning). Only enabling this at a later stage will # potentially mean that blocks below the application-set retain height at the # time will not be available to the data companion. enabled = false # The initial value for the data companion block retain height if the data # companion has not yet explicitly set one. If the data companion has already # set a block retain height, this is ignored. initial_block_retain_height = 0 # The initial value for the data companion block results retain height if the # data companion has not yet explicitly set one. If the data companion has # already set a block results retain height, this is ignored. initial_block_results_retain_height = 0 ####################################################### ### Transaction Indexer Configuration Options ### ####################################################### [tx_index] # What indexer to use for transactions # # The application will set which txs to index. In some cases a node operator will be able # to decide which txs to index based on configuration set in the application. # # Options: # 1) "null" # 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). # - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. # 3) "psql" - the indexer services backed by PostgreSQL. # When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed. indexer = "null" # The PostgreSQL connection configuration, the connection format: # postgresql://:@:/? psql-conn = "" ####################################################### ### Instrumentation Configuration Options ### ####################################################### [instrumentation] # When true, Prometheus metrics are served under /metrics on # PrometheusListenAddr. # Check out the documentation for the list of available metrics. prometheus = true # Address to listen for Prometheus collector(s) connections prometheus_listen_addr = ":26660" # Maximum number of simultaneous connections. # If you want to accept a larger number than the default, make sure # you increase your OS limits. # 0 - unlimited. max_open_connections = 800 # Instrumentation namespace namespace = "cometbft" ================================================ FILE: testing/networks/80094/el-bootnodes.txt ================================================ South Korea enode://0c5a4a3c0e81fce2974e4d317d88df783731183d534325e32e0fdf8f4b119d7889fa254d3a38890606ec300d744e2aa9c87099a4a032f5c94efe53f3fcdfecfe@34.64.176.79:30303 enode://b6a3137d3a36ef37c4d31843775a9dc293f41bcbde33b6309c80b1771b6634827cd188285136a57474427bd8845adc2f6fe2e0b106bd58d14795b08910b9c326@34.64.181.70:30303 enode://0b6633300614bc2b9749aee0cace7a091ec5348762aee7b1d195f7616d03a9409019d9bef336624bab72e0d069cd4cf0b0de6fbbf53f04f6b6e4c5b39c6bdca6@34.64.39.31:30303 enode://552b001abebb5805fcd734ad367cd05d9078d18f23ec598d7165460fadcfc51116ad95c418f7ea9a141aa8cbc496c8bea3322b67a5de0d3380f11aab1a797513@34.64.183.158:30303 Singapore enode://5b037f66099d5ded86eb7e1619f6d06ceb15609e8cc345ced22a4772b06178004e1490a3cd32fd1222789de4c6e4021c2d648a3d750f6d5323e64b771bbd8de7@34.87.142.180:30303 enode://846db253c53753d3ea1197aec296306dc84c25f3afdf142b65cb0fe0f984de55072daa3bbf05a9aea046a38a2292403137b6eafefd5646fcf62120b74e3b898d@34.142.170.110:30303 enode://64b7f6ee9bcd942ad4949c70f2077627f078a057dfd930e6e904e12643d8952f5ae87c91e24559765393f244a72c9d5c011d7d5176e59191d38f315db85a20f5@34.126.161.16:30303 enode://cf4d19bfb8ec507427ec882bac0bac85a0c8c9ddaa0ec91b773bb614e5e09d107cd9fbe323b96f62f31c493f8f42cc5495c18b87c08560c5dea1dfd25256dcf6@35.247.162.2:30303 Germany enode://bb7e44178543431feac8f0ee3827056b7b84d8235b802a8bdbbcd4939dab7f7dd2579ff577a38b002bb0139792af67abd2dd5c9f4f85b8da6e914fa76dca82bc@35.198.150.35:30303 enode://8fef1f5df45e7b31be00a21e1da5665d5a5f5bf4c379086b843f03eade941bdd157f08c95b31880c492577edb9a9b185df7191eaebf54ab06d5bd683b289f3af@34.107.7.241:30303 enode://ce9c87cfe089f6811d26c96913fa3ec10b938d9017fc6246684c74a33679ee34ceca9447180fb509e37bf2b706c2877a82085d34bfd83b5b520ee1288b0fc32f@35.198.109.49:30303 enode://713657eb6a53feadcbc47e634ad557326a51eb6818a3e19a00a8111492f50a666ccbf2f5d334d247ecf941e68d242ef5c3b812b63c44d381ef11f79c2cdb45c7@34.141.15.100:30303 Canada enode://d071fa740e063ce1bb9cdc2b7937baeff6dc4000f91588d730a731c38a6ff0d4015814812c160fab8695e46f74b9b618735368ea2f16db4d785f16d29b3fb7b0@35.203.2.210:30303 enode://ffc452fe451a2e5f89fe634744aea334d92dcd30d881b76209d2db7dbf4b7ee047e7c69a5bb1633764d987a7441d9c4bc57ccdbfd6442a2f860bf953bc89a9b9@34.152.50.224:30303 enode://da94328302a1d1422209d1916744e90b6095a48b2340dcec39b22002c098bb4d58a880dab98eb26edf03fa4705d1b62f99a8c5c14e6666e4726b6d3066d8a4d7@34.95.61.106:30303 enode://19c7671a4844699b481e81a5bcfe7bafc7fefa953c16ebbe1951b1046371e73839e9058de6b7d3c934318fe7e7233dde3621c1c1018eb8b294ea3d4516147150@35.203.82.137:30303 ================================================ FILE: testing/networks/80094/el-peers.txt ================================================ enode://0c5a4a3c0e81fce2974e4d317d88df783731183d534325e32e0fdf8f4b119d7889fa254d3a38890606ec300d744e2aa9c87099a4a032f5c94efe53f3fcdfecfe@34.22.104.177:30303,enode://b6a3137d3a36ef37c4d31843775a9dc293f41bcbde33b6309c80b1771b6634827cd188285136a57474427bd8845adc2f6fe2e0b106bd58d14795b08910b9c326@34.64.247.85:30303,enode://0b6633300614bc2b9749aee0cace7a091ec5348762aee7b1d195f7616d03a9409019d9bef336624bab72e0d069cd4cf0b0de6fbbf53f04f6b6e4c5b39c6bdca6@34.22.73.21:30303,enode://552b001abebb5805fcd734ad367cd05d9078d18f23ec598d7165460fadcfc51116ad95c418f7ea9a141aa8cbc496c8bea3322b67a5de0d3380f11aab1a797513@34.64.37.55:30303,enode://5b037f66099d5ded86eb7e1619f6d06ceb15609e8cc345ced22a4772b06178004e1490a3cd32fd1222789de4c6e4021c2d648a3d750f6d5323e64b771bbd8de7@35.247.182.34:30303,enode://846db253c53753d3ea1197aec296306dc84c25f3afdf142b65cb0fe0f984de55072daa3bbf05a9aea046a38a2292403137b6eafefd5646fcf62120b74e3b898d@34.87.9.231:30303,enode://64b7f6ee9bcd942ad4949c70f2077627f078a057dfd930e6e904e12643d8952f5ae87c91e24559765393f244a72c9d5c011d7d5176e59191d38f315db85a20f5@34.126.78.49:30303,enode://cf4d19bfb8ec507427ec882bac0bac85a0c8c9ddaa0ec91b773bb614e5e09d107cd9fbe323b96f62f31c493f8f42cc5495c18b87c08560c5dea1dfd25256dcf6@35.240.200.36:30303,enode://bb7e44178543431feac8f0ee3827056b7b84d8235b802a8bdbbcd4939dab7f7dd2579ff577a38b002bb0139792af67abd2dd5c9f4f85b8da6e914fa76dca82bc@34.40.14.50:30303,enode://8fef1f5df45e7b31be00a21e1da5665d5a5f5bf4c379086b843f03eade941bdd157f08c95b31880c492577edb9a9b185df7191eaebf54ab06d5bd683b289f3af@35.246.168.217:30303,enode://ce9c87cfe089f6811d26c96913fa3ec10b938d9017fc6246684c74a33679ee34ceca9447180fb509e37bf2b706c2877a82085d34bfd83b5b520ee1288b0fc32f@34.40.28.159:30303,enode://713657eb6a53feadcbc47e634ad557326a51eb6818a3e19a00a8111492f50a666ccbf2f5d334d247ecf941e68d242ef5c3b812b63c44d381ef11f79c2cdb45c7@35.234.82.236:30303,enode://d071fa740e063ce1bb9cdc2b7937baeff6dc4000f91588d730a731c38a6ff0d4015814812c160fab8695e46f74b9b618735368ea2f16db4d785f16d29b3fb7b0@35.203.86.197:30303,enode://ffc452fe451a2e5f89fe634744aea334d92dcd30d881b76209d2db7dbf4b7ee047e7c69a5bb1633764d987a7441d9c4bc57ccdbfd6442a2f860bf953bc89a9b9@34.118.187.161:30303,enode://da94328302a1d1422209d1916744e90b6095a48b2340dcec39b22002c098bb4d58a880dab98eb26edf03fa4705d1b62f99a8c5c14e6666e4726b6d3066d8a4d7@34.95.30.190:30303,enode://19c7671a4844699b481e81a5bcfe7bafc7fefa953c16ebbe1951b1046371e73839e9058de6b7d3c934318fe7e7233dde3621c1c1018eb8b294ea3d4516147150@34.47.60.196:30303 ================================================ FILE: testing/networks/80094/eth-genesis.json ================================================ [File too large to display: 46.5 MB] ================================================ FILE: testing/networks/80094/genesis.json ================================================ { "app_name": "beacond", "app_version": "v1.0.0", "genesis_time": "2025-01-20T14:00:00Z", "chain_id": "mainnet-beacon-80094", "initial_height": 1, "app_hash": null, "app_state": { "beacon": { "fork_version": "0x04000000", "deposits": [ { "pubkey": "0x98111a6ee569f1be005551d8c76e042aabcb5bf4c491d177445a2b5fb30dedc7bf6db39e387831c6739bde4129c6ada5", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0x88a0a6b0cfa3e03b6c33684edbad9062431f5db53b7fe9322a386a335e0e3936c45e886f6bcf228d88c980423c69433e0491a74ff0be6d93657425b1f7146e654f7405a8d956a175657551a6a9e319264b5b2fbc4ad423dfe6308d0ee32411f0", "index": 0 }, { "pubkey": "0xa14fa37a1d4c65326bf091d3bb0e5607fde8946471ed923e6815077fac7282d89820dd4f8765e4085ca8247fb99ecb6b", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0xac2a43306aaad2da1ed72c4171f9b20f9d5cf3e9abffca6868dffedd5b710cd4b972cd662719fffa86870666b1b160390f671dfa22bf32987cf993ef92b72e2fff45af60438998a629037884242255567bea35be7cfe2e2a3317b2a788dc0925", "index": 1 }, { "pubkey": "0x80305831f81c688a6814ebf9d9b842e28a20b425864c480fab6f52e41541853eab39e77ca68248d096bd4d5499b24b7e", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xb0058439696ffcb4b75add47afce6d4adcc3306f16cae5fe620748bb17cf00899f71bbd348fb3cf32e06799eb435a7c60dc31b9a0179956f2cb77309594e6c3b809e999dbddcf540f7d96f58d3ec4410a847c1cd91ba63384630222d33dc8185", "index": 2 }, { "pubkey": "0x8148ddb478a291cf6a16fb98195e3076aad319ca8821b4aef69c8d1d45c8ed49d61109a1cbc029b58f22f5bb60854fe4", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0x8c76bcc35b2d7b8fdddcfba02302dedc83f1c0aa69610a3568e3445defc31abd6427d93a60b7cde09b167fffdbfbc49d1916584925214b54339fbd800323a80150bfd7209c7103cda89032232f380716331a3888795eaf5ce031b53d125b7c5a", "index": 3 }, { "pubkey": "0xa232a81b5e834b817db01d85ee13e36552b48413626287de511b6c89b7b8ff4a448e865713fd21c98f1467a58fe6efe5", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xa3073a0c3f7db231f284cc144b96b53134a5a58e5f72de8d44547ea6e95fc948842963a9dac97b1418e4951e7a7ef8ae0a8b8556c87fef0e29f92b809f20fea424806ef6d2658f357175d1049c2802f233de3f5b9265a1166e8174f1880890c1", "index": 4 }, { "pubkey": "0xa247c21f73c3327f31f8ee0dbb40110ef0a830af89b83986dddf92d1bd1a68b88f9050bc6a0f1405cb75fbb457e3e83b", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0x95930ca76ed1b79a3c7a41d2521efb2d196944b8af0714b35df77a2d55d56a75868d160eea040cad7badc6aab0901bee178e8c26f3d5509fc10c5fbb7bd5d20693e20c5f9f3c817d06f64284abce34f6c11d7ffe2632b7582a7cec569325662b", "index": 5 }, { "pubkey": "0x832153bf3e09b9cab14414425a0ebaeb889e21d20872ebb990ed9a6102d7dc7f3017d4689f931a8e96d918bdeb184e1b", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0x8b9c2cd08c7ea88d6535e7c8dc4d62ba5e4e58049424e79724f5365b8adce2b338e2ec6e6510570e7b9951838975da49189f37ffc3752d906ff14a9b659f05f13188fd34ac0bdb4d24e408ff3dac8e09652099f6b2c76ed4bebb2d9b944d2bc5", "index": 6 }, { "pubkey": "0xa3539ca28e0fd74d2a3c4c552740be77d6914cad2d8ec16583492cc57e8cfa358c62e31cc9106b1700cc169962855a6f", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0x9978adfbceddc79b472634aacb781060a7d3d4e9c1051325385f1fa75169f10b04d45f7b8dddf1c5a4104e7bcbad450903d80ce7b59a59b8597fd9d72cd7f514336a6e7987e3234ab570195f617a515a08b1e1f52f6eb3f8c7b47d3748f3ce0d", "index": 7 }, { "pubkey": "0xa3ae000f40c06c1af1c40d713370a5fbf2cc28fdd6a03b36b751a1eb28a5699eea469d7b337981081facc738c326091d", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0x96a4310025bb94b8ce017c67cd87848807a7848b8f936bc230a9796eb73f61da8c3a633cf8430352fa61d0005816b1e405941a1970eefb5d9aa8799a0cd6855302e6fb05e0d8e00d055fd9fce29f01b23b06cf88ca263393a08a1f5f681ff6b5", "index": 8 }, { "pubkey": "0xa6194b4dc5f7c8bd00666cbe1a9490eae3306ff397c4d198395dd938100fc3828e2d072a1bf6f256299f9cdb8d2b42f0", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xb31e4b01eee9b172b6da62a40eafd3df3e7dd72f24bc90263efbdc18dd585c0fdae77cf10378465d09123989629b6b33039631b107a60bafcb3437d1c36abcee173945669c936036b9eafb6a042fd51b00f526e84bddd1197172fbf06f8100aa", "index": 9 }, { "pubkey": "0x865a04fc3fb234b69595fc464b00604e8e1f387d47dc6bca2d1503a82d2e20060334ef275c764136f13b87447bd3d0a8", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0x8a71c514d75a5506f2cc8e7f4bcd5e67dab6ecba21f6f0adbcb927751b0cbceacce0629991956cab84f1aa2fd23eae7d14ba271adaddf39612769c9b6db4bde9d455158976f6f45319c428f254e9b8704b5d3e6c0e9b8f9f679cc5a9d8a5fdf4", "index": 10 }, { "pubkey": "0xa769858cabcbe2fa239997e676e378f2037a679a1cf674679c40e410ffa9e72921781c24af7cc79969361559e88615de", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xa3bccffbc3daf7f34f8f1fcad65d32019f56e891341806b2536c457dd65932236be7379cfa36515fe928257506643d6806bd23096abcb5459d8209a315d69f296df5c3a68f8480c7285aec5ca7a8dc4b7cee69177db8cbf254fb91348794db13", "index": 11 }, { "pubkey": "0xa7f3186065f3f18a4b21b661f40941b942dad39062d9df399d94a18870e0600f1ccab51ee71ca5d6f971b79c2e51d6de", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xaa16f8f87b93cdbeb375fc86b284209b8c0146748b9981dda09548feb44a4cb02b5a09b76d4a5965d053dc20b157ec290b7a0e6b3d353ecec135f0f790fb5061b084392bb4caf2d0e6ed204e3382260ec3692f684dcc1ebf33aa0d3f86d3bfa3", "index": 12 }, { "pubkey": "0x89233d54cc54e67cbab9493af37bcbedaa9def92c14637694bf88f675b2ccd0a6c98a8dde009d6d80f515f11a8845517", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xaeabb1b459dd7069a0979e70a988734b880087e0e739b49fb461b8900fe8b2d24528469559553d286342960a25187bc611aaf289c6872b9fb3af68326a6cbc92b0e12c85109bd7d656670a7cd64194620b448d6179cd0776a69c369bd62c3f43", "index": 13 }, { "pubkey": "0x89884fc95abcb82736d768fc8ad4fdf4cb2112496974ae05440d835d0e93216643ae212b365fb6d9d2501d76d0925ef3", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0xa3ffd89ca2332fd848489d32d8bc6ab971a745edceac4bd6ad0262a020869c1ebe549c690ad818895fa767d0f111c91a106ad863bc58fcd90724e07baea01adcc8c8be67f2af9a153aea8cbc114b4959c7aaa78f2e13c5e6592b53512733b494", "index": 14 }, { "pubkey": "0x89c7f0d4cbace56294b624f6fa1b27beaa5afc9dab7072383c5f63f636e9f78f9e868a82e6684a72068199461f1f1c15", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0x84243354ef9365d76a68911f0ce632cdf7b4f02fa201dafe2afa7a09636315bf9417172cd5a503faeffed8da4c6e4ed50c67c119100964080481a41ee6e323db8f8d6e108bcb5b7f9a4b4b1f46edfb7250343a78468a70885ece13cbc2872807", "index": 15 }, { "pubkey": "0xab98ea73f3afab04154829f8d12a537cbf31a8b08f7f8e3870f4902001f0011234ed8f9218b40b4ed732d11d889f609d", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0x84e20df0f06e96fc428d8e3de91f07e2adf2b6cb38b40d27d3fe3bc4cf5c1a8ef70ba7443e6133deda9f5300d19458f907ed03cc8f514a4aacec548cd1d2b113b63143965c83a302f25b00a085ae109ee5dd9393efe2d981bb7c12a9384195fc", "index": 16 }, { "pubkey": "0x8bca787da4be8b093c0e8bb9e62311ee61459140cd616aad48dbcab233a163da85994869983e74658fa53af595432df4", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xae469d8fad70139a3e646b1fe9277c28c6664b1ebf26b0cc5d6e4b87436c6cc93f707420b4352023bea70ccc6d66b77815831a677a23d8bfd191feaa5e80ec8c79b1a52c4faafc6ef4cc046ac9a6b89dafb3f6299e4b17d05d23aff05c4309d2", "index": 17 }, { "pubkey": "0xabfb6d9eb0785e57b43ecffddd5d906375dd627e7338137a77c02788ed6d569b1a098ff2c2499a740e382930b39bce48", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x2aa1efb94e000", "signature": "0xa3c97804578b6e579a14ad40133520a7c55c19182085ff93d56c188ccb8a7c4f650d28879e4bd9a26b8b35619ad2e46806560e7939c9a2758b4f6e22ca11b7a360e8b92edc6ece33cbb907d87de4846f4757931bec4f262d2c27cddad3d3d9f1", "index": 18 }, { "pubkey": "0x8d0a94a5a2bb0289ebb24e73233f5ae6508d635022d8a12c69fce99791783bd76ab3fd33b6304a5fe42b85201db12f18", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x2aa1efb94e000", "signature": "0xa2d3c4aebd0a19123515b8a03137ab5ffba65d6ae5ebd255d312d42441b35a07ac1cd56ae4e0d93b5858ca81387eed430973c8e20c1f8d34d26e7ffe6930c7b1c09fd8db557945fac57cc57b3047957957f7337ffdfe44ff2357103f6a3532bc", "index": 19 }, { "pubkey": "0x8db0c2f3475fbe90310e7b2ed608546dae7aa5d0fe7f3d2775c2e18ab0e87368bc8c670de021f7740f2f82e6d54a8131", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xb8ffcdbaad229d6cd0045b10d80d2f35b9d7c47abae43550eae0230861ff8f790b49825462bef4ba629c0526058dcb6803ac176ad5d0397dce1cfba76d754cd8b897a048dc3371932eb036de99bb7445392c7375e8d37bd2e25fb8a21b950036", "index": 20 }, { "pubkey": "0x8e3b35bd379652019fe8f341c5c854a60f55772016340781e8d3577e2b24e1ac0d5786d45459cd756810281eff8f729c", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xa56d5493a899bd0f7048b911b865329aa60baaac75ac583e471c5c1ef0b217e1e0ac752aef65a554741e71f1e749d9eb0c3a8c470822cc529a2a5ceb95e1bd064812579c08bd4ff6102a961ccd1de81e4afad59c08b7d157058d85f89ef1f62b", "index": 21 }, { "pubkey": "0xb1580b412431ff7a1cca16045f0996740a5e52ebd1aeff6359415d99886b89a3506b36bd71af132a5dcb989e7a89b58d", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xb93a03089b440b426ed181ce934df4b4683557fee4790b333da2e6e15af58533a177dfa6e30749a5775339000a8e3eab054c4cb2896677a4141abeeeea2a4ab0abd319f1567b13e4c77e80a8fe7b39ccb566654937604df03e0ae5196063386a", "index": 22 }, { "pubkey": "0xb255e317f7e6415eab053180c8e36b5f6312c1e6ee1e884a26c490aa4121595574656ed89c83e0d6afd5e2b33c00b101", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xada62b2c6a8b20f2e85b82a121c7762b69222108334a9c9ccb0fb48c84f42bc289b74257f28e3e3307bde6273ae2339b08429adad60a5f99d4e4904e03c99acb4a70c8bdfbf6a592d24a706544604d00186c1d47cd655eab8e8604e16c01686a", "index": 23 }, { "pubkey": "0xb2faa51f9cf1a8c818459034941d965445bda15b212661f74f09394f2febe40c1f8feeba0cedcafd4ad28a944afb2b2c", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0x963e542a648f85bf0e7b261e4fe35a6b8fe843f13dfdad0c6852fc7ad62e01c23834ec062323d0a771d8a430d420e0a817a966768496175fb7c664e929ad7a5a79e529c6867156b7ffa0fe4988c741ccc4e9bb68491504990664a4f3e7965c8b", "index": 24 }, { "pubkey": "0x93012bdcf6baa87c1737df03c5fac7c8bb447282fbca5d2de42726ec67f237d66a2f867853e32ebd295010f075f22e95", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xb44c9fa4887a02bf109dc10ea87421e27cc466d22efbd46b4044c89e1639a68e07c688ef8b36fd3361699f4554a734570f70975f4d15228e661f067a5ade7b5bd545287ef0c4eafba7b541f315c214cde7623443432313e21e95512eff4b8f5e", "index": 25 }, { "pubkey": "0xb40cc8701d344c41054a3d028bb5f5f0702f7c228b22bdc9081541808c101808d3db2c130d64359efdd7589365b8f05b", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xb2370b357a6d928c5112dcf86a44027c93e2148cbcb79472cae1b454a671c8daf98c5a05f007b45c940656867ea8358810c735b5a6eca502ff97f83b27f93220df1ff04e81f4ced487abb27a7923a00e29a98c3060ce213daaf5455ea1a6cbc7", "index": 26 }, { "pubkey": "0xb577aa07f35ba1651b266f7f316ed1cd10907d0064e01dbcb502ec8c39bc1fc01acde07f4755ad0d414832fa2e2b5629", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xacbe459f7949a2d30b652912a2b88faf78bc71f815367252e99ecf3c9a4f160dc3bfaa1ef5357a49e2a9105063757c020609f62d8e7f9794277b95025400ba390bd7b33c211a07f885125383b953e666c6bab3ee33dfa93d4fd87ec948427fd6", "index": 27 }, { "pubkey": "0x960052c5509caa280218f3ecf3da7ba5bf4ec20b97e6c52700dd93515ef4e963813aa92a8731c9e137b1027dbc77102f", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0xadaec61ef0e55cf534648e3b3380618809716efdef669099bf74569281bef837ab7e6f8e4b17c838c9b8adaa3f6a4bdf00676520bac406621dfbd34c6243d95849f6dd3bd88cdb2e5075a3724cb967b811150f05f87c3e8e944416bd4d3e0ba9", "index": 28 }, { "pubkey": "0x964dd0632d0ed772dd0b5a269e9809be5b742df0ad4463552c7b51beef6baf6021360db60b0428ff1c4c38661c02b283", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0x8727fd93a940faa915d8b506537eb81dd786978892babab26c7c4a4cca6873604e7a1c057b74dcd8a5c4ffed02c43ac20bd17b4e24d66ba5a2ce2ceab21f10d1c8dee2cd566b75cedd37fe1d7868db212903ec66599a4ead0faadd29ff22555d", "index": 29 }, { "pubkey": "0x97266c94c490662479a9188b070c86e505df4f167016883af4114c8c1a71429e8f270c0c2f1b74375880f81828b768c0", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xa449362a6db71c5444eaa553d0239b148d3086fc3be0cdcb1184b947bd02c834bc9de91a197a61e51d9e1cbc059ca73d07001cca6fa2035fa49a668e6fce040d785e9bce595e8a63a6d26fabb3d65c49e27486ee28a77afed41d9cf2b3c2ed7d", "index": 30 }, { "pubkey": "0xb77084d2b92baa3e01ec5ce57fbd529d3c8e60941c637bdc7c85d9ca2cc56545c3cbea86879dcbe9402f8a55d0284e7b", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x1c6bf52634000", "signature": "0xabc2bd89d64c715cc5ea811b0f42ffffea6feb4e2b3e631834bdeb6d4771bf181d30a659f4733517353c5e7ec4dbc5cf14f5490e1b5c1b0068c155a4c16caf2cb84ea3666b35f711f399faefe63d5cdd99180129cc5f04fec55a96b825c0b641", "index": 31 }, { "pubkey": "0x98b7240b6aa60283ef2733840dc0996b1a16b68b38f9cbd83e5b7dda516d47b8279449f14c5b6a3d2bd8e74816ce2cae", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xac631262e9de9ce61e3502cb2fae5fdb68f6b173b74cd49707624c7ba0876c8e7d62076daefafea44af5821f32cf72630f91e1eea2a65f821003e80ec80dbb1e1a11d9368de404049f7fceacec0510c3a66748efd32a504ed807de3e68e44786", "index": 32 }, { "pubkey": "0x98beef4053d097aa1527a70301021a363fd3b92754a446932f5c97e7daa9c8d0bcf2ed315e7a55775a8bbe5ebe134ffb", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0x9187f8f325962f690fe67b497723df3a427e443832dcb7dc54c3019e061be9d15edb03c3644b7c37b6efc8fda915810e048cab47d752d1e04e6906d043e7f901c5e063dd6f3f2122ebb14cbcd4e2ddbaefcc82b06e062b7304511f15af012a41", "index": 33 }, { "pubkey": "0x83d0f90cdedaac1450c8dc08cfa644ae02f5918572041c2fca7df8b55336682cb5edbccadd6e77129de425844e147d02", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x2386f26fc10000", "signature": "0x921e7ea4d25e4904472db0cf2dcada03a776f614ef7c6a322972c1fc67f05ba76589cf577d62d7e7695795ac66242951160efab8200ed98781216ca7a0166e554efd4f3963bdd1f2ede64628be9661e8c406f91a35cf026baae4490878dda27e", "index": 34 }, { "pubkey": "0xa47aa6bd157dfa6ab6f411384a662c3d4d4f8745217ea8198470d6f3135bd71958fd824256fdbf16b21494ec3080b7ee", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0xa5682983524a9285c9bf6ec1d197d6c7bd87cb0f065d39b811be67527317b691c80dbd0cb4d01e3764675a7a8b36ec040f8e01bd51596ad79436c37ce87eaa1f79a69c7055bb0f4df79860f54f0ba2ba251fcaf24fe80c2e64ffc0421f6cfe37", "index": 35 }, { "pubkey": "0xa9504e88e6e969bd31a194c7c81df0e44b4644d0db81ad712d55023c5c6e1ac656558f27c8f8bac65c1fe72c597e6578", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0xe35fa931a000", "signature": "0x8e6ca94997c9cdb616e2a446e82e169cba1cc6428b6e126099fe46b9f13ba01135d20bf54d1f0d84d5df470312bd3ddc045671b983c76bf313377faa68a3761d43196449528fa59b561d6e6c2fd322b8f37251d92ee44f006d5ca653d81f7f6f", "index": 36 }, { "pubkey": "0x83fd53710b75c2115bd0aac128b739eb9fa9e262603dacdf834030abb1bf4c8a6c00bb72b314c123d77f4ff40cd4d49a", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x2386f26fc10000", "signature": "0xaeddc8a422aad2f0a1ed0806211bc5b67ccfb6ffe83f17dce5e589b63861a82c9cc4481bb0bd3f64905eb63b6788a9cc006dda3330aba22248ddc882dde000ed35ac2dda310416f84737fd0951f4e99358fcb9bb3bbbb9576570c60613b8b3f9", "index": 37 }, { "pubkey": "0x89543c3e50251ae355835484faf7cb38dacfca943b97fef9c9ee1e47248258a7198da417bf8fc6771fa7ef16a8adec0f", "credentials": "0x0100000000000000000000000b2261d5b8748aaf43e138c0a4a556659150a11a", "amount": "0x11c37937e08000", "signature": "0x82d5bd0d24c4db783333cf2f211d3e4c94953ea56c4df989f176d05ebe74b3bf3efdfeafb8152f5c9aa41326c587eb330a9c6d15d6464eb9a278a3a5729c8f9141198d8d5f829deaa9eb99145e449231b8206b07f3f49fec1fbbda832e23e55e", "index": 38 } ], "execution_payload_header": { "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000", "stateRoot": "0x2aace2f233f1ef6ca13e5fd8feae4cb1b0b580fa56c8ee081ab89d861eaf1515", "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000", "blockNumber": "0x0", "gasLimit": "0x1c9c380", "gasUsed": "0x0", "timestamp": "0x678e56e0", "extraData": "0x", "baseFeePerGas": "1000000000", "blockHash": "0xd57819422128da1c44339fc7956662378c17e2213e669b427ac91cd11dfcfb38", "transactionsRoot": "0x7ffe241ea60187fdb0187bfa22de35d1f9bed7ab061d9401fd47e34a54fbede1", "withdrawalsRoot": "0x792930bbd5baac43bcc798ee49aa8185ef76bb3b44ba62b91d86ae569e4bb535", "blobGasUsed": "0x0", "excessBlobGas": "0x0" } } }, "consensus": { "params": { "block": { "max_bytes": "104857600", "max_gas": "10000000" }, "evidence": { "max_age_num_blocks": "100000", "max_age_duration": "172800000000000", "max_bytes": "1048576" }, "validator": { "pub_key_types": [ "bls12_381" ] }, "version": { "app": "0" }, "synchrony": { "precision": "505000000", "message_delay": "15000000000" }, "feature": { "vote_extensions_enable_height": "0", "pbts_enable_height": "1" } } } } ================================================ FILE: testing/networks/80094/kzg-trusted-setup.json ================================================ { "g1_lagrange": [ "0xa0413c0dcafec6dbc9f47d66785cf1e8c981044f7d13cfe3e4fcbb71b5408dfde6312493cb3c1d30516cb3ca88c03654", "0x8b997fb25730d661918371bb41f2a6e899cac23f04fc5365800b75433c0a953250e15e7a98fb5ca5cc56a8cd34c20c57", "0x83302852db89424d5699f3f157e79e91dc1380f8d5895c5a772bb4ea3a5928e7c26c07db6775203ce33e62a114adaa99", "0xa759c48b7e4a685e735c01e5aa6ef9c248705001f470f9ad856cd87806983e917a8742a3bd5ee27db8d76080269b7c83", "0x967f8dc45ebc3be14c8705f43249a30ff48e96205fb02ae28daeab47b72eb3f45df0625928582aa1eb4368381c33e127", "0xa418eb1e9fb84cb32b370610f56f3cb470706a40ac5a47c411c464299c45c91f25b63ae3fcd623172aa0f273c0526c13", "0x8f44e3f0387293bc7931e978165abbaed08f53acd72a0a23ac85f6da0091196b886233bcee5b4a194db02f3d5a9b3f78", "0x97173434b336be73c89412a6d70d416e170ea355bf1956c32d464090b107c090ef2d4e1a467a5632fbc332eeb679bf2d", "0xa24052ad8d55ad04bc5d951f78e14213435681594110fd18173482609d5019105b8045182d53ffce4fc29fc8810516c1", "0xb950768136b260277590b5bec3f56bbc2f7a8bc383d44ce8600e85bf8cf19f479898bcc999d96dfbd2001ede01d94949", "0x92ab8077871037bd3b57b95cbb9fb10eb11efde9191690dcac655356986fd02841d8fdb25396faa0feadfe3f50baf56d", "0xa79b096dff98038ac30f91112dd14b78f8ad428268af36d20c292e2b3b6d9ed4fb28480bb04e465071cc67d05786b6d1", "0xb9ff71461328f370ce68bf591aa7fb13027044f42a575517f3319e2be4aa4843fa281e756d0aa5645428d6dfa857cef2", "0x8d765808c00b3543ff182e2d159c38ae174b12d1314da88ea08e13bd9d1c37184cb515e6bf6420531b5d41767987d7ce", "0xb8c9a837d20c3b53e6f578e4a257bb7ef8fc43178614ec2a154915b267ad2be135981d01ed2ee1b5fbd9d9bb27f0800a", "0xa9773d92cf23f65f98ef68f6cf95c72b53d0683af2f9bf886bb9036e4a38184b1131b26fd24397910b494fbef856f3aa", "0xb41ebe38962d112da4a01bf101cb248d808fbd50aaf749fc7c151cf332032eb3e3bdbd716db899724b734d392f26c412", "0x90fbb030167fb47dcc13d604a726c0339418567c1d287d1d87423fa0cb92eec3455fbb46bcbe2e697144a2d3972142e4", "0xb11d298bd167464b35fb923520d14832bd9ed50ed841bf6d7618424fd6f3699190af21759e351b89142d355952149da1", "0x8bc36066f69dc89f7c4d1e58d67497675050c6aa002244cebd9fc957ec5e364c46bab4735ea3db02b73b3ca43c96e019", "0xab7ab92c5d4d773068e485aa5831941ebd63db7118674ca38089635f3b4186833af2455a6fb9ed2b745df53b3ce96727", "0xaf191ca3089892cb943cd97cf11a51f38e38bd9be50844a4e8da99f27e305e876f9ed4ab0628e8ae3939066b7d34a15f", "0xa3204c1747feabc2c11339a542195e7cb6628fd3964f846e71e2e3f2d6bb379a5e51700682ea1844eba12756adb13216", "0x903a29883846b7c50c15968b20e30c471aeac07b872c40a4d19eb1a42da18b649d5bbfde4b4cf6225d215a461b0deb6d", "0x8e6e9c15ffbf1e16e5865a5fef7ed751dc81957a9757b535cb38b649e1098cda25d42381dc4f776778573cdf90c3e6e0", "0xa8f6dd26100b512a8c96c52e00715c4b2cb9ac457f17aed8ffe1cf1ea524068fe5a1ddf218149845fc1417b789ecfc98", "0xa5b0ffc819451ea639cfd1c18cbc9365cc79368d3b2e736c0ae54eba2f0801e6eb0ee14a5f373f4a70ca463bdb696c09", "0x879f91ccd56a1b9736fbfd20d8747354da743fb121f0e308a0d298ff0d9344431890e41da66b5009af3f442c636b4f43", "0x81bf3a2d9755e206b515a508ac4d1109bf933c282a46a4ae4a1b4cb4a94e1d23642fad6bd452428845afa155742ade7e", "0x8de778d4742f945df40004964e165592f9c6b1946263adcdd5a88b00244bda46c7bb49098c8eb6b3d97a0dd46148a8ca", "0xb7a57b21d13121907ee28c5c1f80ee2e3e83a3135a8101e933cf57171209a96173ff5037f5af606e9fd6d066de6ed693", "0xb0877d1963fd9200414a38753dffd9f23a10eb3198912790d7eddbc9f6b477019d52ddd4ebdcb9f60818db076938a5a9", "0x88da2d7a6611bc16adc55fc1c377480c828aba4496c645e3efe0e1a67f333c05a0307f7f1d2df8ac013602c655c6e209", "0x95719eb02e8a9dede1a888c656a778b1c69b7716fbe3d1538fe8afd4a1bc972183c7d32aa7d6073376f7701df80116d8", "0x8e8a1ca971f2444b35af3376e85dccda3abb8e8e11d095d0a4c37628dfe5d3e043a377c3de68289ef142e4308e9941a0", "0xb720caaff02f6d798ac84c4f527203e823ff685869e3943c979e388e1c34c3f77f5c242c6daa7e3b30e511aab917b866", "0x86040d55809afeec10e315d1ad950d269d37cfee8c144cd8dd4126459e3b15a53b3e68df5981df3c2346d23c7b4baaf4", "0x82d8cabf13ab853db0377504f0aec00dba3a5cd3119787e8ad378ddf2c40b022ecfc67c642b7acc8c1e3dd03ab50993e", "0xb8d873927936719d2484cd03a6687d65697e17dcf4f0d5aed6f5e4750f52ef2133d4645894e7ebfc4ef6ce6788d404c8", "0xb1235594dbb15b674a419ff2b2deb644ad2a93791ca05af402823f87114483d6aa1689b7a9bea0f547ad12fe270e4344", "0xa53fda86571b0651f5affb74312551a082fffc0385cfd24c1d779985b72a5b1cf7c78b42b4f7e51e77055f8e5e915b00", "0xb579adcfd9c6ef916a5a999e77a0cb21d378c4ea67e13b7c58709d5da23a56c2e54218691fc4ac39a4a3d74f88cc31f7", "0xab79e584011713e8a2f583e483a91a0c2a40771b77d91475825b5acbea82db4262132901cb3e4a108c46d7c9ee217a4e", "0xa0fe58ea9eb982d7654c8aaf9366230578fc1362f6faae0594f8b9e659bcb405dff4aac0c7888bbe07f614ecf0d800a6", "0x867e50e74281f28ecd4925560e2e7a6f8911b135557b688254623acce0dbc41e23ac3e706a184a45d54c586edc416eb0", "0x89f81b61adda20ea9d0b387a36d0ab073dc7c7cbff518501962038be19867042f11fcc7ff78096e5d3b68c6d8dc04d9b", "0xa58ee91bb556d43cf01f1398c5811f76dc0f11efdd569eed9ef178b3b0715e122060ec8f945b4dbf6eebfa2b90af6fa6", "0xac460be540f4c840def2eef19fc754a9af34608d107cbadb53334cf194cc91138d53b9538fcd0ec970b5d4aa455b224a", "0xb09b91f929de52c09d48ca0893be6eb44e2f5210a6c394689dc1f7729d4be4e11d0474b178e80cea8c2ac0d081f0e811", "0x8d37a442a76b06a02a4e64c2504aea72c8b9b020ab7bcc94580fe2b9603c7c50d7b1e9d70d2a7daea19c68667e8f8c31", "0xa9838d4c4e3f3a0075a952cf7dd623307ec633fcc81a7cf9e52e66c31780de33dbb3d74c320dc7f0a4b72f7a49949515", "0xa44766b6251af458fe4f5f9ed1e02950f35703520b8656f09fc42d9a2d38a700c11a7c8a0436ac2e5e9f053d0bb8ff91", "0xad78d9481c840f5202546bea0d13c776826feb8b1b7c72e83d99a947622f0bf38a4208551c4c41beb1270d7792075457", "0xb619ffa8733b470039451e224b777845021e8dc1125f247a4ff2476cc774657d0ff9c5279da841fc1236047de9d81c60", "0xaf760b0a30a1d6af3bc5cd6686f396bd41779aeeb6e0d70a09349bd5da17ca2e7965afc5c8ec22744198fbe3f02fb331", "0xa0cc209abdb768b589fcb7b376b6e1cac07743288c95a1cf1a0354b47f0cf91fca78a75c1fcafa6f5926d6c379116608", "0x864add673c89c41c754eeb3cd8dcff5cdde1d739fce65c30e474a082bb5d813cba6412e61154ce88fdb6c12c5d9be35b", "0xb091443b0ce279327dc37cb484e9a5b69b257a714ce21895d67539172f95ffa326903747b64a3649e99aea7bb10d03f7", "0xa8c452b8c4ca8e0a61942a8e08e28f17fb0ef4c5b018b4e6d1a64038280afa2bf1169202f05f14af24a06ca72f448ccd", "0xa23c24721d18bc48d5dcf70effcbef89a7ae24e67158d70ae1d8169ee75d9a051d34b14e9cf06488bac324fe58549f26", "0x92a730e30eb5f3231feb85f6720489dbb1afd42c43f05a1610c6b3c67bb949ec8fde507e924498f4ffc646f7b07d9123", "0x8dbe5abf4031ec9ba6bb06d1a47dd1121fb9e03b652804069250967fd5e9577d0039e233441b7f837a7c9d67ba18c28e", "0xaa456bcfef6a21bb88181482b279df260297b3778e84594ebddbdf337e85d9e3d46ca1d0b516622fb0b103df8ec519b7", "0xa3b31ae621bd210a2b767e0e6f22eb28fe3c4943498a7e91753225426168b9a26da0e02f1dc5264da53a5ad240d9f51b", "0xaa8d66857127e6e71874ce2202923385a7d2818b84cb73a6c42d71afe70972a70c6bdd2aad1a6e8c5e4ca728382a8ea8", "0xac7e8e7a82f439127a5e40558d90d17990f8229852d21c13d753c2e97facf077cf59582b603984c3dd3faebd80aff4f5", "0x93a8bcf4159f455d1baa73d2ef2450dcd4100420de84169bbe28b8b7a5d1746273f870091a87a057e834f754f34204b1", "0x89d0ebb287c3613cdcae7f5acc43f17f09c0213fc40c074660120b755d664109ffb9902ed981ede79e018ddb0c845698", "0xa87ccbfad431406aadbee878d9cf7d91b13649d5f7e19938b7dfd32645a43b114eef64ff3a13201398bd9b0337832e5a", "0x833c51d0d0048f70c3eefb4e70e4ff66d0809c41838e8d2c21c288dd3ae9d9dfaf26d1742bf4976dab83a2b381677011", "0x8bcd6b1c3b02fffead432e8b1680bad0a1ac5a712d4225e220690ee18df3e7406e2769e1f309e2e803b850bc96f0e768", "0xb61e3dbd88aaf4ff1401521781e2eea9ef8b66d1fac5387c83b1da9e65c2aa2a56c262dea9eceeb4ad86c90211672db0", "0x866d3090db944ecf190dd0651abf67659caafd31ae861bab9992c1e3915cb0952da7c561cc7e203560a610f48fae633b", "0xa5e8971543c14274a8dc892b0be188c1b4fbc75c692ed29f166e0ea80874bc5520c2791342b7c1d2fb5dd454b03b8a5b", "0x8f2f9fc50471bae9ea87487ebd1bc8576ef844cc42d606af5c4c0969670fdf2189afd643e4de3145864e7773d215f37f", "0xb1bb0f2527db6d51f42b9224383c0f96048bbc03d469bf01fe1383173ef8b1cc9455d9dd8ba04d46057f46949bfc92b5", "0xaa7c99d906b4d7922296cfe2520473fc50137c03d68b7865c5bfb8adbc316b1034310ec4b5670c47295f4a80fb8d61e9", "0xa5d1da4d6aba555919df44cbaa8ff79378a1c9e2cfdfbf9d39c63a4a00f284c5a5724e28ecbc2d9dba27fe4ee5018bd5", "0xa8db53224f70af4d991b9aae4ffe92d2aa5b618ad9137784b55843e9f16cefbfd25ada355d308e9bbf55f6d2f7976fb3", "0xb6536c4232bb20e22af1a8bb12de76d5fec2ad9a3b48af1f38fa67e0f8504ef60f305a73d19385095bb6a9603fe29889", "0x87f7e371a1817a63d6838a8cf4ab3a8473d19ce0d4f40fd013c03d5ddd5f4985df2956531cc9f187928ef54c68f4f9a9", "0xae13530b1dbc5e4dced9d909ea61286ec09e25c12f37a1ed2f309b0eb99863d236c3b25ed3484acc8c076ad2fa8cd430", "0x98928d850247c6f7606190e687d5c94a627550198dbdbea0161ef9515eacdb1a0f195cae3bb293112179082daccf8b35", "0x918528bb8e6a055ad4db6230d3a405e9e55866da15c4721f5ddd1f1f37962d4904aad7a419218fe6d906fe191a991806", "0xb71e31a06afe065773dd3f4a6e9ef81c3292e27a3b7fdfdd452d03e05af3b6dd654c355f7516b2a93553360c6681a73a", "0x8870b83ab78a98820866f91ac643af9f3ff792a2b7fda34185a9456a63abdce42bfe8ad4dc67f08a6392f250d4062df4", "0x91eea1b668e52f7a7a5087fabf1cab803b0316f78d9fff469fbfde2162f660c250e4336a9eea4cb0450bd30ac067bc8b", "0x8b74990946de7b72a92147ceac1bd9d55999a8b576e8df68639e40ed5dc2062cfcd727903133de482b6dca19d0aaed82", "0x8ebad537fece090ebbab662bdf2618e21ca30cf6329c50935e8346d1217dcbe3c1fe1ea28efca369c6003ce0a94703c1", "0xa8640479556fb59ebd1c40c5f368fbd960932fdbb782665e4a0e24e2bdb598fc0164ce8c0726d7759cfc59e60a62e182", "0xa9a52a6bf98ee4d749f6d38be2c60a6d54b64d5cbe4e67266633dc096cf28c97fe998596707d31968cbe2064b72256bf", "0x847953c48a4ce6032780e9b39d0ed4384e0be202c2bbe2dfda3910f5d87aa5cd3c2ffbfcfae4dddce16d6ab657599b95", "0xb6f6e1485d3ec2a06abaecd23028b200b2e4a0096c16144d07403e1720ff8f9ba9d919016b5eb8dc5103880a7a77a1d3", "0x98dfc2065b1622f596dbe27131ea60bef7a193b12922cecb27f8c571404f483014f8014572e86ae2e341ab738e4887ef", "0xacb0d205566bacc87bbe2e25d10793f63f7a1f27fd9e58f4f653ceae3ffeba511eaf658e068fad289eeb28f9edbeb35b", "0xae4411ed5b263673cee894c11fe4abc72a4bf642d94022a5c0f3369380fcdfc1c21e277f2902972252503f91ada3029a", "0xac4a7a27ba390a75d0a247d93d4a8ef1f0485f8d373a4af4e1139369ec274b91b3464d9738eeaceb19cd6f509e2f8262", "0x87379c3bf231fdafcf6472a79e9e55a938d851d4dd662ab6e0d95fd47a478ed99e2ad1e6e39be3c0fc4f6d996a7dd833", "0x81316904b035a8bcc2041199a789a2e6879486ba9fddcba0a82c745cc8dd8374a39e523b91792170cd30be7aa3005b85", "0xb8206809c6cd027ed019f472581b45f7e12288f89047928ba32b4856b6560ad30395830d71e5e30c556f6f182b1fe690", "0x88d76c028f534a62e019b4a52967bb8642ede6becfa3807be68fdd36d366fc84a4ac8dc176e80a68bc59eb62caf5dff9", "0x8c3b8be685b0f8aad131ee7544d0e12f223f08a6f8edaf464b385ac644e0ddc9eff7cc7cb5c1b50ab5d71ea0f41d2213", "0x8d91410e004f76c50fdc05784157b4d839cb5090022c629c7c97a5e0c3536eeafee17a527b54b1165c3cd81774bb54ce", "0xb25c2863bc28ec5281ce800ddf91a7e1a53f4c6d5da1e6c86ef4616e93bcf55ed49e297216d01379f5c6e7b3c1e46728", "0x865f7b09ac3ca03f20be90c48f6975dd2588838c2536c7a3532a6aa5187ed0b709cd03d91ff4048061c10d0aa72b69ce", "0xb3f7477c90c11596eb4f8bbf34adbcb832638c4ff3cdd090d4d477ee50472ac9ddaf5be9ad7eca3f148960d362bbd098", "0x8db35fd53fca04faecd1c76a8227160b3ab46ac1af070f2492445a19d8ff7c25bbaef6c9fa0c8c088444561e9f7e4eb2", "0xa478b6e9d058a2e01d2fc053b739092e113c23a6a2770a16afbef044a3709a9e32f425ace9ba7981325f02667c3f9609", "0x98caa6bd38916c08cf221722a675a4f7577f33452623de801d2b3429595f988090907a7e99960fff7c076d6d8e877b31", "0xb79aaaacefc49c3038a14d2ac468cfec8c2161e88bdae91798d63552cdbe39e0e02f9225717436b9b8a40a022c633c6e", "0x845a31006c680ee6a0cc41d3dc6c0c95d833fcf426f2e7c573fa15b2c4c641fbd6fe5ebb0e23720cc3467d6ee1d80dc4", "0xa1bc287e272cf8b74dbf6405b3a5190883195806aa351f1dc8e525aa342283f0a35ff687e3b434324dedee74946dd185", "0xa4fd2dc8db75d3783a020856e2b3aa266dc6926e84f5c491ef739a3bddd46dc8e9e0fc1177937839ef1b18d062ffbb9e", "0xacbf0d3c697f57c202bb8c5dc4f3fc341b8fc509a455d44bd86acc67cad2a04495d5537bcd3e98680185e8aa286f2587", "0xa5caf423a917352e1b8e844f5968a6da4fdeae467d10c6f4bbd82b5eea46a660b82d2f5440d3641c717b2c3c9ed0be52", "0x8a39d763c08b926599ab1233219c49c825368fad14d9afc7c0c039224d37c00d8743293fd21645bf0b91eaf579a99867", "0xb2b53a496def0ba06e80b28f36530fbe0fb5d70a601a2f10722e59abee529369c1ae8fd0f2db9184dd4a2519bb832d94", "0xa73980fcef053f1b60ebbb5d78ba6332a475e0b96a0c724741a3abf3b59dd344772527f07203cf4c9cb5155ebed81fa0", "0xa070d20acce42518ece322c9db096f16aed620303a39d8d5735a0df6e70fbeceb940e8d9f5cc38f3314b2240394ec47b", "0xa50cf591f522f19ca337b73089557f75929d9f645f3e57d4f241e14cdd1ea3fb48d84bcf05e4f0377afbb789fbdb5d20", "0x82a5ffce451096aca8eeb0cd2ae9d83db3ed76da3f531a80d9a70a346359bf05d74863ce6a7c848522b526156a5e20cd", "0x88e0e84d358cbb93755a906f329db1537c3894845f32b9b0b691c29cbb455373d9452fadd1e77e20a623f6eaf624de6f", "0xaa07ac7b84a6d6838826e0b9e350d8ec75e398a52e9824e6b0da6ae4010e5943fec4f00239e96433f291fef9d1d1e609", "0xac8887bf39366034bc63f6cc5db0c26fd27307cbc3d6cce47894a8a019c22dd51322fb5096edc018227edfafc053a8f6", "0xb7d26c26c5b33f77422191dca94977588ab1d4b9ce7d0e19c4a3b4cd1c25211b78c328dbf81e755e78cd7d1d622ad23e", "0x99a676d5af49f0ba44047009298d8474cabf2d5bca1a76ba21eff7ee3c4691a102fdefea27bc948ccad8894a658abd02", "0xb0d09a91909ab3620c183bdf1d53d43d39eb750dc7a722c661c3de3a1a5d383ad221f71bae374f8a71867505958a3f76", "0x84681a883de8e4b93d68ac10e91899c2bbb815ce2de74bb48a11a6113b2a3f4df8aceabda1f5f67bc5aacac8c9da7221", "0x9470259957780fa9b43521fab3644f555f5343281c72582b56d2efd11991d897b3b481cafa48681c5aeb80c9663b68f7", "0xab1b29f7ece686e6fa968a4815da1d64f3579fed3bc92e1f3e51cd13a3c076b6cf695ed269d373300a62463dc98a4234", "0x8ab415bfcd5f1061f7687597024c96dd9c7cb4942b5989379a7a3b5742f7d394337886317659cbeacaf030234a24f972", "0xb9b524aad924f9acc63d002d617488f31b0016e0f0548f050cada285ce7491b74a125621638f19e9c96eabb091d945be", "0x8c4c373e79415061837dd0def4f28a2d5d74d21cb13a76c9049ad678ca40228405ab0c3941df49249847ecdefc1a5b78", "0xa8edf4710b5ab2929d3db6c1c0e3e242261bbaa8bcec56908ddadd7d2dad2dca9d6eb9de630b960b122ebeea41040421", "0x8d66bb3b50b9df8f373163629f9221b3d4b6980a05ea81dc3741bfe9519cf3ebba7ab98e98390bae475e8ede5821bd5c", "0x8d3c21bae7f0cfb97c56952bb22084b58e7bb718890935b73103f33adf5e4d99cd262f929c6eeab96209814f0dbae50a", "0xa5c66cfab3d9ebf733c4af24bebc97070e7989fe3c73e79ac85fb0e4d40ae44fb571e0fad4ad72560e13ed453900d14f", "0x9362e6b50b43dbefbc3254471372297b5dcce809cd3b60bf74a1268ab68bdb50e46e462cbd78f0d6c056330e982846af", "0x854630d08e3f0243d570cc2e856234cb4c1a158d9c1883bf028a76525aaa34be897fe918d5f6da9764a3735fa9ebd24a", "0x8c7d246985469ff252c3f4df6c7c9196fc79f05c1c66a609d84725c78001d0837c7a7049394ba5cf7e863e2d58af8417", "0xae050271e01b528925302e71903f785b782f7bf4e4e7a7f537140219bc352dc7540c657ed03d3a297ad36798ecdb98cd", "0x8d2ae9179fcf2b0c69850554580b52c1f4a5bd865af5f3028f222f4acad9c1ad69a8ef6c7dc7b03715ee5c506b74325e", "0xb8ef8de6ce6369a8851cd36db0ccf00a85077e816c14c4e601f533330af9e3acf0743a95d28962ed8bfcfc2520ef3cfe", "0xa6ecad6fdfb851b40356a8b1060f38235407a0f2706e7b8bb4a13465ca3f81d4f5b99466ac2565c60af15f022d26732e", "0x819ff14cdea3ab89d98e133cd2d0379361e2e2c67ad94eeddcdb9232efd509f51d12f4f03ebd4dd953bd262a886281f7", "0x8561cd0f7a6dbcddd83fcd7f472d7dbcba95b2d4fb98276f48fccf69f76d284e626d7e41314b633352df8e6333fd52a1", "0xb42557ccce32d9a894d538c48712cb3e212d06ac05cd5e0527ccd2db1078ee6ae399bf6a601ffdab1f5913d35fc0b20c", "0x89b4008d767aad3c6f93c349d3b956e28307311a5b1cec237e8d74bb0dee7e972c24f347fd56afd915a2342bd7bc32f0", "0x877487384b207e53f5492f4e36c832c2227f92d1bb60542cfeb35e025a4a7afc2b885fae2528b33b40ab09510398f83e", "0x8c411050b63c9053dd0cd81dacb48753c3d7f162028098e024d17cd6348482703a69df31ad6256e3d25a8bbf7783de39", "0xa8506b54a88d17ac10fb1b0d1fe4aa40eae7553a064863d7f6b52ccc4236dd4b82d01dca6ba87da9a239e3069ba879fb", "0xb1a24caef9df64750c1350789bb8d8a0db0f39474a1c74ea9ba064b1516db6923f00af8d57c632d58844fb8786c3d47a", "0x959d6e255f212b0708c58a2f75cb1fe932248c9d93424612c1b8d1e640149656059737e4db2139afd5556bcdacf3eda2", "0x84525af21a8d78748680b6535bbc9dc2f0cf9a1d1740d12f382f6ecb2e73811d6c1da2ad9956070b1a617c61fcff9fe5", "0xb74417d84597a485d0a8e1be07bf78f17ebb2e7b3521b748f73935b9afbbd82f34b710fb7749e7d4ab55b0c7f9de127d", "0xa4a9aecb19a6bab167af96d8b9d9aa5308eab19e6bfb78f5a580f9bf89bdf250a7b52a09b75f715d651cb73febd08e84", "0x9777b30be2c5ffe7d29cc2803a562a32fb43b59d8c3f05a707ab60ec05b28293716230a7d264d7cd9dd358fc031cc13e", "0x95dce7a3d4f23ac0050c510999f5fbf8042f771e8f8f94192e17bcbfa213470802ebdbe33a876cb621cf42e275cbfc8b", "0xb0b963ebcbbee847ab8ae740478544350b3ac7e86887e4dfb2299ee5096247cd2b03c1de74c774d9bde94ae2ee2dcd59", "0xa4ab20bafa316030264e13f7ef5891a2c3b29ab62e1668fcb5881f50a9acac6adbe3d706c07e62f2539715db768f6c43", "0x901478a297669d608e406fe4989be75264b6c8be12169aa9e0ad5234f459ca377f78484ffd2099a2fe2db5e457826427", "0x88c76e5c250810c057004a03408b85cd918e0c8903dc55a0dd8bb9b4fc2b25c87f9b8cf5943eb19fbbe99d36490050c5", "0x91607322bbad4a4f03fc0012d0821eff5f8c516fda45d1ec1133bface6f858bf04b25547be24159cab931a7aa08344d4", "0x843203e07fce3c6c81f84bc6dc5fb5e9d1c50c8811ace522dc66e8658433a0ef9784c947e6a62c11bf705307ef05212e", "0x91dd8813a5d6dddcda7b0f87f672b83198cd0959d8311b2b26fb1fae745185c01f796fbd03aad9db9b58482483fdadd8", "0x8d15911aacf76c8bcd7136e958febd6963104addcd751ce5c06b6c37213f9c4fb0ffd4e0d12c8e40c36d658999724bfd", "0x8a36c5732d3f1b497ebe9250610605ee62a78eaa9e1a45f329d09aaa1061131cf1d9df00f3a7d0fe8ad614a1ff9caaae", "0xa407d06affae03660881ce20dab5e2d2d6cddc23cd09b95502a9181c465e57597841144cb34d22889902aff23a76d049", "0xb5fd856d0578620a7e25674d9503be7d97a2222900e1b4738c1d81ff6483b144e19e46802e91161e246271f90270e6cf", "0x91b7708869cdb5a7317f88c0312d103f8ce90be14fb4f219c2e074045a2a83636fdc3e69e862049fc7c1ef000e832541", "0xb64719cc5480709d1dae958f1d3082b32a43376da446c8f9f64cb02a301effc9c34d9102051733315a8179aed94d53cc", "0x94347a9542ff9d18f7d9eaa2f4d9b832d0e535fe49d52aa2de08aa8192400eddabdb6444a2a78883e27c779eed7fdf5a", "0x840ef44a733ff1376466698cd26f82cf56bb44811e196340467f932efa3ae1ef9958a0701b3b032f50fd9c1d2aed9ab5", "0x90ab3f6f67688888a31ffc2a882bb37adab32d1a4b278951a21646f90d03385fc976715fc639a785d015751171016f10", "0xb56f35d164c24b557dbcbc8a4bfa681ec916f8741ffcb27fb389c164f4e3ed2be325210ef5bdaeae7a172ca9599ab442", "0xa7921a5a80d7cf6ae81ba9ee05e0579b18c20cd2852762c89d6496aa4c8ca9d1ca2434a67b2c16d333ea8e382cdab1e3", "0xa506bcfbd7e7e5a92f68a1bd87d07ad5fe3b97aeee40af2bf2cae4efcd77fff03f872732c5b7883aa6584bee65d6f8cb", "0xa8c46cff58931a1ce9cbe1501e1da90b174cddd6d50f3dfdfb759d1d4ad4673c0a8feed6c1f24c7af32865a7d6c984e5", "0xb45686265a83bff69e312c5149db7bb70ac3ec790dc92e392b54d9c85a656e2bf58596ce269f014a906eafc97461aa5f", "0x8d4009a75ccb2f29f54a5f16684b93202c570d7a56ec1a8b20173269c5f7115894f210c26b41e8d54d4072de2d1c75d0", "0xaef8810af4fc676bf84a0d57b189760ddc3375c64e982539107422e3de2580b89bd27aa6da44e827b56db1b5555e4ee8", "0x888f0e1e4a34f48eb9a18ef4de334c27564d72f2cf8073e3d46d881853ac1424d79e88d8ddb251914890588937c8f711", "0xb64b0aa7b3a8f6e0d4b3499fe54e751b8c3e946377c0d5a6dbb677be23736b86a7e8a6be022411601dd75012012c3555", "0x8d57776f519f0dd912ea14f79fbab53a30624e102f9575c0bad08d2dc754e6be54f39b11278c290977d9b9c7c0e1e0ad", "0xa018fc00d532ceb2e4de908a15606db9b6e0665dd77190e2338da7c87a1713e6b9b61554e7c1462f0f6d4934b960b15c", "0x8c932be83ace46f65c78e145b384f58e41546dc0395270c1397874d88626fdeda395c8a289d602b4c312fe98c1311856", "0x89174838e21639d6bdd91a0621f04dc056907b88e305dd66e46a08f6d65f731dea72ae87ca5e3042d609e8de8de9aa26", "0xb7b7f508bb74f7a827ac8189daa855598ff1d96fa3a02394891fd105d8f0816224cd50ac4bf2ed1cf469ace516c48184", "0xb31877ad682583283baadd68dc1bebd83f5748b165aadd7fe9ef61a343773b88bcd3a022f36d6c92f339b7bfd72820a9", "0xb79d77260b25daf9126dab7a193df2d7d30542786fa1733ffaf6261734770275d3ca8bae1d9915d1181a78510b3439db", "0x91894fb94cd4c1dd2ceaf9c53a7020c5799ba1217cf2d251ea5bc91ed26e1159dd758e98282ebe35a0395ef9f1ed15a0", "0xab59895cdafd33934ceedfc3f0d5d89880482cba6c99a6db93245f9e41987efd76e0640e80aef31782c9a8c7a83fccec", "0xaa22ea63654315e033e09d4d4432331904a6fc5fb1732557987846e3c564668ca67c60a324b4af01663a23af11a9ce4b", "0xb53ba3ef342601467e1f71aa280e100fbabbd38518fa0193e0099505036ee517c1ac78e96e9baeb549bb6879bb698fb0", "0x943fd69fd656f37487cca3605dc7e5a215fddd811caf228595ec428751fc1de484a0cb84c667fe4d7c35599bfa0e5e34", "0x9353128b5ebe0dddc555093cf3e5942754f938173541033e8788d7331fafc56f68d9f97b4131e37963ab7f1c8946f5f1", "0xa76cd3c566691f65cfb86453b5b31dbaf3cab8f84fe1f795dd1e570784b9b01bdd5f0b3c1e233942b1b5838290e00598", "0x983d84b2e53ffa4ae7f3ba29ef2345247ea2377686b74a10479a0ef105ecf90427bf53b74c96dfa346d0f842b6ffb25b", "0x92e0fe9063306894a2c6970c001781cff416c87e87cb5fbac927a3192655c3da4063e6fa93539f6ff58efac6adcc5514", "0xb00a81f03c2b8703acd4e2e4c21e06973aba696415d0ea1a648ace2b0ea19b242fede10e4f9d7dcd61c546ab878bc8f9", "0xb0d08d880f3b456a10bf65cff983f754f545c840c413aea90ce7101a66eb0a0b9b1549d6c4d57725315828607963f15a", "0x90cb64d03534f913b411375cce88a9e8b1329ce67a9f89ca5df8a22b8c1c97707fec727dbcbb9737f20c4cf751359277", "0x8327c2d42590dfcdb78477fc18dcf71608686ad66c49bce64d7ee874668be7e1c17cc1042a754bbc77c9daf50b2dae07", "0x8532171ea13aa7e37178e51a6c775da469d2e26ec854eb16e60f3307db4acec110d2155832c202e9ba525fc99174e3b0", "0x83ca44b15393d021de2a511fa5511c5bd4e0ac7d67259dce5a5328f38a3cce9c3a269405959a2486016bc27bb140f9ff", "0xb1d36e8ca812be545505c8214943b36cabee48112cf0de369957afa796d37f86bf7249d9f36e8e990f26f1076f292b13", "0x9803abf45be5271e2f3164c328d449efc4b8fc92dfc1225d38e09630909fe92e90a5c77618daa5f592d23fc3ad667094", "0xb268ad68c7bf432a01039cd889afae815c3e120f57930d463aece10af4fd330b5bd7d8869ef1bcf6b2e78e4229922edc", "0xa4c91a0d6f16b1553264592b4cbbbf3ca5da32ab053ffbdd3dbb1aed1afb650fb6e0dc5274f71a51d7160856477228db", "0xad89d043c2f0f17806277ffdf3ecf007448e93968663f8a0b674254f36170447b7527d5906035e5e56f4146b89b5af56", "0x8b6964f757a72a22a642e4d69102951897e20c21449184e44717bd0681d75f7c5bfa5ee5397f6e53febf85a1810d6ed1", "0xb08f5cdaabec910856920cd6e836c830b863eb578423edf0b32529488f71fe8257d90aed4a127448204df498b6815d79", "0xaf26bb3358be9d280d39b21d831bb53145c4527a642446073fee5a86215c4c89ff49a3877a7a549486262f6f57a0f476", "0xb4010b37ec4d7c2af20800e272539200a6b623ae4636ecbd0e619484f4ab9240d02bc5541ace3a3fb955dc0a3d774212", "0x82752ab52bdcc3cc2fc405cb05a2e694d3df4a3a68f2179ec0652536d067b43660b96f85f573f26fbd664a9ef899f650", "0x96d392dde067473a81faf2d1fea55b6429126b88b160e39b4210d31d0a82833ffd3a80e07d24d495aea2d96be7251547", "0xa76d8236d6671204d440c33ac5b8deb71fa389f6563d80e73be8b043ec77d4c9b06f9a586117c7f957f4af0331cbc871", "0xb6c90961f68b5e385d85c9830ec765d22a425f506904c4d506b87d8944c2b2c09615e740ed351df0f9321a7b93979cae", "0xa6ec5ea80c7558403485b3b1869cdc63bde239bafdf936d9b62a37031628402a36a2cfa5cfbb8e26ac922cb0a209b3ba", "0x8c3195bbdbf9bc0fc95fa7e3d7f739353c947f7767d1e3cb24d8c8602d8ea0a1790ac30b815be2a2ba26caa5227891e2", "0xa7f8a63d809f1155722c57f375ea00412b00147776ae4444f342550279ef4415450d6f400000a326bf11fea6c77bf941", "0x97fa404df48433a00c85793440e89bb1af44c7267588ae937a1f5d53e01e1c4d4fc8e4a6d517f3978bfdd6c2dfde012f", "0xa984a0a3836de3d8d909c4629a2636aacb85393f6f214a2ef68860081e9db05ad608024762db0dc35e895dc00e2d4cdd", "0x9526cf088ab90335add1db4d3a4ac631b58cbfbe88fa0845a877d33247d1cfeb85994522e1eb8f8874651bfb1df03e2a", "0xac83443fd0afe99ad49de9bf8230158c118e2814c9c89db5ac951c240d6c2ce45e7677221279d9e97848ec466b99aafe", "0xaeeefdbaba612e971697798ceaf63b247949dc823a0ad771ae5b988a5e882b338a98d3d0796230f49d533ec5ba411b39", "0xae3f248b5a7b0f92b7820a6c5ae21e5bd8f4265d4f6e21a22512079b8ee9be06393fd3133ce8ebac0faf23f4f8517e36", "0xa64a831b908eee784b8388b45447d2885ec0551b26b0c2b15e5f417d0a12c79e867fb7bd3d008d0af98b44336f8ec1ad", "0xb242238cd8362b6e440ba21806905714dd55172db25ec7195f3fc4937b2aba146d5cbf3cf691a1384b4752dc3b54d627", "0x819f97f337eea1ffb2a678cc25f556f1aab751c6b048993a1d430fe1a3ddd8bb411c152e12ca60ec6e057c190cd1db9a", "0xb9d7d187407380df54ee9fef224c54eec1bfabf17dc8abf60765b7951f538f59aa26fffd5846cfe05546c35f59b573f4", "0xaa6e3c14efa6a5962812e3f94f8ce673a433f4a82d07a67577285ea0eaa07f8be7115853122d12d6d4e1fdf64c504be1", "0x82268bee9c1662d3ddb5fb785abfae6fb8b774190f30267f1d47091d2cd4b3874db4372625aa36c32f27b0eee986269b", "0xb236459565b7b966166c4a35b2fa71030b40321821b8e96879d95f0e83a0baf33fa25721f30af4a631df209e25b96061", "0x8708d752632d2435d2d5b1db4ad1fa2558d776a013655f88e9a3556d86b71976e7dfe5b8834fdec97682cd94560d0d0d", "0xae1424a68ae2dbfb0f01211f11773732a50510b5585c1fb005cb892b2c6a58f4a55490b5c5b4483c6fce40e9d3236a52", "0xb3f5f722af9dddb07293c871ce97abbccba0093ca98c8d74b1318fa21396fc1b45b69c15084f63d728f9908442024506", "0x9606f3ce5e63886853ca476dc0949e7f1051889d529365c0cb0296fdc02abd088f0f0318ecd2cf36740a3634132d36f6", "0xb11a833a49fa138db46b25ff8cdda665295226595bc212c0931b4931d0a55c99da972c12b4ef753f7e37c6332356e350", "0xafede34e7dab0a9e074bc19a7daddb27df65735581ca24ad70c891c98b1349fcebbcf3ba6b32c2617fe06a5818dabc2d", "0x97993d456e459e66322d01f8eb13918979761c3e8590910453944bdff90b24091bb018ac6499792515c9923be289f99f", "0x977e3e967eff19290a192cd11df3667d511b398fb3ac9a5114a0f3707e25a0edcb56105648b1b85a8b7519fc529fc6f6", "0xb873a7c88bf58731fe1bf61ff6828bf114cf5228f254083304a4570e854e83748fc98683ddba62d978fff7909f2c5c47", "0xad4b2691f6f19da1d123aaa23cca3e876247ed9a4ab23c599afdbc0d3aa49776442a7ceaa996ac550d0313d9b9a36cee", "0xb9210713c78e19685608c6475bfa974b57ac276808a443f8b280945c5d5f9c39da43effa294bfb1a6c6f7b6b9f85bf6c", "0xa65152f376113e61a0e468759de38d742caa260291b4753391ee408dea55927af08a4d4a9918600a3bdf1df462dffe76", "0x8bf8c27ad5140dde7f3d2280fd4cc6b29ab76537e8d7aa7011a9d2796ee3e56e9a60c27b5c2da6c5e14fc866301dc195", "0x92fde8effc9f61393a2771155812b863cff2a0c5423d7d40aa04d621d396b44af94ddd376c28e7d2f53c930aea947484", "0x97a01d1dd9ee30553ce676011aea97fa93d55038ada95f0057d2362ae9437f3ed13de8290e2ff21e3167dd7ba10b9c3f", "0x89affffaa63cb2df3490f76f0d1e1d6ca35c221dd34057176ba739fa18d492355e6d2a5a5ad93a136d3b1fed0bb8aa19", "0x928b8e255a77e1f0495c86d3c63b83677b4561a5fcbbe5d3210f1e0fc947496e426d6bf3b49394a5df796c9f25673fc4", "0x842a0af91799c9b533e79ee081efe2a634cac6c584c2f054fb7d1db67dde90ae36de36cbf712ec9cd1a0c7ee79e151ea", "0xa65b946cf637e090baf2107c9a42f354b390e7316beb8913638130dbc67c918926eb87bec3b1fe92ef72bc77a170fa3b", "0xaafc0f19bfd71ab5ae4a8510c7861458b70ad062a44107b1b1dbacbfa44ba3217028c2824bd7058e2fa32455f624040b", "0x95269dc787653814e0be899c95dba8cfa384f575a25e671c0806fd80816ad6797dc819d30ae06e1d0ed9cb01c3950d47", "0xa1e760f7fa5775a1b2964b719ff961a92083c5c617f637fc46e0c9c20ab233f8686f7f38c3cb27d825c54dd95e93a59b", "0xac3b8a7c2317ea967f229eddc3e23e279427f665c4705c7532ed33443f1243d33453c1088f57088d2ab1e3df690a9cc9", "0xb787beeddfbfe36dd51ec4efd9cf83e59e84d354c3353cc9c447be53ae53d366ed1c59b686e52a92f002142c8652bfe0", "0xb7a64198300cb6716aa7ac6b25621f8bdec46ad5c07a27e165b3f774cdf65bcfdbf31e9bae0c16b44de4b00ada7a4244", "0xb8ae9f1452909e0c412c7a7fe075027691ea8df1347f65a5507bc8848f1d2c833d69748076db1129e5b4fb912f65c86c", "0x9682e41872456b9fa67def89e71f06d362d6c8ca85c9c48536615bc401442711e1c9803f10ab7f8ab5feaec0f9df20a6", "0x88889ff4e271dc1c7e21989cc39f73cde2f0475acd98078281591ff6c944fadeb9954e72334319050205d745d4df73df", "0x8f79b5b8159e7fd0d93b0645f3c416464f39aec353b57d99ecf24f96272df8a068ad67a6c90c78d82c63b40bb73989bb", "0x838c01a009a3d8558a3f0bdd5e22de21af71ca1aefc8423c91dc577d50920e9516880e87dce3e6d086e11cd45c9052d9", "0xb97f1c6eee8a78f137c840667cc288256e39294268a3009419298a04a1d0087c9c9077b33c917c65caf76637702dda8a", "0x972284ce72f96a61c899260203dfa06fc3268981732bef74060641c1a5068ead723e3399431c247ca034b0dae861e8df", "0x945a8d52d6d3db6663dbd3110c6587f9e9c44132045eeffba15621576d178315cb52870fa5861669f84f0bee646183fe", "0xa0a547b5f0967b1c3e5ec6c6a9a99f0578521489180dfdfbb5561f4d166baac43a2f06f950f645ce991664e167537eed", "0xa0592cda5cdddf1340033a745fd13a6eff2021f2e26587116c61c60edead067e0f217bc2bef4172a3c9839b0b978ab35", "0xb9c223b65a3281587fa44ec829e609154b32f801fd1de6950e01eafb07a8324243b960d5735288d0f89f0078b2c42b5b", "0x99ebfc3b8f9f98249f4d37a0023149ed85edd7a5abe062c8fb30c8c84555258b998bdcdd1d400bc0fa2a4aaa8b224466", "0x955b68526e6cb3937b26843270f4e60f9c6c8ece2fa9308fe3e23afa433309c068c66a4bc16ee2cf04220f095e9afce4", "0xb766caeafcc00378135ae53397f8a67ed586f5e30795462c4a35853de6681b1f17401a1c40958de32b197c083b7279c1", "0x921bf87cad947c2c33fa596d819423c10337a76fe5a63813c0a9dc78a728207ae7b339407a402fc4d0f7cba3af6da6fc", "0xa74ba1f3bc3e6c025db411308f49b347ec91da1c916bda9da61e510ec8d71d25e0ac0f124811b7860e5204f93099af27", "0xa29b4d144e0bf17a7e8353f2824cef0ce85621396babe8a0b873ca1e8a5f8d508b87866cf86da348470649fceefd735c", "0xa8040e12ffc3480dd83a349d06741d1572ef91932c46f5cf03aee8454254156ee95786fd013d5654725e674c920cec32", "0x8c4cf34ca60afd33923f219ffed054f90cd3f253ffeb2204a3b61b0183417e366c16c07fae860e362b0f2bfe3e1a1d35", "0x8195eede4ddb1c950459df6c396b2e99d83059f282b420acc34220cadeed16ab65c856f2c52568d86d3c682818ed7b37", "0x91fff19e54c15932260aa990c7fcb3c3c3da94845cc5aa8740ef56cf9f58d19b4c3c55596f8d6c877f9f4d22921d93aa", "0xa3e0bf7e5d02a80b75cf75f2db7e66cb625250c45436e3c136d86297d652590ec97c2311bafe407ad357c79ab29d107b", "0x81917ff87e5ed2ae4656b481a63ced9e6e5ff653b8aa6b7986911b8bc1ee5b8ef4f4d7882c3f250f2238e141b227e510", "0x915fdbe5e7de09c66c0416ae14a8750db9412e11dc576cf6158755fdcaf67abdbf0fa79b554cac4fe91c4ec245be073f", "0x8df27eafb5c3996ba4dc5773c1a45ca77e626b52e454dc1c4058aa94c2067c18332280630cc3d364821ee53bf2b8c130", "0x934f8a17c5cbb827d7868f5c8ca00cb027728a841000a16a3428ab16aa28733f16b52f58c9c4fbf75ccc45df72d9c4df", "0xb83f4da811f9183c25de8958bc73b504cf790e0f357cbe74ef696efa7aca97ad3b7ead1faf76e9f982c65b6a4d888fc2", "0x87188213c8b5c268dc2b6da413f0501c95749e953791b727450af3e43714149c115b596b33b63a2f006a1a271b87efd0", "0x83e9e888ab9c3e30761de635d9aabd31248cdd92f7675fc43e4b21fd96a03ec1dc4ad2ec94fec857ffb52683ac98e360", "0xb4b9a1823fe2d983dc4ec4e3aaea297e581c3fc5ab4b4af5fa1370caa37af2d1cc7fc6bfc5e7da60ad8fdce27dfe4b24", "0x856388bc78aef465dbcdd1f559252e028c9e9a2225c37d645c138e78f008f764124522705822a61326a6d1c79781e189", "0xa6431b36db93c3b47353ba22e7c9592c9cdfb9cbdd052ecf2cc3793f5b60c1e89bc96e6bae117bfd047f2308da00dd2f", "0xb619972d48e7e4291542dcde08f7a9cdc883c892986ded2f23ccb216e245cd8d9ad1d285347b0f9d7611d63bf4cee2bc", "0x8845cca6ff8595955f37440232f8e61d5351500bd016dfadd182b9d39544db77a62f4e0102ff74dd4173ae2c181d24ef", "0xb2f5f7fa26dcd3b6550879520172db2d64ee6aaa213cbef1a12befbce03f0973a22eb4e5d7b977f466ac2bf8323dcedd", "0x858b7f7e2d44bdf5235841164aa8b4f3d33934e8cb122794d90e0c1cac726417b220529e4f896d7b77902ab0ccd35b3a", "0x80b0408a092dae2b287a5e32ea1ad52b78b10e9c12f49282976cd738f5d834e03d1ad59b09c5ccaccc39818b87d06092", "0xb996b0a9c6a2d14d984edcd6ab56bc941674102980d65b3ad9733455f49473d3f587c8cbf661228a7e125ddbe07e3198", "0x90224fcebb36865293bd63af786e0c5ade6b67c4938d77eb0cbae730d514fdd0fe2d6632788e858afd29d46310cf86df", "0xb71351fdfff7168b0a5ec48397ecc27ac36657a8033d9981e97002dcca0303e3715ce6dd3f39423bc8ef286fa2e9e669", "0xae2a3f078b89fb753ce4ed87e0c1a58bb19b4f0cfb6586dedb9fcab99d097d659a489fb40e14651741e1375cfc4b6c5f", "0x8ef476b118e0b868caed297c161f4231bbeb863cdfa5e2eaa0fc6b6669425ce7af50dc374abceac154c287de50c22307", "0x92e46ab472c56cfc6458955270d3c72b7bde563bb32f7d4ab4d959db6f885764a3d864e1aa19802fefaa5e16b0cb0b54", "0x96a3f68323d1c94e73d5938a18a377af31b782f56212de3f489d22bc289cf24793a95b37f1d6776edf88114b5c1fa695", "0x962cc068cfce6faaa27213c4e43e44eeff0dfbb6d25b814e82c7da981fb81d7d91868fa2344f05fb552362f98cfd4a72", "0x895d4e4c4ad670abf66d43d59675b1add7afad7438ada8f42a0360c704cee2060f9ac15b4d27e9b9d0996bb801276fe3", "0xb3ad18d7ece71f89f2ef749b853c45dc56bf1c796250024b39a1e91ed11ca32713864049c9aaaea60cde309b47486bbf", "0x8f05404e0c0258fdbae50e97ccb9b72ee17e0bd2400d9102c0dad981dac8c4c71585f03e9b5d50086d0a2d3334cb55d1", "0x8bd877e9d4591d02c63c6f9fc9976c109de2d0d2df2bfa5f6a3232bab5b0b8b46e255679520480c2d7a318545efa1245", "0x8d4c16b5d98957c9da13d3f36c46f176e64e5be879f22be3179a2c0e624fe4758a82bf8c8027410002f973a3b84cd55a", "0x86e2a8dea86427b424fa8eada881bdff896907084a495546e66556cbdf070b78ba312bf441eb1be6a80006d25d5097a3", "0x8608b0c117fd8652fdab0495b08fadbeba95d9c37068e570de6fddfef1ba4a1773b42ac2be212836141d1bdcdef11a17", "0xa13d6febf5fb993ae76cae08423ca28da8b818d6ef0fde32976a4db57839cd45b085026b28ee5795f10a9a8e3098c683", "0x8e261967fa6de96f00bc94a199d7f72896a6ad8a7bbb1d6187cca8fad824e522880e20f766620f4f7e191c53321d70f9", "0x8b8e8972ac0218d7e3d922c734302803878ad508ca19f5f012bc047babd8a5c5a53deb5fe7c15a4c00fd6d1cb9b1dbd0", "0xb5616b233fb3574a2717d125a434a2682ff68546dccf116dd8a3b750a096982f185614b9fb6c7678107ff40a451f56fa", "0xaa6adf9b0c3334b0d0663f583a4914523b2ac2e7adffdb026ab9109295ff6af003ef8357026dbcf789896d2afded8d73", "0xacb72df56a0b65496cd534448ed4f62950bb1e11e50873b6ed349c088ee364441821294ce0f7c61bd7d38105bea3b442", "0xabae12df83e01ec947249fedd0115dc501d2b03ff7232092979eda531dbbca29ace1d46923427c7dde4c17bdf3fd7708", "0x820b4fc2b63a9fda7964acf5caf19a2fc4965007cb6d6b511fcafcb1f71c3f673a1c0791d3f86e3a9a1eb6955b191cc0", "0xaf277259d78c6b0f4f030a10c53577555df5e83319ddbad91afbd7c30bc58e7671c56d00d66ec3ab5ef56470cd910cee", "0xad4a861c59f1f5ca1beedd488fb3d131dea924fffd8e038741a1a7371fad7370ca5cf80dc01f177fbb9576713bb9a5b3", "0xb67a5162982ce6a55ccfb2f177b1ec26b110043cf18abd6a6c451cf140b5af2d634591eb4f28ad92177d8c7e5cd0a5e8", "0x96176d0a83816330187798072d449cbfccff682561e668faf6b1220c9a6535b32a6e4f852e8abb00f79abb87493df16b", "0xb0afe6e7cb672e18f0206e4423f51f8bd0017bf464c4b186d46332c5a5847647f89ff7fa4801a41c1b0b42f6135bcc92", "0x8fc5e7a95ef20c1278c645892811f6fe3f15c431ebc998a32ec0da44e7213ea934ed2be65239f3f49b8ec471e9914160", "0xb7793e41adda6c82ba1f2a31f656f6205f65bf8a3d50d836ee631bc7ce77c153345a2d0fc5c60edf8b37457c3729c4ec", "0xa504dd7e4d6b2f4379f22cc867c65535079c75ccc575955f961677fa63ecb9f74026fa2f60c9fb6323c1699259e5e9c8", "0xab899d00ae693649cc1afdf30fb80d728973d2177c006e428bf61c7be01e183866614e05410041bc82cb14a33330e69c", "0x8a3bd8b0b1be570b65c4432a0f6dc42f48a2000e30ab089cf781d38f4090467b54f79c0d472fcbf18ef6a00df69cc6f3", "0xb4d7028f7f76a96a3d7803fca7f507ae11a77c5346e9cdfccb120a833a59bda1f4264e425aa588e7a16f8e7638061d84", "0xb9c7511a76ea5fb105de905d44b02edb17008335766ee357ed386b7b3cf19640a98b38785cb14603c1192bee5886c9b6", "0x8563afb12e53aed71ac7103ab8602bfa8371ae095207cb0d59e8fd389b6ad1aff0641147e53cb6a7ca16c7f37c9c5e6b", "0x8e108be614604e09974a9ed90960c28c4ea330a3d9a0cb4af6dd6f193f84ab282b243ecdf549b3131036bebc8905690c", "0xb794d127fbedb9c5b58e31822361706ffac55ce023fbfe55716c3c48c2fd2f2c7660a67346864dfe588812d369cb50b6", "0xb797a3442fc3b44f41baefd30346f9ac7f96e770d010d53c146ce74ce424c10fb62758b7e108b8abfdc5fafd89d745cb", "0x993bb71e031e8096442e6205625e1bfddfe6dd6a83a81f3e2f84fafa9e5082ab4cad80a099f21eff2e81c83457c725c3", "0x8711ab833fc03e37acf2e1e74cfd9133b101ff4144fe30260654398ae48912ab46549d552eb9d15d2ea57760d35ac62e", "0xb21321fd2a12083863a1576c5930e1aecb330391ef83326d9d92e1f6f0d066d1394519284ddab55b2cb77417d4b0292f", "0x877d98f731ffe3ee94b0b5b72d127630fa8a96f6ca4f913d2aa581f67732df6709493693053b3e22b0181632ac6c1e3b", "0xae391c12e0eb8c145103c62ea64f41345973311c3bf7281fa6bf9b7faafac87bcf0998e5649b9ef81e288c369c827e07", "0xb83a2842f36998890492ab1cd5a088d9423d192681b9a3a90ec518d4c541bce63e6c5f4df0f734f31fbfdd87785a2463", "0xa21b6a790011396e1569ec5b2a423857b9bec16f543e63af28024e116c1ea24a3b96e8e4c75c6537c3e4611fd265e896", "0xb4251a9c4aab3a495da7a42e684ba4860dbcf940ad1da4b6d5ec46050cbe8dab0ab9ae6b63b5879de97b905723a41576", "0x8222f70aebfe6ac037f8543a08498f4cadb3edaac00336fc00437eb09f2cba758f6c38e887cc634b4d5b7112b6334836", "0x86f05038e060594c46b5d94621a1d9620aa8ba59a6995baf448734e21f58e23c1ea2993d3002ad5250d6edd5ba59b34f", "0xa7c0c749baef811ab31b973c39ceb1d94750e2bc559c90dc5eeb20d8bb6b78586a2b363c599ba2107d6be65cd435f24e", "0x861d46a5d70b38d6c1cd72817a2813803d9f34c00320c8b62f8b9deb67f5b5687bc0b37c16d28fd017367b92e05da9ca", "0xb3365d3dab639bffbe38e35383686a435c8c88b397b717cd4aeced2772ea1053ceb670f811f883f4e02975e5f1c4ac58", "0xa5750285f61ab8f64cd771f6466e2c0395e01b692fd878f2ef2d5c78bdd8212a73a3b1dfa5e4c8d9e1afda7c84857d3b", "0x835a10809ccf939bc46cf950a33b36d71be418774f51861f1cd98a016ade30f289114a88225a2c11e771b8b346cbe6ef", "0xa4f59473a037077181a0a62f1856ec271028546ca9452b45cedfcb229d0f4d1aabfc13062b07e536cc8a0d4b113156a2", "0x95cd14802180b224d44a73cc1ed599d6c4ca62ddcaa503513ccdc80aaa8be050cc98bd4b4f3b639549beb4587ac6caf9", "0x973b731992a3e69996253d7f36dd7a0af1982b5ed21624b77a7965d69e9a377b010d6dabf88a8a97eec2a476259859cc", "0xaf8a1655d6f9c78c8eb9a95051aa3baaf9c811adf0ae8c944a8d3fcba87b15f61021f3baf6996fa0aa51c81b3cb69de1", "0x835aad5c56872d2a2d6c252507b85dd742bf9b8c211ccb6b25b52d15c07245b6d89b2a40f722aeb5083a47cca159c947", "0xabf4e970b02bef8a102df983e22e97e2541dd3650b46e26be9ee394a3ea8b577019331857241d3d12b41d4eacd29a3ac", "0xa13c32449dbedf158721c13db9539ae076a6ce5aeaf68491e90e6ad4e20e20d1cdcc4a89ed9fd49cb8c0dd50c17633c1", "0x8c8f78f88b7e22dd7e9150ab1c000f10c28e696e21d85d6469a6fe315254740f32e73d81ab1f3c1cf8f544c86df506e8", "0xb4b77f2acfe945abf81f2605f906c10b88fb4d28628487fb4feb3a09f17f28e9780445dfcee4878349d4c6387a9d17d4", "0x8d255c235f3812c6ecc646f855fa3832be5cb4dbb9c9e544989fafdf3f69f05bfd370732eaf954012f0044aa013fc9c6", "0xb982efd3f34b47df37c910148ac56a84e8116647bea24145a49e34e0a6c0176e3284d838dae6230cb40d0be91c078b85", "0x983f365aa09bd85df2a6a2ad8e4318996b1e27d02090755391d4486144e40d80b1fbfe1c798d626db92f52e33aa634da", "0x95fd1981271f3ea3a41d654cf497e6696730d9ff7369f26bc4d7d15c7adb4823dd0c42e4a005a810af12d234065e5390", "0xa9f5219bd4b913c186ef30c02f995a08f0f6f1462614ea5f236964e02bdaa33db9d9b816c4aee5829947840a9a07ba60", "0x9210e6ceb05c09b46fd09d036287ca33c45124ab86315e5d6911ff89054f1101faaa3e83d123b7805056d388bcec6664", "0x8ed9cbf69c6ff3a5c62dd9fe0d7264578c0f826a29e614bc2fb4d621d90c8c9992438accdd7a614b1dca5d1bb73dc315", "0x85cf2a8cca93e00da459e3cecd22c342d697eee13c74d5851634844fc215f60053cf84b0e03c327cb395f48d1c71a8a4", "0x8818a18e9a2ec90a271b784400c1903089ffb0e0b40bc5abbbe12fbebe0f731f91959d98c5519ef1694543e31e2016d4", "0x8dabc130f296fa7a82870bf9a8405aaf542b222ed9276bba9bd3c3555a0f473acb97d655ee7280baff766a827a8993f0", "0xac7952b84b0dc60c4d858f034093b4d322c35959605a3dad2b806af9813a4680cb038c6d7f4485b4d6b2ff502aaeca25", "0xad65cb6d57b48a2602568d2ec8010baed0eb440eec7638c5ec8f02687d764e9de5b5d42ad5582934e592b48471c22d26", "0xa02ab8bd4c3d114ea23aebdd880952f9495912817da8c0c08eabc4e6755439899d635034413d51134c72a6320f807f1c", "0x8319567764b8295402ec1ebef4c2930a138480b37e6d7d01c8b4c9cd1f2fc3f6e9a44ae6e380a0c469b25b06db23305f", "0xafec53b2301dc0caa8034cd9daef78c48905e6068d692ca23d589b84a6fa9ddc2ed24a39480597e19cb3e83eec213b3f", "0xac0b4ffdb5ae08e586a9cdb98f9fe56f4712af3a97065e89e274feacfb52b53c839565aee93c4cfaaccfe51432c4fab0", "0x8972cbf07a738549205b1094c5987818124144bf187bc0a85287c94fdb22ce038c0f11df1aa16ec5992e91b44d1af793", "0xb7267aa6f9e3de864179b7da30319f1d4cb2a3560f2ea980254775963f1523b44c680f917095879bebfa3dc2b603efcf", "0x80f68f4bfc337952e29504ee5149f15093824ea7ab02507efd1317a670f6cbc3611201848560312e3e52e9d9af72eccf", "0x8897fee93ce8fc1e1122e46b6d640bba309384dbd92e46e185e6364aa8210ebf5f9ee7e5e604b6ffba99aa80a10dd7d0", "0xb58ea6c02f2360be60595223d692e82ee64874fda41a9f75930f7d28586f89be34b1083e03bbc1575bbfdda2d30db1ea", "0x85a523a33d903280d70ac5938770453a58293480170c84926457ac2df45c10d5ff34322ab130ef4a38c916e70d81af53", "0xa2cbf045e1bed38937492c1f2f93a5ba41875f1f262291914bc1fc40c60bd0740fb3fea428faf6da38b7c180fe8ac109", "0x8c09328770ed8eb17afc6ac7ddd87bb476de18ed63cab80027234a605806895959990c47bd10d259d7f3e2ecb50074c9", "0xb4b9e19edb4a33bde8b7289956568a5b6b6557404e0a34584b5721fe6f564821091013fbb158e2858c6d398293bb4b59", "0x8a47377df61733a2aa5a0e945fce00267f8e950f37e109d4487d92d878fb8b573317bb382d902de515b544e9e233458d", "0xb5804c9d97efeff5ca94f3689b8088c62422d92a1506fd1d8d3b1b30e8a866ad0d6dad4abfa051dfc4471250cac4c5d9", "0x9084a6ee8ec22d4881e9dcc8a9eb3c2513523d8bc141942370fd191ad2601bf9537a0b1e84316f3209b3d8a54368051e", "0x85447eea2fa26656a649f8519fa67279183044791d61cf8563d0783d46d747d96af31d0a93507bbb2242666aa87d3720", "0x97566a84481027b60116c751aec552adfff2d9038e68d48c4db9811fb0cbfdb3f1d91fc176a0b0d988a765f8a020bce1", "0xae87e5c1b9e86c49a23dceda4ecfd1dcf08567f1db8e5b6ec752ebd45433c11e7da4988573cdaebbb6f4135814fc059e", "0xabee05cf9abdbc52897ac1ce9ed157f5466ed6c383d6497de28616238d60409e5e92619e528af8b62cc552bf09970dc2", "0xae6d31cd7bf9599e5ee0828bab00ceb4856d829bba967278a73706b5f388465367aa8a6c7da24b5e5f1fdd3256ef8e63", "0xac33e7b1ee47e1ee4af472e37ab9e9175260e506a4e5ce449788075da1b53c44cb035f3792d1eea2aa24b1f688cc6ed3", "0x80f65b205666b0e089bb62152251c48c380a831e5f277f11f3ef4f0d52533f0851c1b612267042802f019ec900dc0e8f", "0x858520ad7aa1c9fed738e3b583c84168f2927837ad0e1d326afe9935c26e9b473d7f8c382e82ef1fe37d2b39bb40a1ee", "0xb842dd4af8befe00a97c2d0f0c33c93974761e2cb9e5ab8331b25170318ddd5e4bdbc02d8f90cbfdd5f348f4f371c1f7", "0x8bf2cb79bc783cb57088aae7363320cbeaabd078ffdec9d41bc74ff49e0043d0dad0086a30e5112b689fd2f5a606365d", "0x982eb03bbe563e8850847cd37e6a3306d298ab08c4d63ab6334e6b8c1fa13fce80cf2693b09714c7621d74261a0ff306", "0xb143edb113dec9f1e5105d4a93fbe502b859e587640d3db2f628c09a17060e6aec9e900e2c8c411cda99bc301ff96625", "0xaf472d9befa750dcebc5428fe1a024f18ec1c07bca0f95643ce6b5f4189892a910285afb03fd7ed7068fbe614e80d33c", "0xa97e3bc57ede73ecd1bbf02de8f51b4e7c1a067da68a3cd719f4ba26a0156cbf1cef2169fd35a18c5a4cced50d475998", "0xa862253c937cf3d75d7183e5f5be6a4385d526aeda5171c1c60a8381fea79f88f5f52a4fab244ecc70765d5765e6dfd5", "0x90cb776f8e5a108f1719df4a355bebb04bf023349356382cae55991b31720f0fd03206b895fa10c56c98f52453be8778", "0xa7614e8d0769dccd520ea4b46f7646e12489951efaef5176bc889e9eb65f6e31758df136b5bf1e9107e68472fa9b46ec", "0xac3a9b80a3254c42e5ed3a090a0dd7aee2352f480de96ad187027a3bb6c791eddfc3074b6ffd74eea825188f107cda4d", "0x82a01d0168238ef04180d4b6e0a0e39024c02c2d75b065017c2928039e154d093e1af4503f4d1f3d8a948917abb5d09f", "0x8fab000a2b0eef851a483aec8d2dd85fe60504794411a2f73ed82e116960547ac58766cb73df71aea71079302630258d", "0x872451a35c6db61c63e9b8bb9f16b217f985c20be4451c14282c814adb29d7fb13f201367c664435c7f1d4d9375d7a58", "0x887d9ff54cc96b35d562df4a537ff972d7c4b3fd91ab06354969a4cfede0b9fc68bbffb61d0dbf1a58948dc701e54f5a", "0x8cb5c2a6bd956875d88f41ae24574434f1308514d44057b55c9c70f13a3366ed054150eed0955a38fda3f757be73d55f", "0x89ad0163cad93e24129d63f8e38422b7674632a8d0a9016ee8636184cab177659a676c4ee7efba3abe1a68807c656d60", "0xb9ec01c7cab6d00359b5a0b4a1573467d09476e05ca51a9227cd16b589a9943d161eef62dcc73f0de2ec504d81f4d252", "0x8031d17635d39dfe9705c485d2c94830b6fc9bc67b91300d9d2591b51e36a782e77ab5904662effa9382d9cca201f525", "0x8be5a5f6bc8d680e5092d6f9a6585acbaaaa2ddc671da560dcf5cfa4472f4f184b9597b5b539438accd40dda885687cc", "0xb1fc0f052fae038a2e3de3b3a96b0a1024b009de8457b8b3adb2d315ae68a89af905720108a30038e5ab8d0d97087785", "0x8b8bdc77bd3a6bc7ca5492b6f8c614852c39a70d6c8a74916eaca0aeb4533b11898b8820a4c2620a97bf35e275480029", "0xaf35f4dc538d4ad5cdf710caa38fd1eb496c3fa890a047b6a659619c5ad3054158371d1e88e0894428282eed9f47f76b", "0x8166454a7089cc07758ad78724654f4e7a1a13e305bbf88ddb86f1a4b2904c4fc8ab872d7da364cdd6a6c0365239e2ad", "0xab287c7d3addce74ce40491871c768abe01daaa0833481276ff2e56926b38a7c6d2681ffe837d2cc323045ad1a4414f9", "0xb90317f4505793094d89365beb35537f55a6b5618904236258dd04ca61f21476837624a2f45fef8168acf732cab65579", "0x98ae5ea27448e236b6657ab5ef7b1cccb5372f92ab25f5fa651fbac97d08353a1dae1b280b1cd42b17d2c6a70a63ab9d", "0xadcf54e752d32cbaa6cb98fbca48d8cd087b1db1d131d465705a0d8042c8393c8f4d26b59006eb50129b21e6240f0c06", "0xb591a3e4db18a7345fa935a8dd7994bbac5cc270b8ebd84c8304c44484c7a74afb45471fdbe4ab22156a30fae1149b40", "0x806b53ac049a42f1dcc1d6335505371da0bf27c614f441b03bbf2e356be7b2fb4eed7117eabcce9e427a542eaa2bf7d8", "0x800482e7a772d49210b81c4a907f5ce97f270b959e745621ee293cf8c71e8989363d61f66a98f2d16914439544ca84c7", "0x99de9eafdad3617445312341644f2bb888680ff01ce95ca9276b1d2e5ef83fa02dab5e948ebf66c17df0752f1bd37b70", "0x961ee30810aa4c93ae157fbe9009b8e443c082192bd36a73a6764ff9b2ad8b0948fe9a73344556e01399dd77badb4257", "0xae0a361067c52efbe56c8adf982c00432cd478929459fc7f74052c8ee9531cd031fe1335418fde53f7c2ef34254eb7ac", "0xa3503d16b6b27eb20c1b177bcf90d13706169220523a6271b85b2ce35a9a2b9c5bed088540031c0a4ebfdae3a4c6ab04", "0x909420122c3e723289ca4e7b81c2df5aff312972a2203f4c45821b176e7c862bf9cac7f7df3adf1d59278f02694d06e7", "0x989f42380ae904b982f85d0c6186c1aef5d6bcba29bcfbb658e811b587eb2749c65c6e4a8cc6409c229a107499a4f5d7", "0x8037a6337195c8e26a27ea4ef218c6e7d79a9720aaab43932d343192abc2320fe72955f5e431c109093bda074103330a", "0xb312e168663842099b88445e940249cc508f080ab0c94331f672e7760258dbd86be5267e4cf25ea25facb80bff82a7e9", "0xaaa3ff8639496864fcdbfdda1ac97edc4f08e3c9288b768f6c8073038c9fbbf7e1c4bea169b4d45c31935cdf0680d45e", "0x97dbd3df37f0b481a311dfc5f40e59227720f367912200d71908ef6650f32cc985cb05b981e3eea38958f7e48d10a15d", "0xa89d49d1e267bb452d6cb621b9a90826fe55e9b489c0427b94442d02a16f390eed758e209991687f73f6b5a032321f42", "0x9530dea4e0e19d6496f536f2e75cf7d814d65fde567055eb20db48fd8d20d501cd2a22fb506db566b94c9ee10f413d43", "0x81a7009b9e67f1965fa7da6a57591c307de91bf0cd35ab4348dc4a98a4961e096d004d7e7ad318000011dc4342c1b809", "0x83440a9402b766045d7aca61a58bba2aa29cac1cf718199e472ba086f5d48093d9dda4d135292ba51d049a23964eceae", "0xa06c9ce5e802df14f6b064a3d1a0735d429b452f0e2e276042800b0a4f16df988fd94cf3945921d5dd3802ab2636f867", "0xb1359e358b89936dee9e678a187aad3e9ab14ac40e96a0a68f70ee2583cdcf467ae03bef4215e92893f4e12f902adec8", "0x835304f8619188b4d14674d803103d5a3fa594d48e96d9699e653115dd05fdc2dda6ba3641cf7ad53994d448da155f02", "0x8327cba5a9ff0d3f5cd0ae55e77167448926d5fcf76550c0ad978092a14122723090c51c415e88e42a2b62eb07cc3981", "0xb373dcdaea85f85ce9978b1426a7ef4945f65f2d3467a9f1cc551a99766aac95df4a09e2251d3f89ca8c9d1a7cfd7b0e", "0xab1422dc41af2a227b973a6fd124dfcb2367e2a11a21faa1d381d404f51b7257e5bc82e9cf20cd7fe37d7ae761a2ab37", "0xa93774a03519d2f20fdf2ef46547b0a5b77c137d6a3434b48d56a2cbef9e77120d1b85d0092cf8842909213826699477", "0x8eb967a495a38130ea28711580b7e61bcd1d051cd9e4f2dbf62f1380bd86e0d60e978d72f6f31e909eb97b3b9a2b867c", "0xae8213378da1287ba1fe4242e1acaec19b877b6fe872400013c6eac1084b8d03156792fa3020201725b08228a1e80f49", "0xb143daf6893d674d607772b3b02d8ac48f294237e2f2c87963c0d4e26d9227d94a2a13512457c3d5883544bbc259f0ef", "0xb343bd2aca8973888e42542218924e2dda2e938fd1150d06878af76f777546213912b7c7a34a0f94186817d80ffa185c", "0xb188ebc6a8c3007001aa347ae72cc0b15d09bc6c19a80e386ee4b334734ec0cc2fe8b493c2422f38d1e6d133cc3db6fe", "0xb795f6a8b9b826aaeee18ccd6baf6c5adeeec85f95eb5b6d19450085ec7217e95a2d9e221d77f583b297d0872073ba0e", "0xb1c7dbd998ad32ae57bfa95deafa147024afd57389e98992c36b6e52df915d3d5a39db585141ec2423173e85d212fed8", "0x812bcdeb9fe5f12d0e1df9964798056e1f1c3de3b17b6bd2919b6356c4b86d8e763c01933efbe0224c86a96d5198a4be", "0xb19ebeda61c23d255cbf472ef0b8a441f4c55b70f0d8ed47078c248b1d3c7c62e076b43b95c00a958ec8b16d5a7cb0d7", "0xb02adc9aaa20e0368a989c2af14ff48b67233d28ebee44ff3418bb0473592e6b681af1cc45450bd4b175df9051df63d9", "0x8d87f0714acee522eb58cec00360e762adc411901dba46adc9227124fa70ee679f9a47e91a6306d6030dd4eb8de2f3c1", "0x8be54cec21e74bcc71de29dc621444263737db15f16d0bb13670f64e42f818154e04b484593d19ef95f2ee17e4b3fe21", "0xab8e20546c1db38d31493b5d5f535758afb17e459645c1b70813b1cf7d242fd5d1f4354a7c929e8f7259f6a25302e351", "0x89f035a1ed8a1e302ac893349ba8ddf967580fcb6e73d44af09e3929cde445e97ff60c87dafe489e2c0ab9c9986cfa00", "0x8b2b0851a795c19191a692af55f7e72ad2474efdc5401bc3733cfdd910e34c918aaebe69d5ea951bdddf3c01cabbfc67", "0xa4edb52c2b51495ccd1ee6450fc14b7b3ede8b3d106808929d02fb31475bacb403e112ba9c818d2857651e508b3a7dd1", "0x9569341fded45d19f00bcf3cbf3f20eb2b4d82ef92aba3c8abd95866398438a2387437e580d8b646f17cf6fde8c5af23", "0xaa4b671c6d20f72f2f18a939a6ff21cc37e0084b44b4a717f1be859a80b39fb1be026b3205adec2a66a608ec2bcd578f", "0x94902e980de23c4de394ad8aec91b46f888d18f045753541492bfbb92c59d3daa8de37ae755a6853744af8472ba7b72b", "0xaf651ef1b2a0d30a7884557edfad95b6b5d445a7561caebdc46a485aedd25932c62c0798465c340a76f6feaa196dd712", "0xb7b669b8e5a763452128846dd46b530dca4893ace5cc5881c7ddcd3d45969d7e73fbebdb0e78aa81686e5f7b22ec5759", "0x82507fd4ebe9fa656a7f2e084d64a1fa6777a2b0bc106d686e2d9d2edafc58997e58cb6bfd0453b2bf415704aa82ae62", "0xb40bce2b42b88678400ecd52955bbdadd15f8b9e1b3751a1a3375dc0efb5ca3ee258cf201e1140b3c09ad41217d1d49e", "0xb0210d0cbb3fbf3b8cdb39e862f036b0ff941cd838e7aaf3a8354e24246e64778d22f3de34572e6b2a580614fb6425be", "0x876693cba4301b251523c7d034108831df3ce133d8be5a514e7a2ca494c268ca0556fa2ad8310a1d92a16b55bcd99ea9", "0x8660281406d22a4950f5ef050bf71dd3090edb16eff27fa29ef600cdea628315e2054211ed2cc6eaf8f2a1771ef689fd", "0xa610e7e41e41ab66955b809ba4ade0330b8e9057d8efc9144753caed81995edeb1a42a53f93ce93540feca1fae708dac", "0xa49e2c176a350251daef1218efaccc07a1e06203386ede59c136699d25ca5cb2ac1b800c25b28dd05678f14e78e51891", "0x83e0915aa2b09359604566080d411874af8c993beba97d4547782fdbe1a68e59324b800ff1f07b8db30c71adcbd102a8", "0xa19e84e3541fb6498e9bb8a099c495cbfcad113330e0262a7e4c6544495bb8a754b2208d0c2d895c93463558013a5a32", "0x87f2bd49859a364912023aca7b19a592c60214b8d6239e2be887ae80b69ebdeb59742bdebcfa73a586ab23b2c945586c", "0xb8e8fdddae934a14b57bc274b8dcd0d45ebb95ddbaabef4454e0f6ce7d3a5a61c86181929546b3d60c447a15134d08e1", "0x87e0c31dcb736ea4604727e92dc1d9a3cf00adcff79df3546e02108355260f3dd171531c3c0f57be78d8b28058fcc8c0", "0x9617d74e8f808a4165a8ac2e30878c349e1c3d40972006f0787b31ea62d248c2d9f3fc3da83181c6e57e95feedfd0e8c", "0x8949e2cee582a2f8db86e89785a6e46bc1565c2d8627d5b6bf43ba71ffadfab7e3c5710f88dcb5fb2fc6edf6f4fae216", "0xad3fa7b0edceb83118972a2935a09f409d09a8db3869f30be3a76f67aa9fb379cabb3a3aff805ba023a331cad7d7eb64", "0x8c95718a4112512c4efbd496be38bf3ca6cdcaad8a0d128f32a3f9aae57f3a57bdf295a3b372a8c549fda8f4707cffed", "0x88f3261d1e28a58b2dee3fcc799777ad1c0eb68b3560f9b4410d134672d9533532a91ea7be28a041784872632d3c9d80", "0xb47472a41d72dd2e8b72f5c4f8ad626737dde3717f63d6bc776639ab299e564cbad0a2ad5452a07f02ff49a359c437e5", "0x9896d21dc2e8aad87b76d6df1654f10cd7bceed4884159d50a818bea391f8e473e01e14684814c7780235f28e69dca6e", "0x82d47c332bbd31bbe83b5eb44a23da76d4a7a06c45d7f80f395035822bc27f62f59281d5174e6f8e77cc9b5c3193d6f0", "0x95c74cd46206e7f70c9766117c34c0ec45c2b0f927a15ea167901a160e1530d8522943c29b61e03568aa0f9c55926c53", "0xa89d7757825ae73a6e81829ff788ea7b3d7409857b378ebccd7df73fdbe62c8d9073741cf038314971b39af6c29c9030", "0x8c1cd212d0b010905d560688cfc036ae6535bc334fa8b812519d810b7e7dcf1bb7c5f43deaa40f097158358987324a7f", "0xb86993c383c015ed8d847c6b795164114dd3e9efd25143f509da318bfba89389ea72a420699e339423afd68b6512fafb", "0x8d06bd379c6d87c6ed841d8c6e9d2d0de21653a073725ff74be1934301cc3a79b81ef6dd0aad4e7a9dc6eac9b73019bc", "0x81af4d2d87219985b9b1202d724fe39ef988f14fef07dfe3c3b11714e90ffba2a97250838e8535eb63f107abfe645e96", "0x8c5e0af6330a8becb787e4b502f34f528ef5756e298a77dc0c7467433454347f3a2e0bd2641fbc2a45b95e231c6e1c02", "0x8e2a8f0f04562820dc8e7da681d5cad9fe2e85dd11c785fb6fba6786c57a857e0b3bd838fb849b0376c34ce1665e4837", "0xa39be8269449bfdfc61b1f62077033649f18dae9bef7c6163b9314ca8923691fb832f42776f0160b9e8abd4d143aa4e1", "0x8c154e665706355e1cc98e0a4cabf294ab019545ba9c4c399d666e6ec5c869ca9e1faf8fb06cd9c0a5c2f51a7d51b70a", "0xa046a7d4de879d3ebd4284f08f24398e9e3bf006cd4e25b5c67273ade248689c69affff92ae810c07941e4904296a563", "0xafd94c1cb48758e5917804df03fb38a6da0e48cd9b6262413ea13b26973f9e266690a1b7d9d24bbaf7e82718e0e594b0", "0x859e21080310c8d6a38e12e2ac9f90a156578cdeb4bb2e324700e97d9a5511cd6045dc39d1d0de3f94aeed043a24119d", "0xa219fb0303c379d0ab50893264919f598e753aac9065e1f23ef2949abc992577ab43c636a1d2c089203ec9ddb941e27d", "0xb0fdb639d449588a2ca730afcba59334e7c387342d56defdfb7ef79c493f7fd0e5277eff18e7203e756c7bdda5803047", "0x87f9c3b7ed01f54368aca6dbcf2f6e06bff96e183c4b2c65f8baa23b377988863a0a125d5cdd41a072da8462ced4c070", "0x99ef7a5d5ac2f1c567160e1f8c95f2f38d41881850f30c461a205f7b1b9fb181277311333839b13fb3ae203447e17727", "0xaeaca9b1c2afd24e443326cc68de67b4d9cedb22ad7b501a799d30d39c85bb2ea910d4672673e39e154d699e12d9b3dc", "0xa11675a1721a4ba24dd3d0e4c3c33a6edf4cd1b9f6b471070b4386c61f77452266eae6e3f566a40cfc885eada9a29f23", "0xb228334445e37b9b49cb4f2cc56b454575e92173ddb01370a553bba665adadd52df353ad74470d512561c2c3473c7bb9", "0xa18177087c996572d76f81178d18ed1ceebc8362a396348ce289f1d8bd708b9e99539be6fccd4acb1112381cfc5749b4", "0x8e7b8bf460f0d3c99abb19803b9e43422e91507a1c0c22b29ee8b2c52d1a384da4b87c292e28eff040db5be7b1f8641f", "0xb03d038d813e29688b6e6f444eb56fec3abba64c3d6f890a6bcf2e916507091cdb2b9d2c7484617be6b26552ed1c56cb", "0xa1c88ccd30e934adfc5494b72655f8afe1865a84196abfb376968f22ddc07761210b6a9fb7638f1413d1b4073d430290", "0x961b714faebf172ad2dbc11902461e286e4f24a99a939152a53406117767682a571057044decbeb3d3feef81f4488497", "0xa03dc4059b46effdd786a0a03cc17cfee8585683faa35bb07936ded3fa3f3a097f518c0b8e2db92fd700149db1937789", "0xadf60180c99ca574191cbcc23e8d025b2f931f98ca7dfcebfc380226239b6329347100fcb8b0fcb12db108c6ad101c07", "0x805d4f5ef24d46911cbf942f62cb84b0346e5e712284f82b0db223db26d51aabf43204755eb19519b00e665c7719fcaa", "0x8dea7243e9c139662a7fe3526c6c601eee72fd8847c54c8e1f2ad93ef7f9e1826b170afe58817dac212427164a88e87f", "0xa2ba42356606d651b077983de1ad643650997bb2babb188c9a3b27245bb65d2036e46667c37d4ce02cb1be5ae8547abe", "0xaf2ae50b392bdc013db2d12ce2544883472d72424fc767d3f5cb0ca2d973fc7d1f425880101e61970e1a988d0670c81b", "0x98e6bec0568d3939b31d00eb1040e9b8b2a35db46ddf4369bdaee41bbb63cc84423d29ee510a170fb5b0e2df434ba589", "0x822ff3cd12fbef4f508f3ca813c04a2e0b9b799c99848e5ad3563265979e753ee61a48f6adc2984a850f1b46c1a43d35", "0x891e8b8b92a394f36653d55725ef514bd2e2a46840a0a2975c76c2a935577f85289026aaa74384da0afe26775cbddfb9", "0xb2a3131a5d2fe7c8967047aa66e4524babae941d90552171cc109527f345f42aa0df06dcbb2fa01b33d0043917bbed69", "0x80c869469900431f3eeefafdbe07b8afd8cee7739e659e6d0109b397cacff85a88247698f87dc4e2fe39a592f250ac64", "0x9091594f488b38f9d2bb5df49fd8b4f8829d9c2f11a197dd1431ed5abbc5c954bbde3387088f9ee3a5a834beb7619bce", "0xb472e241e6956146cca57b97a8a204668d050423b4e76f857bad5b47f43b203a04c8391ba9d9c3e95093c071f9d376a1", "0xb7dd2de0284844392f7dfb56fe7ca3ede41e27519753ffc579a0a8d2d65ceb8108d06b6b0d4c3c1a2588951297bd1a1e", "0x902116ce70d0a079ac190321c1f48701318c05f8e69ee09694754885d33a835a849cafe56f499a2f49f6cda413ddf9a7", "0xb18105cc736787fafaf7c3c11c448bce9466e683159dff52723b7951dff429565e466e4841d982e3aaa9ee2066838666", "0x97ab9911f3f659691762d568ae0b7faa1047b0aed1009c319fa79d15d0db8db9f808fc385dc9a68fa388c10224985379", "0xb2a2cba65f5b927e64d2904ba412e2bac1cf18c9c3eda9c72fb70262497ecf505b640827e2afebecf10eebbcf48ccd3e", "0xb36a3fd677baa0d3ef0dac4f1548ff50a1730286b8c99d276a0a45d576e17b39b3cbadd2fe55e003796d370d4be43ce3", "0xa5dfec96ca3c272566e89dc453a458909247e3895d3e44831528130bc47cc9d0a0dac78dd3cad680a4351d399d241967", "0x8029382113909af6340959c3e61db27392531d62d90f92370a432aec3eb1e4c36ae1d4ef2ba8ec6edb4d7320c7a453f6", "0x971d85121ea108e6769d54f9c51299b0381ece8b51d46d49c89f65bedc123bab4d5a8bc14d6f67f4f680077529cbae4c", "0x98ff6afc01d0bec80a278f25912e1b1ebff80117adae72e31d5b9fa4d9624db4ba2065b444df49b489b0607c45e26c4c", "0x8fa29be10fb3ab30ce25920fec0187e6e91e458947009dabb869aade7136c8ba23602682b71e390c251f3743164cbdaa", "0xb3345c89eb1653418fe3940cf3e56a9a9c66526389b98f45ca02dd62bfb37baa69a4baaa7132d7320695f8ea6ad1fd94", "0xb72c7f5541c9ac6b60a7ec9f5415e7fb14da03f7164ea529952a29399f3a071576608dbbcc0d45994f21f92ddbeb1e19", "0xaa3450bb155a5f9043d0ef95f546a2e6ade167280bfb75c9f09c6f9cdb1fffb7ce8181436161a538433afa3681c7a141", "0x92a18fecaded7854b349f441e7102b638ababa75b1b0281dd0bded6541abe7aa37d96693595be0b01fe0a2e2133d50f9", "0x980756ddf9d2253cfe6c94960b516c94889d09e612810935150892627d2ecee9a2517e04968eea295d0106850c04ca44", "0xae68c6ccc454318cdd92f32b11d89116a3b8350207a36d22a0f626718cad671d960090e054c0c77ac3162ae180ecfd4b", "0x99f31f66eaaa551749ad91d48a0d4e3ff4d82ef0e8b28f3184c54e852422ba1bdafd53b1e753f3a070f3b55f3c23b6a2", "0xa44eaeaa6589206069e9c0a45ff9fc51c68da38d4edff1d15529b7932e6f403d12b9387019c44a1488a5d5f27782a51f", "0xb80b5d54d4b344840e45b79e621bd77a3f83fb4ce6d8796b7d6915107b3f3c34d2e7d95bdafd120f285669e5acf2437a", "0xb36c069ec085a612b5908314d6b84c00a83031780261d1c77a0384c406867c9847d5b0845deddfa512cc04a8df2046fb", "0xb09dbe501583220f640d201acea7ee3e39bf9eda8b91aa07b5c50b7641d86d71acb619b38d27835ce97c3759787f08e9", "0x87403d46a2bf63170fff0b857acacf42ee801afe9ccba8e5b4aea967b68eac73a499a65ca46906c2eb4c8f27bc739faa", "0x82b93669f42a0a2aa5e250ffe6097269da06a9c02fcd1801abbad415a7729a64f830754bafc702e64600ba47671c2208", "0x8e3a3029be7edb8dd3ab1f8216664c8dc50d395f603736061d802cef77627db7b859ef287ed850382c13b4d22d6a2d80", "0x968e9ec7194ff424409d182ce0259acd950c384c163c04463bc8700a40b79beba6146d22b7fa7016875a249b7b31c602", "0x8b42c984bbe4996e0c20862059167c6bdc5164b1ffcd928f29512664459212d263e89f0f0e30eed4e672ffa5ed0b01b5", "0x96bac54062110dada905363211133f1f15dc7e4fd80a4c6e4a83bc9a0bcbbaba11cd2c7a13debcf0985e1a954c1da66b", "0xa16dc8a653d67a7cd7ae90b2fffac0bf1ca587005430fe5ba9403edd70ca33e38ba5661d2ed6e9d2864400d997626a62", "0xa68ab11a570a27853c8d67e491591dcba746bfbee08a2e75ae0790399130d027ed387f41ef1d7de8df38b472df309161", "0x92532b74886874447c0300d07eda9bbe4b41ed25349a3da2e072a93fe32c89d280f740d8ff70d5816793d7f2b97373cc", "0x88e35711b471e89218fd5f4d0eadea8a29405af1cd81974427bc4a5fb26ed60798daaf94f726c96e779b403a2cd82820", "0xb5c72aa4147c19f8c4f3a0a62d32315b0f4606e0a7025edc5445571eaf4daff64f4b7a585464821574dd50dbe1b49d08", "0x9305d9b4095258e79744338683fd93f9e657367b3ab32d78080e51d54eec331edbc224fad5093ebf8ee4bd4286757eb8", "0xb2a17abb3f6a05bcb14dc7b98321fa8b46d299626c73d7c6eb12140bf4c3f8e1795250870947af817834f033c88a59d6", "0xb3477004837dbd8ba594e4296f960fc91ab3f13551458445e6c232eb04b326da803c4d93e2e8dcd268b4413305ff84da", "0x924b4b2ebaafdcfdfedb2829a8bf46cd32e1407d8d725a5bd28bdc821f1bafb3614f030ea4352c671076a63494275a3f", "0x8b81b9ef6125c82a9bece6fdcb9888a767ac16e70527753428cc87c56a1236e437da8be4f7ecfe57b9296dc3ae7ba807", "0x906e19ec8b8edd58bdf9ae05610a86e4ea2282b1bbc1e8b00b7021d093194e0837d74cf27ac9916bdb8ec308b00da3da", "0xb41c5185869071760ac786078a57a2ab4e2af60a890037ac0c0c28d6826f15c2cf028fddd42a9b6de632c3d550bfbc14", "0xa646e5dec1b713ae9dfdf7bdc6cd474d5731a320403c7dfcfd666ffc9ae0cff4b5a79530e8df3f4aa9cb80568cb138e9", "0xb0efad22827e562bd3c3e925acbd0d9425d19057868608d78c2209a531cccd0f2c43dc5673acf9822247428ffa2bb821", "0xa94c19468d14b6f99002fc52ac06bbe59e5c472e4a0cdb225144a62f8870b3f10593749df7a2de0bd3c9476ce682e148", "0x803864a91162f0273d49271dafaab632d93d494d1af935aefa522768af058fce52165018512e8d6774976d52bd797e22", "0xa08711c2f7d45c68fb340ac23597332e1bcaec9198f72967b9921204b9d48a7843561ff318f87908c05a44fc35e3cc9d", "0x91c3cad94a11a3197ae4f9461faab91a669e0dddb0371d3cab3ed9aeb1267badc797d8375181130e461eadd05099b2a2", "0x81bdaaf48aae4f7b480fc13f1e7f4dd3023a41439ba231760409ce9292c11128ab2b0bdbbf28b98af4f97b3551f363af", "0x8d60f9df9fd303f625af90e8272c4ecb95bb94e6efc5da17b8ab663ee3b3f673e9f6420d890ccc94acf4d2cae7a860d8", "0xa7b75901520c06e9495ab983f70b61483504c7ff2a0980c51115d11e0744683ce022d76e3e09f4e99e698cbd21432a0d", "0x82956072df0586562fda7e7738226f694e1c73518dd86e0799d2e820d7f79233667192c9236dcb27637e4c65ef19d493", "0xa586beb9b6ffd06ad200957490803a7cd8c9bf76e782734e0f55e04a3dc38949de75dc607822ec405736c576cf83bca3", "0xa179a30d00def9b34a7e85607a447eea0401e32ab5abeee1a281f2acd1cf6ec81a178020666f641d9492b1bdf66f05a3", "0x83e129705c538787ed8e0fdc1275e6466a3f4ee21a1e6abedd239393b1df72244723b92f9d9d9339a0cab6ebf28f5a16", "0x811bd8d1e3722b64cd2f5b431167e7f91456e8bba2cc669d3fbbce7d553e29c3c19f629fcedd2498bc26d33a24891d17", "0xa243c030c858f1f60cccd26b45b024698cc6d9d9e6198c1ed4964a235d9f8d0baf9cde10c8e63dfaa47f8e74e51a6e85", "0xab839eb82e23ca52663281f863b55b0a3d6d4425c33ffb4eeb1d7979488ab068bf99e2a60e82cea4dc42c56c26cbfebe", "0x8b896f9bb21d49343e67aec6ad175b58c0c81a3ca73d44d113ae4354a0065d98eb1a5cafedaf232a2bb9cdc62152f309", "0xaf6230340cc0b66f5bf845540ed4fc3e7d6077f361d60762e488d57834c3e7eb7eacc1b0ed73a7d134f174a01410e50c", "0x88975e1b1af678d1b5179f72300a30900736af580dd748fd9461ef7afccc91ccd9bed33f9da55c8711a7635b800e831f", "0xa97486bb9047391661718a54b8dd5a5e363964e495eae6c692730264478c927cf3e66dd3602413189a3699fbeae26e15", "0xa5973c161ab38732885d1d2785fd74bf156ba34881980cba27fe239caef06b24a533ffe6dbbbeca5e6566682cc00300a", "0xa24776e9a840afda0003fa73b415d5bd6ecd9b5c2cc842b643ee51b8c6087f4eead4d0bfbd987eb174c489a7b952ff2a", "0xa8a6ee06e3af053b705a12b59777267c546f33ba8a0f49493af8e6df4e15cf8dd2d4fb4daf7e84c6b5d3a7363118ff03", "0xa28e59ce6ad02c2ce725067c0123117e12ac5a52c8f5af13eec75f4a9efc4f696777db18a374fa33bcae82e0734ebd16", "0x86dfc3b78e841c708aff677baa8ee654c808e5d257158715097c1025d46ece94993efe12c9d188252ad98a1e0e331fec", "0xa88d0275510f242eab11fdb0410ff6e1b9d7a3cbd3658333539815f1b450a84816e6613d15aa8a8eb15d87cdad4b27a2", "0x8440acea2931118a5b481268ff9f180ee4ede85d14a52c026adc882410825b8275caa44aff0b50c2b88d39f21b1a0696", "0xa7c3182eab25bd6785bacf12079d0afb0a9b165d6ed327814e2177148539f249eb9b5b2554538f54f3c882d37c0a8abe", "0x85291fbe10538d7da38efdd55a7acebf03b1848428a2f664c3ce55367aece60039f4f320b1771c9c89a35941797f717c", "0xa2c6414eeb1234728ab0de94aa98fc06433a58efa646ca3fcbd97dbfb8d98ae59f7ce6d528f669c8149e1e13266f69c9", "0x840c8462785591ee93aee2538d9f1ec44ba2ca61a569ab51d335ac873f5d48099ae8d7a7efa0725d9ff8f9475bfa4f56", "0xa7065a9d02fb3673acf7702a488fbc01aa69580964932f6f40b6c2d1c386b19e50b0e104fcac24ea26c4e723611d0238", "0xb72db6d141267438279e032c95e6106c2ccb3164b842ba857a2018f3a35f4b040da92680881eb17cd61d0920d5b8f006", "0xa8005d6c5960e090374747307ef0be2871a7a43fa4e76a16c35d2baab808e9777b496e9f57a4218b23390887c33a0b55", "0x8e152cea1e00a451ca47c20a1e8875873419700af15a5f38ee2268d3fbc974d4bd5f4be38008fa6f404dbdedd6e6e710", "0xa3391aed1fcd68761f06a7d1008ec62a09b1cb3d0203cd04e300a0c91adfed1812d8bc1e4a3fd7976dc0aae0e99f52f1", "0x967eb57bf2aa503ee0c6e67438098149eac305089c155f1762cf5e84e31f0fbf27c34a9af05621e34645c1ec96afaec8", "0x88af97ddc4937a95ec0dcd25e4173127260f91c8db2f6eac84afb789b363705fb3196235af631c70cafd09411d233589", "0xa32df75b3f2c921b8767638fd289bcfc61e08597170186637a7128ffedd52c798c434485ac2c7de07014f9e895c2c3d8", "0xb0a783832153650aa0d766a3a73ec208b6ce5caeb40b87177ffc035ab03c7705ecdd1090b6456a29f5fb7e90e2fa8930", "0xb59c8e803b4c3486777d15fc2311b97f9ded1602fa570c7b0200bada36a49ee9ef4d4c1474265af8e1c38a93eb66b18b", "0x982f2c85f83e852022998ff91bafbb6ff093ef22cf9d5063e083a48b29175ccbd51b9c6557151409e439096300981a6c", "0x939e3b5989fefebb9d272a954659a4eb125b98c9da6953f5e628d26266bd0525ec38304b8d56f08d65abc4d6da4a8dbb", "0x8898212fe05bc8de7d18503cb84a1c1337cc2c09d1eeef2b475aa79185b7322bf1f8e065f1bf871c0c927dd19faf1f6d", "0x94b0393a41cd00f724aee2d4bc72103d626a5aecb4b5486dd1ef8ac27528398edf56df9db5c3d238d8579af368afeb09", "0x96ac564450d998e7445dd2ea8e3fc7974d575508fa19e1c60c308d83b645864c029f2f6b7396d4ff4c1b24e92e3bac37", "0x8adf6638e18aff3eb3b47617da696eb6c4bdfbecbbc3c45d3d0ab0b12cbad00e462fdfbe0c35780d21aa973fc150285e", "0xb53f94612f818571b5565bbb295e74bada9b5f9794b3b91125915e44d6ddcc4da25510eab718e251a09c99534d6042d9", "0x8b96462508d77ee083c376cd90807aebad8de96bca43983c84a4a6f196d5faf6619a2351f43bfeec101864c3bf255519", "0xaeadf34657083fc71df33bd44af73bf5281c9ca6d906b9c745536e1819ea90b56107c55e2178ebad08f3ba75b3f81c86", "0x9784ba29b2f0057b5af1d3ab2796d439b8753f1f749c73e791037461bdfc3f7097394283105b8ab01788ea5255a96710", "0x8756241bda159d4a33bf74faba0d4594d963c370fb6a18431f279b4a865b070b0547a6d1613cf45b8cfb5f9236bbf831", "0xb03ebfd6b71421dfd49a30460f9f57063eebfe31b9ceaa2a05c37c61522b35bdc09d7db3ad75c76c253c00ba282d3cd2", "0xb34e7e6341fa9d854b2d3153bdda0c4ae2b2f442ab7af6f99a0975d45725aa48e36ae5f7011edd249862e91f499687d4", "0xb462ee09dc3963a14354244313e3444de5cc37ea5ccfbf14cd9aca8027b59c4cb2a949bc30474497cab8123e768460e6", "0xaea753290e51e2f6a21a9a0ee67d3a2713f95c2a5c17fe41116c87d3aa77b1683761264d704df1ac34f8b873bc88ef7b", "0x98430592afd414394f98ddfff9f280fcb1c322dbe3510f45e1e9c4bb8ee306b3e0cf0282c0ee73ebb8ba087d4d9e0858", "0xb95d3b5aaf54ffca11f4be8d57f76e14afdb20afc859dc7c7471e0b42031e8f3d461b726ecb979bdb2f353498dfe95ea", "0x984d17f9b11a683132e0b5a9ee5945e3ff7054c2d5c716be73b29078db1d36f54c6e652fd2f52a19da313112e97ade07", "0xab232f756b3fff3262be418a1af61a7e0c95ceebbc775389622a8e10610508cd6784ab7960441917a83cc191c58829ea", "0xa28f41678d6e60de76b0e36ab10e4516e53e02e9c77d2b5af3cfeee3ce94cfa30c5797bd1daab20c98e1cad83ad0f633", "0xb55395fca84dd3ccc05dd480cb9b430bf8631ff06e24cb51d54519703d667268c2f8afcde4ba4ed16bece8cc7bc8c6e0", "0x8a8a5392a0e2ea3c7a8c51328fab11156004e84a9c63483b64e8f8ebf18a58b6ffa8fe8b9d95af0a2f655f601d096396", "0xab480000fe194d23f08a7a9ec1c392334e9c687e06851f083845121ce502c06b54dda8c43092bcc1035df45cc752fe9b", "0xb265644c29f628d1c7e8e25a5e845cabb21799371814730a41a363e1bda8a7be50fee7c3996a365b7fcba4642add10db", "0xb8a915a3c685c2d4728f6931c4d29487cad764c5ce23c25e64b1a3259ac27235e41b23bfe7ae982921b4cb84463097df", "0x8efa7338442a4b6318145a5440fc213b97869647eeae41b9aa3c0a27ee51285b73e3ae3b4a9423df255e6add58864aa9", "0x9106d65444f74d217f4187dfc8fcf3810b916d1e4275f94f6a86d1c4f3565b131fd6cde1fa708bc05fe183c49f14941a", "0x948252dac8026bbbdb0a06b3c9d66ec4cf9532163bab68076fda1bd2357b69e4b514729c15aaa83b5618b1977bbc60c4", "0xae6596ccfdf5cbbc5782efe3bb0b101bb132dbe1d568854ca24cacc0b2e0e9fabcb2ca7ab42aecec412efd15cf8cb7a2", "0x84a0b6c198ff64fd7958dfd1b40eac9638e8e0b2c4cd8cf5d8cdf80419baee76a05184bce6c5b635f6bf2d30055476a7", "0x8893118be4a055c2b3da593dbca51b1ae2ea2469911acfb27ee42faf3e6c3ad0693d3914c508c0b05b36a88c8b312b76", "0xb097479e967504deb6734785db7e60d1d8034d6ca5ba9552887e937f5e17bb413fccac2c1d1082154ed76609127860ad", "0xa0294e6b9958f244d29943debf24b00b538b3da1116269b6e452bb12dc742226712fd1a15b9c88195afeb5d2415f505c", "0xb3cc15f635080bc038f61b615f62b5b5c6f2870586191f59476e8368a73641d6ac2f7d0c1f54621982defdb318020230", "0x99856f49b9fe1604d917c94d09cc0ed753d13d015d30587a94e6631ffd964b214e607deb8a69a8b5e349a7edf4309206", "0xa8571e113ea22b4b4fce41a094da8c70de37830ae32e62c65c2fa5ad06a9bc29e884b945e73d448c72b176d6ecebfb58", "0xa9e9c6e52beb0013273c29844956b3ce291023678107cdc785f7b44eff5003462841ad8780761b86aefc6b734adde7cf", "0x80a784b0b27edb51ef2bad3aee80e51778dcaa0f3f5d3dcb5dc5d4f4b2cf7ae35b08de6680ea9dac53f8438b92eb09ef", "0x827b543e609ea328e97e373f70ad72d4915a2d1daae0c60d44ac637231070e164c43a2a58db80a64df1c624a042b38f9", "0xb449c65e8195202efdcb9bdb4e869a437313b118fef8b510cbbf8b79a4e99376adb749b37e9c20b51b31ed3310169e27", "0x8ea3028f4548a79a94c717e1ed28ad4d8725b8d6ab18b021063ce46f665c79da3c49440c6577319dab2d036b7e08f387", "0x897798431cfb17fe39f08f5f854005dc37b1c1ec1edba6c24bc8acb3b88838d0534a75475325a5ea98b326ad47dbad75", "0x89cf232e6303b0751561960fd4dea5754a28c594daf930326b4541274ffb03c7dd75938e411eb9a375006a70ce38097f", "0x9727c6ae7f0840f0b6c8bfb3a1a5582ceee705e0b5c59b97def7a7a2283edd4d3f47b7971e902a3a2079e40b53ff69b8", "0xb76ed72b122c48679d221072efc0eeea063cb205cbf5f9ef0101fd10cb1075b8628166c83577cced654e1c001c7882f7", "0xae908c42d208759da5ee9b405df85a6532ea35c6f0f6a1288d22870f59d98edc896841b8ac890a538e6c8d1e8b02d359", "0x809d12fe4039a0ec80dc9be6a89acaab7797e5f7f9b163378f52f9a75a1d73b2e9ae6e3dd49e32ced439783c1cabbef5", "0xa4149530b7f85d1098ba534d69548c6c612c416e8d35992fc1f64f4deeb41e09e49c6cf7aadbed7e846b91299358fe2d", "0xa49342eacd1ec1148b8df1e253b1c015f603c39de11fa0a364ccb86ea32d69c34fd7aa6980a1fadcd8e785a57fa46f60", "0x87d43eff5a006dc4dddcf76cc96c656a1f3a68f19f124181feab86c6cc9a52cb9189cdbb423414defdd9bb0ca8ff1ddc", "0x861367e87a9aa2f0f68296ba50aa5dbc5713008d260cc2c7e62d407c2063064749324c4e8156dc21b749656cfebce26b", "0xb5303c2f72e84e170e66ae1b0fbd51b8c7a6f27476eaf5694b64e8737d5c84b51fe90100b256465a4c4156dd873cddb0", "0xb62849a4f891415d74f434cdc1d23c4a69074487659ca96e1762466b2b7a5d8525b056b891d0feea6fe6845cba8bc7fb", "0x923dd9e0d6590a9307e8c4c23f13bae3306b580e297a937711a8b13e8de85e41a61462f25b7d352b682e8437bf2b4ab3", "0x9147379860cd713cd46c94b8cdf75125d36c37517fbecf81ace9680b98ce6291cd1c3e472f84249cc3b2b445e314b1b6", "0xa808a4f17ac21e3fb5cfef404e61fae3693ca3e688d375f99b6116779696059a146c27b06de3ac36da349b0649befd56", "0x87787e9322e1b75e66c1f0d9ea0915722a232770930c2d2a95e9478c4b950d15ab767e30cea128f9ed65893bfc2d0743", "0x9036a6ee2577223be105defe1081c48ea7319e112fff9110eb9f61110c319da25a6cea0464ce65e858635b079691ef1f", "0xaf5548c7c24e1088c23b57ee14d26c12a83484c9fd9296edf1012d8dcf88243f20039b43c8c548c265ef9a1ffe9c1c88", "0xa0fff520045e14065965fb8accd17e878d3fcaf9e0af2962c8954e50be6683d31fa0bf4816ab68f08630dbac6bfce52a", "0xb4c1b249e079f6ae1781af1d97a60b15855f49864c50496c09c91fe1946266915b799f0406084d7783f5b1039116dd8b", "0x8b0ffa5e7c498cb3879dddca34743b41eee8e2dea3d4317a6e961b58adb699ef0c92400c068d5228881a2b08121226bf", "0x852ae8b19a1d80aa8ae5382e7ee5c8e7670ceb16640871c56b20b96b66b3b60e00015a3dde039446972e57b49a999ddd", "0xa49942f04234a7d8492169da232cfff8051df86e8e1ba3db46aede02422c689c87dc1d99699c25f96cb763f5ca0983e5", "0xb04b597b7760cf5dcf411ef896d1661e6d5b0db3257ac2cf64b20b60c6cc18fa10523bb958a48d010b55bac7b02ab3b1", "0xa494591b51ea8285daecc194b5e5bd45ae35767d0246ac94fae204d674ee180c8e97ff15f71f28b7aeb175b8aea59710", "0x97d2624919e78406e7460730680dea8e71c8571cf988e11441aeea54512b95bd820e78562c99372d535d96f7e200d20d", "0xac693ddb00e48f76e667243b9b6a7008424043fb779e4f2252330285232c3fccac4da25cbd6d95fe9ad959ff305a91f6", "0x8d20ca0a71a64a3f702a0825bb46bd810d03bebfb227683680d474a52f965716ff99e19a165ebaf6567987f4f9ee3c94", "0xa5c516a438f916d1d68ca76996404792e0a66e97b7f18fc54c917bf10cf3211b62387932756e39e67e47b0bd6e88385a", "0xb089614d830abc0afa435034cec7f851f2f095d479cacf1a3fb57272da826c499a52e7dcbc0eb85f4166fb94778e18e9", "0xa8dacc943765d930848288192f4c69e2461c4b9bc6e79e30eeef9a543318cf9ae9569d6986c65c5668a89d49993f8e07", "0xab5a9361fa339eec8c621bdad0a58078983abd8942d4282b22835d7a3a47e132d42414b7c359694986f7db39386c2e19", "0x94230517fb57bd8eb26c6f64129b8b2abd0282323bf7b94b8bac7fab27b4ecc2c4290c294275e1a759de19f2216134f3", "0xb8f158ea5006bc3b90b285246625faaa6ac9b5f5030dc69701b12f3b79a53ec7e92eeb5a63bbd1f9509a0a3469ff3ffc", "0x8b6944fd8cb8540957a91a142fdcda827762aa777a31e8810ca6d026e50370ee1636fc351724767e817ca38804ebe005", "0x82d1ee40fe1569c29644f79fa6c4033b7ed45cd2c3b343881f6eb0de2e79548fded4787fae19bed6ee76ed76ff9f2f11", "0xa8924c7035e99eaed244ca165607e7e568b6c8085510dcdbaf6ebdbed405af2e6c14ee27d94ffef10d30aa52a60bf66d", "0x956f82a6c2ae044635e85812581e4866c5fa2f427b01942047d81f6d79a14192f66fbbe77c9ffeaef4e6147097fdd2b5", "0xb1100255a1bcf5e05b6aff1dfeb6e1d55b5d68d43a7457ba10cc76b61885f67f4d0d5179abda786e037ae95deb8eea45", "0x99510799025e3e5e8fbf06dedb14c060c6548ba2bda824f687d3999dc395e794b1fb6514b9013f3892b6cf65cb0d65aa", "0x8f9091cebf5e9c809aab415942172258f894e66e625d7388a05289183f01b8d994d52e05a8e69f784fba41db9ea357f0", "0xa13d2eeb0776bdee9820ecb6693536720232848c51936bb4ef4fe65588d3f920d08a21907e1fdb881c1ad70b3725e726", "0xa68b8f18922d550284c5e5dc2dda771f24c21965a6a4d5e7a71678178f46df4d8a421497aad8fcb4c7e241aba26378a0", "0x8b7601f0a3c6ad27f03f2d23e785c81c1460d60100f91ea9d1cab978aa03b523150206c6d52ce7c7769c71d2c8228e9e", "0xa8e02926430813caa851bb2b46de7f0420f0a64eb5f6b805401c11c9091d3b6d67d841b5674fa2b1dce0867714124cd8", "0xb7968ecba568b8193b3058400af02c183f0a6df995a744450b3f7e0af7a772454677c3857f99c140bbdb2a09e832e8e0", "0x8f20b1e9ba87d0a3f35309b985f3c18d2e8800f1ca7f0c52cadef773f1496b6070c936eea48c4a1cae83fd2524e9d233", "0x88aef260042db0d641a51f40639dbeeefa9e9811df30bee695f3791f88a2f84d318f04e8926b7f47bf25956cb9e3754f", "0x9725345893b647e9ba4e6a29e12f96751f1ae25fcaec2173e9a259921a1a7edb7a47159b3c8767e44d9e2689f5aa0f72", "0x8c281e6f72752cb11e239e4df9341c45106eb7993c160e54423c2bffe10bc39d42624b45a1f673936ef2e1a02fc92f1a", "0x90aba2f68bddb2fcce6c51430dacdfeec43ea8dc379660c99095df11017691ccf5faa27665cf4b9f0eea7728ae53c327", "0xb7022695c16521c5704f49b7ddbdbec9b5f57ce0ceebe537bc0ebb0906d8196cc855a9afeb8950a1710f6a654464d93f", "0x8fe1b9dd3c6a258116415d36e08374e094b22f0afb104385a5da48be17123e86fb8327baacc4f0d9ebae923d55d99bb5", "0x817e85d8e3d19a4cbc1dec31597142c2daa4871bda89c2177fa719c00eda3344eb08b82eb92d4aa91a9eaacb3fc09783", "0xb59053e1081d2603f1ca0ba553804d6fa696e1fd996631db8f62087b26a40dfef02098b0326bb75f99ec83b9267ca738", "0x990a173d857d3ba81ff3789b931bfc9f5609cde0169b7f055fa3cb56451748d593d62d46ba33f80f9cafffe02b68dd14", "0xb0c538dbba4954b809ab26f9f94a3cf1dcb77ce289eaec1d19f556c0ae4be1fa03af4a9b7057837541c3cc0a80538736", "0xac3ba42f5f44f9e1fc453ce49c4ab79d0e1d5c42d3b30b1e098f3ab3f414c4c262fa12fb2be249f52d4aaf3c5224beb9", "0xaf47467eb152e59870e21f0d4da2f43e093daf40180ab01438030684b114d025326928eaab12c41b81a066d94fce8436", "0x98d1b58ba22e7289b1c45c79a24624f19b1d89e00f778eef327ec4856a9a897278e6f1a9a7e673844b31dde949153000", "0x97ccb15dfadc7c59dca08cfe0d22df2e52c684cf97de1d94bc00d7ba24e020025130b0a39c0f4d46e4fc872771ee7875", "0xb699e4ed9a000ff96ca296b2f09dce278832bc8ac96851ff3cff99ed3f6f752cfc0fea8571be28cd9b5a7ec36f1a08ee", "0xb9f49f0edb7941cc296435ff0a912e3ad16848ee8765ab5f60a050b280d6ea585e5b34051b15f6b8934ef01ceb85f648", "0xac3893df7b4ceab23c6b9054e48e8ba40d6e5beda8fbe90b814f992f52494186969b35d8c4cdc3c99890a222c9c09008", "0xa41293ad22fae81dea94467bc1488c3707f3d4765059173980be93995fa4fcc3c9340796e3eed0beeb0ba0d9bb4fa3aa", "0xa0543e77acd2aeecde13d18d258aeb2c7397b77f17c35a1992e8666ea7abcd8a38ec6c2741bd929abba2f766138618cc", "0x92e79b22bc40e69f6527c969500ca543899105837b6b1075fa1796755c723462059b3d1b028e0b3df2559fa440e09175", "0xa1fa1eac8f41a5197a6fb4aa1eae1a031c89f9c13ff9448338b222780cf9022e0b0925d930c37501a0ef7b2b00fdaf83", "0xb3cb29ff73229f0637335f28a08ad8c5f166066f27c6c175164d0f26766a927f843b987ee9b309ed71cbf0a65d483831", "0x84d4ab787f0ac00f104f4a734dc693d62d48c2aeb03913153da62c2ae2c27d11b1110dcef8980368dd84682ea2c1a308", "0xab6a8e4bbc78d4a7b291ad3e9a8fe2d65f640524ba3181123b09d2d18a9e300e2509ccf7000fe47e75b65f3e992a2e7e", "0xb7805ebe4f1a4df414003dc10bca805f2ab86ca75820012653e8f9b79c405196b0e2cab099f2ab953d67f0d60d31a0f9", "0xb12c582454148338ea605d22bd00a754109063e22617f1f8ac8ddf5502c22a181c50c216c3617b9852aa5f26af56b323", "0x86333ad9f898947e31ce747728dc8c887479e18d36ff3013f69ebef807d82c6981543b5c3788af93c4d912ba084d3cba", "0xb514efa310dc4ad1258add138891e540d8c87142a881b5f46563cc58ecd1488e6d3a2fca54c0b72a929f3364ca8c333e", "0xaa0a30f92843cf2f484066a783a1d75a7aa6f41f00b421d4baf20a6ac7886c468d0eea7ca8b17dd22f4f74631b62b640", "0xb3b7dc63baec9a752e8433c0cdee4d0f9bc41f66f2b8d132faf925eef9cf89aae756fc132c45910f057122462605dc10", "0xb9b8190dac5bfdeb59fd44f4da41a57e7f1e7d2c21faba9da91fa45cbeca06dcf299c9ae22f0c89ece11ac46352d619f", "0x89f8cf36501ad8bdfeab863752a9090e3bfda57cf8fdeca2944864dc05925f501e252c048221bcc57136ab09a64b64b2", "0xb0cbfaf317f05f97be47fc9d69eda2dd82500e00d42612f271a1fe24626408c28881f171e855bd5bd67409f9847502b4", "0xa7c21a8fcede581bfd9847b6835eda62ba250bea81f1bb17372c800a19c732abe03064e64a2f865d974fb636cab4b859", "0x95f9df524ba7a4667351696c4176b505d8ea3659f5ff2701173064acc624af69a0fad4970963736383b979830cb32260", "0x856a74fe8b37a2e3afeac858c8632200485d438422a16ae3b29f359e470e8244995c63ad79c7e007ed063f178d0306fd", "0xb37faa4d78fdc0bb9d403674dbea0176c2014a171c7be8527b54f7d1a32a76883d3422a3e7a5f5fcc5e9b31b57822eeb", "0x8d37234d8594ec3fe75670b5c9cc1ec3537564d4739b2682a75b18b08401869a4264c0f264354219d8d896cded715db4", "0xb5289ee5737f0e0bde485d32096d23387d68dab8f01f47821ab4f06cc79a967afe7355e72dc0c751d96b2747b26f6255", "0x9085e1fdf9f813e9c3b8232d3c8863cd84ab30d45e8e0d3d6a0abd9ebc6fd70cdf749ff4d04390000e14c7d8c6655fc7", "0x93a388c83630331eca4da37ea4a97b3b453238af474817cc0a0727fd3138dcb4a22de38c04783ec829c22cb459cb4e8e", "0xa5377116027c5d061dbe24c240b891c08cdd8cd3f0899e848d682c873aff5b8132c1e7cfe76d2e5ed97ee0eb1d42cb68", "0xa274c84b04338ed28d74683e2a7519c2591a3ce37c294d6f6e678f7d628be2db8eff253ede21823e2df7183e6552f622", "0x8bc201147a842453a50bec3ac97671397bc086d6dfc9377fa38c2124cdc286abda69b7324f47d64da094ae011d98d9d9", "0x9842d0c066c524592b76fbec5132bc628e5e1d21c424bec4555efca8619cc1fd8ea3161febcb8b9e8ab54702f4e815e2", "0xa19191b713a07efe85c266f839d14e25660ee74452e6c691cd9997d85ae4f732052d802d3deb018bdd847caa298a894b", "0xa24f71fc0db504da4e287dd118a4a74301cbcd16033937ba2abc8417956fcb4ae19b8e63b931795544a978137eff51cb", "0xa90eec4a6a3a4b8f9a5b93d978b5026fcf812fe65585b008d7e08c4aaf21195a1d0699f12fc16f79b6a18a369af45771", "0x8b551cf89737d7d06d9b3b9c4c1c73b41f2ea0af4540999c70b82dabff8580797cf0a3caf34c86c59a7069eb2e38f087", "0xb8d312e6c635e7a216a1cda075ae77ba3e1d2fd501dc31e83496e6e81ed5d9c7799f8e578869c2e0e256fb29f5de10a7", "0x8d144bdb8cae0b2cdb5b33d44bbc96984a5925202506a8cc65eb67ac904b466f5a7fe3e1cbf04aa785bbb7348c4bb73c", "0xa101b3d58b7a98659244b88de0b478b3fb87dc5fc6031f6e689b99edf498abd43e151fd32bd4bbd240e0b3e59c440359", "0x907453abca7d8e7151a05cc3d506c988007692fe7401395dc93177d0d07d114ab6cca0cc658eb94c0223fe8658295cad", "0x825329ffbe2147ddb68f63a0a67f32d7f309657b8e5d9ab5bb34b3730bfa2c77a23eaaadb05def7d9f94a9e08fdc1e96", "0x88ee923c95c1dac99ae7ed6067906d734d793c5dc5d26339c1bb3314abe201c5dccb33b9007351885eb2754e9a8ea06c", "0x98bc9798543f5f1adc9f2cfcfa72331989420e9c3f6598c45269f0dc9b7c8607bbeaf03faa0aea2ddde2b8f17fdceff5", "0x8ee87877702a79aef923ab970db6fa81561b3c07d5bf1a072af0a7bad765b4cbaec910afe1a91703feacc7822fa38a94", "0x8060b9584aa294fe8adc2b22f67e988bc6da768eae91e429dcc43ddc53cfcc5d6753fdc1b420b268c7eb2fb50736a970", "0xb344a5524d80a2f051870c7001f74fcf348a70fcf78dbd20c6ff9ca85d81567d2318c8b8089f2c4f195d6aec9fc15fa6", "0x8f5a5d893e1936ed062149d20eb73d98b62b7f50ab5d93a6429c03656b36688d1c80cb5010e4977491e51fa0d7dd35d5", "0x86fa32ebbf97328c5f5f15564e1238297e289ec3219b9a741724e9f3ae8d5c15277008f555863a478b247ba5dc601d44", "0x9557e55377e279f4b6b5e0ffe01eca037cc13aac242d67dfcd0374a1e775c5ed5cb30c25fe21143fee54e3302d34a3ea", "0x8cb6bcbc39372d23464a416ea7039f57ba8413cf3f00d9a7a5b356ab20dcb8ed11b3561f7bce372b8534d2870c7ee270", "0xb5d59075cb5abde5391f64b6c3b8b50adc6e1f654e2a580b6d6d6eff3f4fbdd8fffc92e06809c393f5c8eab37f774c4b", "0xafcfb6903ef13e493a1f7308675582f15af0403b6553e8c37afb8b2808ad21b88b347dc139464367dc260df075fea1ad", "0x810fbbe808375735dd22d5bc7fc3828dc49fdd22cc2d7661604e7ac9c4535c1df578780affb3b895a0831640a945bcad", "0x8056b0c678803b416f924e09a6299a33cf9ad7da6fe1ad7accefe95c179e0077da36815fde3716711c394e2c5ea7127f", "0x8b67403702d06979be19f1d6dc3ec73cc2e81254d6b7d0cc49cd4fdda8cd51ab0835c1d2d26fc0ecab5df90585c2f351", "0x87f97f9e6d4be07e8db250e5dd2bffdf1390665bc5709f2b631a6fa69a7fca958f19bd7cc617183da1f50ee63e9352b5", "0xae151310985940471e6803fcf37600d7fa98830613e381e00dab943aec32c14162d51c4598e8847148148000d6e5af5c", "0x81eb537b35b7602c45441cfc61b27fa9a30d3998fad35a064e05bc9479e9f10b62eba2b234b348219eea3cadcaac64bb", "0x8a441434934180ab6f5bc541f86ebd06eadbee01f438836d797e930fa803a51510e005c9248cecc231a775b74d12b5e9", "0x81f3c250a27ba14d8496a5092b145629eb2c2e6a5298438670375363f57e2798207832c8027c3e9238ad94ecdadfc4df", "0xa6217c311f2f3db02ceaa5b6096849fe92b6f4b6f1491535ef8525f6ccee6130bed2809e625073ecbaddd4a3eb3df186", "0x82d1c396f0388b942cf22b119d7ef1ad03d3dad49a74d9d01649ee284f377c8daddd095d596871669e16160299a210db", "0xa40ddf7043c5d72a7246bd727b07f7fff1549f0e443d611de6f9976c37448b21664c5089c57f20105102d935ab82f27b", "0xb6c03c1c97adf0c4bf4447ec71366c6c1bff401ba46236cd4a33d39291e7a1f0bb34bd078ba3a18d15c98993b153a279", "0x8a94f5f632068399c359c4b3a3653cb6df2b207379b3d0cdace51afdf70d6d5cce6b89a2b0fee66744eba86c98fb21c2", "0xb2f19e78ee85073f680c3bba1f07fd31b057c00b97040357d97855b54a0b5accb0d3b05b2a294568fcd6a4be6f266950", "0xa74632d13bbe2d64b51d7a9c3ae0a5a971c19f51cf7596a807cea053e6a0f3719700976d4e394b356c0329a2dced9aa2", "0xafef616d341a9bc94393b8dfba68ff0581436aa3a3adb7c26a1bbf2cf19fa877066191681f71f17f3cd6f9cf6bf70b5a", "0x8ce96d93ae217408acf7eb0f9cbb9563363e5c7002e19bbe1e80760bc9d449daee2118f3878b955163ed664516b97294", "0x8414f79b496176bc8b8e25f8e4cfee28f4f1c2ddab099d63d2aca1b6403d26a571152fc3edb97794767a7c4686ad557c", "0xb6c61d01fd8ce087ef9f079bf25bf10090db483dd4f88c4a786d31c1bdf52065651c1f5523f20c21e75cea17df69ab73", "0xa5790fd629be70545093631efadddc136661f63b65ec682609c38ef7d3d7fa4e56bdf94f06e263bc055b90cb1c6bcefe", "0xb515a767e95704fb7597bca9e46f1753abacdc0e56e867ee3c6f4cd382643c2a28e65312c05ad040eaa3a8cbe7217a65", "0x8135806a02ead6aa92e9adb6fefb91349837ab73105aaa7be488ef966aa8dfaafdfa64bbae30fcbfa55dd135a036a863", "0x8f22435702716d76b1369750694540742d909d5e72b54d0878245fab7c269953b1c6f2b29c66f08d5e0263ca3a731771", "0x8e0f8a8e8753e077dac95848212aeffd51c23d9b6d611df8b102f654089401954413ecbedc6367561ca599512ae5dda7", "0x815a9084e3e2345f24c5fa559deec21ee1352fb60f4025c0779be65057f2d528a3d91593bd30d3a185f5ec53a9950676", "0x967e6555ccba395b2cc1605f8484c5112c7b263f41ce8439a99fd1c71c5ed14ad02684d6f636364199ca48afbbde13be", "0x8cd0ccf17682950b34c796a41e2ea7dd5367aba5e80a907e01f4cdc611e4a411918215e5aebf4292f8b24765d73314a6", "0xa58bf1bbb377e4b3915df6f058a0f53b8fb8130fdec8c391f6bc82065694d0be59bb67ffb540e6c42cc8b380c6e36359", "0x92af3151d9e6bfb3383d85433e953c0160859f759b0988431ec5893542ba40288f65db43c78a904325ef8d324988f09d", "0x8011bbb05705167afb47d4425065630f54cb86cd462095e83b81dfebf348f846e4d8fbcf1c13208f5de1931f81da40b9", "0x81c743c104fc3cb047885c9fa0fb9705c3a83ee24f690f539f4985509c3dafd507af3f6a2128276f45d5939ef70c167f", "0xa2c9679b151c041aaf5efeac5a737a8f70d1631d931609fca16be1905682f35e291292874cb3b03f14994f98573c6f44", "0xa4949b86c4e5b1d5c82a337e5ce6b2718b1f7c215148c8bfb7e7c44ec86c5c9476048fc5c01f57cb0920876478c41ad6", "0x86c2495088bd1772152e527a1da0ef473f924ea9ab0e5b8077df859c28078f73c4e22e3a906b507fdf217c3c80808b5c", "0x892e0a910dcf162bcea379763c3e2349349e4cda9402949255ac4a78dd5a47e0bf42f5bd0913951576b1d206dc1e536a", "0xa7009b2c6b396138afe4754b7cc10dee557c51c7f1a357a11486b3253818531f781ea8107360c8d4c3b1cd96282353c0", "0x911763ef439c086065cc7b4e57484ed6d693ea44acee4b18c9fd998116da55fbe7dcb8d2a0f0f9b32132fca82d73dff6", "0xa722000b95a4a2d40bed81870793f15ba2af633f9892df507f2842e52452e02b5ea8dea6a043c2b2611d82376e33742a", "0x9387ac49477bd719c2f92240d0bdfcf9767aad247ca93dc51e56106463206bc343a8ec855eb803471629a66fffb565d6", "0x92819a1fa48ab4902939bb72a0a4e6143c058ea42b42f9bc6cea5df45f49724e2530daf3fc4f097cceefa2a8b9db0076", "0x98eac7b04537653bc0f4941aae732e4b1f84bd276c992c64a219b8715eb1fb829b5cbd997d57feb15c7694c468f95f70", "0xb275e7ba848ce21bf7996e12dbeb8dadb5d0e4f1cb5a0248a4f8f9c9fe6c74e3c93f4b61edbcb0a51af5a141e1c14bc7", "0x97243189285aba4d49c53770c242f2faf5fd3914451da4931472e3290164f7663c726cf86020f8f181e568c72fd172d1", "0x839b0b3c25dd412bee3dc24653b873cc65454f8f16186bb707bcd58259c0b6765fa4c195403209179192a4455c95f3b8", "0x8689d1a870514568a074a38232e2ceb4d7df30fabeb76cff0aed5b42bf7f02baea12c5fadf69f4713464dbd52aafa55f", "0x8958ae7b290f0b00d17c3e9fdb4dbf168432b457c7676829299dd428984aba892de1966fc106cfc58a772862ecce3976", "0xa422bc6bd68b8870cfa5bc4ce71781fd7f4368b564d7f1e0917f6013c8bbb5b240a257f89ecfdbecb40fe0f3aa31d310", "0xaa61f78130cebe09bc9a2c0a37f0dd57ed2d702962e37d38b1df7f17dc554b1d4b7a39a44182a452ce4c5eb31fa4cfcc", "0xb7918bd114f37869bf1a459023386825821bfadce545201929d13ac3256d92a431e34f690a55d944f77d0b652cefeffc", "0x819bba35fb6ace1510920d4dcff30aa682a3c9af9022e287751a6a6649b00c5402f14b6309f0aeef8fce312a0402915e", "0x8b7c9ad446c6f63c11e1c24e24014bd570862b65d53684e107ba9ad381e81a2eaa96731b4b33536efd55e0f055071274", "0x8fe79b53f06d33386c0ec7d6d521183c13199498594a46d44a8a716932c3ec480c60be398650bbfa044fa791c4e99b65", "0x9558e10fb81250b9844c99648cf38fa05ec1e65d0ccbb18aa17f2d1f503144baf59d802c25be8cc0879fff82ed5034ad", "0xb538a7b97fbd702ba84645ca0a63725be1e2891c784b1d599e54e3480e4670d0025526674ef5cf2f87dddf2290ba09f0", "0x92eafe2e869a3dd8519bbbceb630585c6eb21712b2f31e1b63067c0acb5f9bdbbcbdb612db4ea7f9cc4e7be83d31973f", "0xb40d21390bb813ab7b70a010dff64c57178418c62685761784e37d327ba3cb9ef62df87ecb84277c325a637fe3709732", "0xb349e6fbf778c4af35fbed33130bd8a7216ed3ba0a79163ebb556e8eb8e1a7dad3456ddd700dad9d08d202491c51b939", "0xa8fdaedecb251f892b66c669e34137f2650509ade5d38fbe8a05d9b9184bb3b2d416186a3640429bd1f3e4b903c159dd", "0xac6167ebfee1dbab338eff7642f5e785fc21ef0b4ddd6660333fe398068cbd6c42585f62e81e4edbb72161ce852a1a4f", "0x874b1fbf2ebe140c683bd7e4e0ab017afa5d4ad38055aaa83ee6bbef77dbc88a6ce8eb0dcc48f0155244af6f86f34c2d", "0x903c58e57ddd9c446afab8256a6bb6c911121e6ccfb4f9b4ed3e2ed922a0e500a5cb7fa379d5285bc16e11dac90d1fda", "0x8dae7a0cffa2fd166859cd1bf10ff82dd1932e488af377366b7efc0d5dec85f85fe5e8150ff86a79a39cefc29631733a", "0xaa047857a47cc4dfc08585f28640420fcf105b881fd59a6cf7890a36516af0644d143b73f3515ab48faaa621168f8c31", "0x864508f7077c266cc0cb3f7f001cb6e27125ebfe79ab57a123a8195f2e27d3799ff98413e8483c533b46a816a3557f1f", "0x8bcd45ab1f9cbab36937a27e724af819838f66dfeb15923f8113654ff877bd8667c54f6307aaf0c35027ca11b6229bfd", "0xb21aa34da9ab0a48fcfdd291df224697ce0c1ebc0e9b022fdee8750a1a4b5ba421c419541ed5c98b461eecf363047471", "0xa9a18a2ab2fae14542dc336269fe612e9c1af6cf0c9ac933679a2f2cb77d3c304114f4d219ca66fe288adde30716775b", "0xb5205989b92c58bdda71817f9a897e84100b5c4e708de1fced5c286f7a6f01ae96b1c8d845f3a320d77c8e2703c0e8b1", "0xa364059412bbcc17b8907d43ac8e5df90bc87fd1724b5f99832d0d24559fae6fa76a74cff1d1eac8cbac6ec80b44af20", "0xae709f2c339886b31450834cf29a38b26eb3b0779bd77c9ac269a8a925d1d78ea3837876c654b61a8fe834b3b6940808", "0x8802581bba66e1952ac4dab36af371f66778958f4612901d95e5cac17f59165e6064371d02de8fb6fccf89c6dc8bd118", "0xa313252df653e29c672cbcfd2d4f775089cb77be1077381cf4dc9533790e88af6cedc8a119158e7da5bf6806ad9b91a1", "0x992a065b4152c7ef11515cd54ba9d191fda44032a01aed954acff3443377ee16680c7248d530b746b8c6dee2d634e68c", "0xb627b683ee2b32c1ab4ccd27b9f6cce2fe097d96386fa0e5c182ad997c4c422ab8dfc03870cd830b8c774feb66537282", "0xb823cf8a9aee03dadd013eb9efe40a201b4b57ef67efaae9f99683005f5d1bf55e950bf4af0774f50859d743642d3fea", "0xb8a7449ffac0a3f206677097baf7ce00ca07a4d2bd9b5356fbcb83f3649b0fda07cfebad220c1066afba89e5a52abf4b", "0xb2dd1a2f986395bb4e3e960fbbe823dbb154f823284ebc9068502c19a7609790ec0073d08bfa63f71e30c7161b6ef966", "0x98e5236de4281245234f5d40a25b503505af140b503a035fc25a26159a9074ec81512b28f324c56ea2c9a5aa7ce90805", "0x89070847dc8bbf5bc4ed073aa2e2a1f699cf0c2ca226f185a0671cecc54e7d3e14cd475c7752314a7a8e7476829da4bc", "0xa9402dc9117fdb39c4734c0688254f23aed3dce94f5f53f5b7ef2b4bf1b71a67f85ab1a38ec224a59691f3bee050aeb3", "0x957288f9866a4bf56a4204218ccc583f717d7ce45c01ea27142a7e245ad04a07f289cc044f8cf1f21d35e67e39299e9c", "0xb2fb31ccb4e69113763d7247d0fc8edaae69b550c5c56aecacfd780c7217dc672f9fb7496edf4aba65dacf3361268e5b", "0xb44a4526b2f1d6eb2aa8dba23bfa385ff7634572ab2afddd0546c3beb630fbfe85a32f42dd287a7fec069041411537f7", "0x8db5a6660c3ac7fd7a093573940f068ee79a82bc17312af900b51c8c439336bc86ca646c6b7ab13aaaa008a24ca508ab", "0x8f9899a6d7e8eb4367beb5c060a1f8e94d8a21099033ae582118477265155ba9e72176a67f7f25d7bad75a152b56e21a", "0xa67de0e91ade8d69a0e00c9ff33ee2909b8a609357095fa12319e6158570c232e5b6f4647522efb7345ce0052aa9d489", "0x82eb2414898e9c3023d57907a2b17de8e7eea5269029d05a94bfd7bf5685ac4a799110fbb375eb5e0e2bd16acf6458ae", "0x94451fc7fea3c5a89ba701004a9693bab555cb622caf0896b678faba040409fdfd14a978979038b2a81e8f0abc4994d2", "0xac879a5bb433998e289809a4a966bd02b4bf6a9c1cc276454e39c886efcf4fc68baebed575826bde577ab5aa71d735a9", "0x880c0f8f49c875dfd62b4ddedde0f5c8b19f5687e693717f7e5c031bc580e58e13ab497d48b4874130a18743c59fdce3", "0xb582af8d8ff0bf76f0a3934775e0b54c0e8fed893245d7d89cae65b03c8125b7237edc29dc45b4fe1a3fe6db45d280ee", "0x89f337882ed3ae060aaee98efa20d79b6822bde9708c1c5fcee365d0ec9297f694cae37d38fd8e3d49717c1e86f078e7", "0x826d2c1faea54061848b484e288a5f4de0d221258178cf87f72e14baaa4acc21322f8c9eab5dde612ef497f2d2e1d60b", "0xa5333d4f227543e9cd741ccf3b81db79f2f03ca9e649e40d6a6e8ff9073e06da83683566d3b3c8d7b258c62970fb24d1", "0xa28f08c473db06aaf4c043a2fae82b3c8cfaa160bce793a4c208e4e168fb1c65115ff8139dea06453c5963d95e922b94", "0x8162546135cc5e124e9683bdfaa45833c18553ff06a0861c887dc84a5b12ae8cd4697f6794c7ef6230492c32faba7014", "0xb23f0d05b74c08d6a7df1760792be83a761b36e3f8ae360f3c363fb196e2a9dd2de2e492e49d36561366e14daa77155c", "0xb6f70d6c546722d3907c708d630dbe289771d2c8bf059c2e32b77f224696d750b4dda9b3a014debda38e7d02c9a77585", "0x83bf4c4a9f3ca022c631017e7a30ea205ba97f7f5927cba8fc8489a4646eac6712cb821c5668c9ffe94d69d524374a27", "0xb0371475425a8076d0dd5f733f55aabbe42d20a7c8ea7da352e736d4d35a327b2beb370dfcb05284e22cfd69c5f6c4cc", "0xa0031ba7522c79211416c2cca3aa5450f96f8fee711552a30889910970ba13608646538781a2c08b834b140aadd7166f", "0x99d273c80c7f2dc6045d4ed355d9fc6f74e93549d961f4a3b73cd38683f905934d359058cd1fc4da8083c7d75070487f", "0xb0e4b0efa3237793e9dcce86d75aafe9879c5fa23f0d628649aef2130454dcf72578f9bf227b9d2b9e05617468e82588", "0xa5ab076fa2e1c5c51f3ae101afdd596ad9d106bba7882b359c43d8548b64f528af19afa76cd6f40da1e6c5fca4def3fa", "0x8ce2299e570331d60f6a6eff1b271097cd5f1c0e1113fc69b89c6a0f685dabea3e5bc2ac6bd789aa492ab189f89be494", "0x91b829068874d911a310a5f9dee001021f97471307b5a3de9ec336870ec597413e1d92010ce320b619f38bed7c4f7910", "0xb14fe91f4b07bf33b046e9285b66cb07927f3a8da0af548ac2569b4c4fb1309d3ced76d733051a20814e90dd5b75ffd1", "0xabaab92ea6152d40f82940277c725aa768a631ee0b37f5961667f82fb990fc11e6d3a6a2752b0c6f94563ed9bb28265c", "0xb7fe28543eca2a716859a76ab9092f135337e28109544f6bd2727728d0a7650428af5713171ea60bfc273d1c821d992c", "0x8a4917b2ab749fc7343fc64bdf51b6c0698ff15d740cc7baf248c030475c097097d5a473bcc00d8c25817563fe0447b4", "0xaa96156d1379553256350a0a3250166add75948fb9cde62aa555a0a9dc0a9cb7f2f7b8428aff66097bf6bfedaf14bbe2", "0xae4ffeb9bdc76830d3eca2b705f30c1bdede6412fa064260a21562c8850c7fb611ec62bc68479fe48f692833e6f66d8d", "0xb96543caaba9d051600a14997765d49e4ab10b07c7a92cccf0c90b309e6da334fdd6d18c96806cbb67a7801024fbd3c7", "0x97b2b9ad76f19f500fcc94ca8e434176249f542ac66e5881a3dccd07354bdab6a2157018b19f8459437a68d8b86ba8e0", "0xa8d206f6c5a14c80005849474fde44b1e7bcf0b2d52068f5f97504c3c035b09e65e56d1cf4b5322791ae2c2fdbd61859", "0x936bad397ad577a70cf99bf9056584a61bd7f02d2d5a6cf219c05d770ae30a5cd902ba38366ce636067fc1dd10108d31", "0xa77e30195ee402b84f3882e2286bf5380c0ed374a112dbd11e16cef6b6b61ab209d4635e6f35cdaaa72c1a1981d5dabe", "0xa46ba4d3947188590a43c180757886a453a0503f79cc435322d92490446f37419c7b999fdf868a023601078070e03346", "0x80d8d4c5542f223d48240b445d4d8cf6a75d120b060bc08c45e99a13028b809d910b534d2ac47fb7068930c54efd8da9", "0x803be9c68c91b42b68e1f55e58917a477a9a6265e679ca44ee30d3eb92453f8c89c64eafc04c970d6831edd33d066902", "0xb14b2b3d0dfe2bb57cee4cd72765b60ac33c1056580950be005790176543826c1d4fbd737f6cfeada6c735543244ab57", "0xa9e480188bba1b8fb7105ff12215706665fd35bf1117bacfb6ab6985f4dbc181229873b82e5e18323c2b8f5de03258e0", "0xa66a0f0779436a9a3999996d1e6d3000f22c2cac8e0b29cddef9636393c7f1457fb188a293b6c875b05d68d138a7cc4a", "0x848397366300ab40c52d0dbbdafbafef6cd3dadf1503bb14b430f52bb9724188928ac26f6292a2412bc7d7aa620763c8", "0x95466cc1a78c9f33a9aaa3829a4c8a690af074916b56f43ae46a67a12bb537a5ac6dbe61590344a25b44e8512355a4a7", "0x8b5f7a959f818e3baf0887f140f4575cac093d0aece27e23b823cf421f34d6e4ff4bb8384426e33e8ec7b5eed51f6b5c", "0x8d5e1368ec7e3c65640d216bcc5d076f3d9845924c734a34f3558ac0f16e40597c1a775a25bf38b187213fbdba17c93b", "0xb4647c1b823516880f60d20c5cc38c7f80b363c19d191e8992226799718ee26b522a12ecb66556ed3d483aa4824f3326", "0xac3abaea9cd283eb347efda4ed9086ea3acf495043e08d0d19945876329e8675224b685612a6badf8fd72fb6274902b1", "0x8eae1ce292d317aaa71bcf6e77e654914edd5090e2e1ebab78b18bb41b9b1bc2e697439f54a44c0c8aa0d436ebe6e1a9", "0x94dc7d1aec2c28eb43d93b111fa59aaa0d77d5a09501220bd411768c3e52208806abf973c6a452fd8292ff6490e0c9e2", "0x8fd8967f8e506fef27d17b435d6b86b232ec71c1036351f12e6fb8a2e12daf01d0ee04451fb944d0f1bf7fd20e714d02", "0x824e6865be55d43032f0fec65b3480ea89b0a2bf860872237a19a54bc186a85d2f8f9989cc837fbb325b7c72d9babe2c", "0x8bd361f5adb27fd6f4e3f5de866e2befda6a8454efeb704aacc606f528c03f0faae888f60310e49440496abd84083ce2", "0xb098a3c49f2aaa28b6b3e85bc40ce6a9cdd02134ee522ae73771e667ad7629c8d82c393fba9f27f5416986af4c261438", "0xb385f5ca285ff2cfe64dcaa32dcde869c28996ed091542600a0b46f65f3f5a38428cca46029ede72b6cf43e12279e3d3", "0x8196b03d011e5be5288196ef7d47137d6f9237a635ab913acdf9c595fa521d9e2df722090ec7eb0203544ee88178fc5f", "0x8ed1270211ef928db18e502271b7edf24d0bbd11d97f2786aee772d70c2029e28095cf8f650b0328cc8a4c38d045316d", "0xa52ab60e28d69b333d597a445884d44fd2a7e1923dd60f763951e1e45f83e27a4dac745f3b9eff75977b3280e132c15d", "0x91e9fe78cdac578f4a4687f71b800b35da54b824b1886dafec073a3c977ce7a25038a2f3a5b1e35c2c8c9d1a7312417c", "0xa42832173f9d9491c7bd93b21497fbfa4121687cd4d2ab572e80753d7edcbb42cfa49f460026fbde52f420786751a138", "0x97b947126d84dcc70c97be3c04b3de3f239b1c4914342fa643b1a4bb8c4fe45c0fcb585700d13a7ed50784790c54bef9", "0x860e407d353eac070e2418ef6cb80b96fc5f6661d6333e634f6f306779651588037be4c2419562c89c61f9aa2c4947f5", "0xb2c9d93c3ba4e511b0560b55d3501bf28a510745fd666b3cb532db051e6a8617841ea2f071dda6c9f15619c7bfd2737f", "0x8596f4d239aeeac78311207904d1bd863ef68e769629cc379db60e019aaf05a9d5cd31dc8e630b31e106a3a93e47cbc5", "0x8b26e14e2e136b65c5e9e5c2022cee8c255834ea427552f780a6ca130a6446102f2a6f334c3f9a0308c53df09e3dba7e", "0xb54724354eb515a3c8bed0d0677ff1db94ac0a07043459b4358cb90e3e1aa38ac23f2caa3072cf9647275d7cd61d0e80", "0xb7ce9fe0e515e7a6b2d7ddcb92bc0196416ff04199326aea57996eef8c5b1548bd8569012210da317f7c0074691d01b7", "0xa1a13549c82c877253ddefa36a29ea6a23695ee401fdd48e65f6f61e5ebd956d5e0edeff99484e9075cb35071fec41e2", "0x838ba0c1e5bd1a6da05611ff1822b8622457ebd019cb065ece36a2d176bd2d889511328120b8a357e44569e7f640c1e6", "0xb916eccff2a95519400bbf76b5f576cbe53cf200410370a19d77734dc04c05b585cfe382e8864e67142d548cd3c4c2f4", "0xa610447cb7ca6eea53a6ff1f5fe562377dcb7f4aaa7300f755a4f5e8eba61e863c51dc2aa9a29b35525b550fbc32a0fe", "0x9620e8f0f0ee9a4719aa9685eeb1049c5c77659ba6149ec4c158f999cfd09514794b23388879931fe26fea03fa471fd3", "0xa9dcf8b679e276583cf5b9360702a185470d09aea463dc474ee9c8aee91ef089dacb073e334e47fbc78ec5417c90465c", "0x8c9adee8410bdd99e5b285744cee61e2593b6300ff31a8a83b0ec28da59475a5c6fb9346fe43aadea2e6c3dad2a8e30a", "0x97d5afe9b3897d7b8bb628b7220cf02d8ee4e9d0b78f5000d500aaf4c1df9251aaaabfd1601626519f9d66f00a821d4e", "0x8a382418157b601ce4c3501d3b8409ca98136a4ef6abcbf62885e16e215b76b035c94d149cc41ff92e42ccd7c43b9b3d", "0xb64b8d11fb3b01abb2646ac99fdb9c02b804ce15d98f9fe0fbf1c9df8440c71417487feb6cdf51e3e81d37104b19e012", "0x849d7d044f9d8f0aab346a9374f0b3a5d14a9d1faa83dbacccbdc629ad1ef903a990940255564770537f8567521d17f0", "0x829dbb0c76b996c2a91b4cbbe93ba455ca0d5729755e5f0c92aaee37dff7f36fcdc06f33aca41f1b609c784127b67d88", "0x85a7c0069047b978422d264d831ab816435f63938015d2e977222b6b5746066c0071b7f89267027f8a975206ed25c1b0", "0x84b9fbc1cfb302df1acdcf3dc5d66fd1edfe7839f7a3b2fb3a0d5548656249dd556104d7c32b73967bccf0f5bdcf9e3b", "0x972220ac5b807f53eac37dccfc2ad355d8b21ea6a9c9b011c09fe440ddcdf7513e0b43d7692c09ded80d7040e26aa28f", "0x855885ed0b21350baeca890811f344c553cf9c21024649c722453138ba29193c6b02c4b4994cd414035486f923472e28", "0x841874783ae6d9d0e59daea03e96a01cbbe4ecaced91ae4f2c8386e0d87b3128e6d893c98d17c59e4de1098e1ad519dd", "0x827e50fc9ce56f97a4c3f2f4cbaf0b22f1c3ce6f844ff0ef93a9c57a09b8bf91ebfbd2ba9c7f83c442920bffdaf288cc", "0xa441f9136c7aa4c08d5b3534921b730e41ee91ab506313e1ba5f7c6f19fd2d2e1594e88c219834e92e6fb95356385aa7", "0x97d75b144471bf580099dd6842b823ec0e6c1fb86dd0da0db195e65524129ea8b6fd4a7a9bbf37146269e938a6956596", "0xa4b6fa87f09d5a29252efb2b3aaab6b3b6ea9fab343132a651630206254a25378e3e9d6c96c3d14c150d01817d375a8e", "0xa31a671876d5d1e95fe2b8858dc69967231190880529d57d3cab7f9f4a2b9b458ac9ee5bdaa3289158141bf18f559efb", "0x90bee6fff4338ba825974021b3b2a84e36d617e53857321f13d2b3d4a28954e6de3b3c0e629d61823d18a9763313b3bf", "0x96b622a63153f393bb419bfcf88272ea8b3560dbd46b0aa07ada3a6223990d0abdd6c2adb356ef4be5641688c8d83941", "0x84c202adeaff9293698022bc0381adba2cd959f9a35a4e8472288fd68f96f6de8be9da314c526d88e291c96b1f3d6db9", "0x8ca01a143b8d13809e5a8024d03e6bc9492e22226073ef6e327edf1328ef4aff82d0bcccee92cb8e212831fa35fe1204", "0xb2f970dbad15bfbefb38903c9bcc043d1367055c55dc1100a850f5eb816a4252c8c194b3132c929105511e14ea10a67d", "0xa5e36556472a95ad57eb90c3b6623671b03eafd842238f01a081997ffc6e2401f76e781d049bb4aa94d899313577a9cf", "0x8d1057071051772f7c8bedce53a862af6fd530dd56ae6321eaf2b9fc6a68beff5ed745e1c429ad09d5a118650bfd420a", "0x8aadc4f70ace4fcb8d93a78610779748dcffc36182d45b932c226dc90e48238ea5daa91f137c65ed532352c4c4d57416", "0xa2ea05ae37e673b4343232ae685ee14e6b88b867aef6dfac35db3589cbcd76f99540fed5c2641d5bb5a4a9f808e9bf0d", "0x947f1abad982d65648ae4978e094332b4ecb90f482c9be5741d5d1cf5a28acf4680f1977bf6e49dd2174c37f11e01296", "0xa27b144f1565e4047ba0e3f4840ef19b5095d1e281eaa463c5358f932114cbd018aa6dcf97546465cf2946d014d8e6d6", "0x8574e1fc3acade47cd4539df578ce9205e745e161b91e59e4d088711a7ab5aa3b410d517d7304b92109924d9e2af8895", "0xa48ee6b86b88015d6f0d282c1ae01d2a5b9e8c7aa3d0c18b35943dceb1af580d08a65f54dc6903cde82fd0d73ce94722", "0x8875650cec543a7bf02ea4f2848a61d167a66c91ffaefe31a9e38dc8511c6a25bde431007eefe27a62af3655aca208dc", "0x999b0a6e040372e61937bf0d68374e230346b654b5a0f591a59d33a4f95bdb2f3581db7c7ccb420cd7699ed709c50713", "0x878c9e56c7100c5e47bbe77dc8da5c5fe706cec94d37fa729633bca63cace7c40102eee780fcdabb655f5fa47a99600e", "0x865006fb5b475ada5e935f27b96f9425fc2d5449a3c106aa366e55ebed3b4ee42adc3c3f0ac19fd129b40bc7d6bc4f63", "0xb7a7da847f1202e7bc1672553e68904715e84fd897d529243e3ecda59faa4e17ba99c649a802d53f6b8dfdd51f01fb74", "0x8b2fb4432c05653303d8c8436473682933a5cb604da10c118ecfcd2c8a0e3132e125afef562bdbcc3df936164e5ce4f2", "0x808d95762d33ddfa5d0ee3d7d9f327de21a994d681a5f372e2e3632963ea974da7f1f9e5bac8ccce24293509d1f54d27", "0x932946532e3c397990a1df0e94c90e1e45133e347a39b6714c695be21aeb2d309504cb6b1dde7228ff6f6353f73e1ca2", "0x9705e7c93f0cdfaa3fa96821f830fe53402ad0806036cd1b48adc2f022d8e781c1fbdab60215ce85c653203d98426da3", "0xaa180819531c3ec1feb829d789cb2092964c069974ae4faad60e04a6afcce5c3a59aec9f11291e6d110a788d22532bc6", "0x88f755097f7e25cb7dd3c449520c89b83ae9e119778efabb54fbd5c5714b6f37c5f9e0346c58c6ab09c1aef2483f895d", "0x99fc03ab7810e94104c494f7e40b900f475fde65bdec853e60807ffd3f531d74de43335c3b2646b5b8c26804a7448898", "0xaf2dea9683086bed1a179110efb227c9c00e76cd00a2015b089ccbcee46d1134aa18bda5d6cab6f82ae4c5cd2461ac21", "0xa500f87ba9744787fdbb8e750702a3fd229de6b8817594348dec9a723b3c4240ddfa066262d002844b9e38240ce55658", "0x924d0e45c780f5bc1c1f35d15dfc3da28036bdb59e4c5440606750ecc991b85be18bc9a240b6c983bc5430baa4c68287", "0x865b11e0157b8bf4c5f336024b016a0162fc093069d44ac494723f56648bc4ded13dfb3896e924959ea11c96321afefc", "0x93672d8607d4143a8f7894f1dcca83fb84906dc8d6dd7dd063bb0049cfc20c1efd933e06ca7bd03ea4cb5a5037990bfe", "0x826891efbdff0360446825a61cd1fa04326dd90dae8c33dfb1ed97b045e165766dd070bd7105560994d0b2044bdea418", "0x93c4a4a8bcbc8b190485cc3bc04175b7c0ed002c28c98a540919effd6ed908e540e6594f6db95cd65823017258fb3b1c", "0xaeb2a0af2d2239fda9aa6b8234b019708e8f792834ff0dd9c487fa09d29800ddceddd6d7929faa9a3edcb9e1b3aa0d6b", "0x87f11de7236d387863ec660d2b04db9ac08143a9a2c4dfff87727c95b4b1477e3bc473a91e5797313c58754905079643", "0x80dc1db20067a844fe8baceca77f80db171a5ca967acb24e2d480eae9ceb91a3343c31ad1c95b721f390829084f0eae6", "0x9825c31f1c18da0de3fa84399c8b40f8002c3cae211fb6a0623c76b097b4d39f5c50058f57a16362f7a575909d0a44a2", "0xa99fc8de0c38dbf7b9e946de83943a6b46a762167bafe2a603fb9b86f094da30d6de7ed55d639aafc91936923ee414b3", "0xad594678b407db5d6ea2e90528121f84f2b96a4113a252a30d359a721429857c204c1c1c4ff71d8bb5768c833f82e80e", "0xb33d985e847b54510b9b007e31053732c8a495e43be158bd2ffcea25c6765bcbc7ca815f7c60b36ad088b955dd6e9350", "0x815f8dfc6f90b3342ca3fbd968c67f324dae8f74245cbf8bc3bef10e9440c65d3a2151f951e8d18959ba01c1b50b0ec1", "0x94c608a362dd732a1abc56e338637c900d59013db8668e49398b3c7a0cae3f7e2f1d1bf94c0299eeafe6af7f76c88618", "0x8ebd8446b23e5adfcc393adc5c52fe172f030a73e63cd2d515245ca0dd02782ceed5bcdd9ccd9c1b4c5953dfac9c340c", "0x820437f3f6f9ad0f5d7502815b221b83755eb8dc56cd92c29e9535eb0b48fb8d08c9e4fcc26945f9c8cca60d89c44710", "0x8910e4e8a56bf4be9cc3bbf0bf6b1182a2f48837a2ed3c2aaec7099bfd7f0c83e14e608876b17893a98021ff4ab2f20d", "0x9633918fde348573eec15ce0ad53ac7e1823aac86429710a376ad661002ae6d049ded879383faaa139435122f64047c6", "0xa1f5e3fa558a9e89318ca87978492f0fb4f6e54a9735c1b8d2ecfb1d1c57194ded6e0dd82d077b2d54251f3bee1279e1", "0xb208e22d04896abfd515a95c429ff318e87ff81a5d534c8ac2c33c052d6ffb73ef1dccd39c0bbe0734b596c384014766", "0x986d5d7d2b5bde6d16336f378bd13d0e671ad23a8ec8a10b3fc09036faeeb069f60662138d7a6df3dfb8e0d36180f770", "0xa2d4e6c5f5569e9cef1cddb569515d4b6ace38c8aed594f06da7434ba6b24477392cc67ba867c2b079545ca0c625c457", "0xb5ac32b1d231957d91c8b7fc43115ce3c5c0d8c13ca633374402fa8000b6d9fb19499f9181844f0c10b47357f3f757ce", "0x96b8bf2504b4d28fa34a4ec378e0e0b684890c5f44b7a6bb6e19d7b3db2ab27b1e2686389d1de9fbd981962833a313ea", "0x953bfd7f6c3a0469ad432072b9679a25486f5f4828092401eff494cfb46656c958641a4e6d0d97d400bc59d92dba0030", "0x876ab3cea7484bbfd0db621ec085b9ac885d94ab55c4bb671168d82b92e609754b86aaf472c55df3d81421d768fd108a", "0x885ff4e67d9ece646d02dd425aa5a087e485c3f280c3471b77532b0db6145b69b0fbefb18aa2e3fa5b64928b43a94e57", "0xb91931d93f806d0b0e6cc62a53c718c099526140f50f45d94b8bbb57d71e78647e06ee7b42aa5714aed9a5c05ac8533f", "0xa0313eeadd39c720c9c27b3d671215331ab8d0a794e71e7e690f06bcd87722b531d6525060c358f35f5705dbb7109ccb", "0x874c0944b7fedc6701e53344100612ddcb495351e29305c00ec40a7276ea5455465ffb7bded898886c1853139dfb1fc7", "0x8dc31701a01ee8137059ca1874a015130d3024823c0576aa9243e6942ec99d377e7715ed1444cd9b750a64b85dcaa3e5", "0x836d2a757405e922ec9a2dfdcf489a58bd48b5f9683dd46bf6047688f778c8dee9bc456de806f70464df0b25f3f3d238", "0xb30b0a1e454a503ea3e2efdec7483eaf20b0a5c3cefc42069e891952b35d4b2c955cf615f3066285ed8fafd9fcfbb8f6", "0x8e6d4044b55ab747e83ec8762ea86845f1785cc7be0279c075dadf08aca3ccc5a096c015bb3c3f738f647a4eadea3ba5", "0xad7735d16ab03cbe09c029610aa625133a6daecfc990b297205b6da98eda8c136a7c50db90f426d35069708510d5ae9c", "0x8d62d858bbb59ec3c8cc9acda002e08addab4d3ad143b3812098f3d9087a1b4a1bb255dcb1635da2402487d8d0249161", "0x805beec33238b832e8530645a3254aeef957e8f7ea24bcfc1054f8b9c69421145ebb8f9d893237e8a001c857fedfc77e", "0xb1005644be4b085e3f5775aa9bd3e09a283e87ddada3082c04e7a62d303dcef3b8cf8f92944c200c7ae6bb6bdf63f832", "0xb4ba0e0790dc29063e577474ffe3b61f5ea2508169f5adc1e394934ebb473e356239413a17962bc3e5d3762d72cce8c2", "0xa157ba9169c9e3e6748d9f1dd67fbe08b9114ade4c5d8fc475f87a764fb7e6f1d21f66d7905cd730f28a1c2d8378682a", "0x913e52b5c93989b5d15e0d91aa0f19f78d592bc28bcfdfddc885a9980c732b1f4debb8166a7c4083c42aeda93a702898", "0x90fbfc1567e7cd4e096a38433704d3f96a2de2f6ed3371515ccc30bc4dd0721a704487d25a97f3c3d7e4344472702d8d", "0x89646043028ffee4b69d346907586fd12c2c0730f024acb1481abea478e61031966e72072ff1d5e65cb8c64a69ad4eb1", "0xb125a45e86117ee11d2fb42f680ab4a7894edd67ff927ae2c808920c66c3e55f6a9d4588eee906f33a05d592e5ec3c04", "0xaad47f5b41eae9be55fb4f67674ff1e4ae2482897676f964a4d2dcb6982252ee4ff56aac49578b23f72d1fced707525e", "0xb9ddff8986145e33851b4de54d3e81faa3352e8385895f357734085a1616ef61c692d925fe62a5ed3be8ca49f5d66306", "0xb3cb0963387ed28c0c0adf7fe645f02606e6e1780a24d6cecef5b7c642499109974c81a7c2a198b19862eedcea2c2d8c", "0xac9c53c885457aaf5cb36c717a6f4077af701e0098eebd7aa600f5e4b14e6c1067255b3a0bc40e4a552025231be7de60", "0x8e1a8d823c4603f6648ec21d064101094f2a762a4ed37dd2f0a2d9aa97b2d850ce1e76f4a4b8cae58819b058180f7031", "0xb268b73bf7a179b6d22bd37e5e8cb514e9f5f8968c78e14e4f6d5700ca0d0ca5081d0344bb73b028970eebde3cb4124e", "0xa7f57d71940f0edbd29ed8473d0149cae71d921dd15d1ff589774003e816b54b24de2620871108cec1ab9fa956ad6ce6", "0x8053e6416c8b120e2b999cc2fc420a6a55094c61ac7f2a6c6f0a2c108a320890e389af96cbe378936132363c0d551277", "0xb3823f4511125e5aa0f4269e991b435a0d6ceb523ebd91c04d7add5534e3df5fc951c504b4fd412a309fd3726b7f940b", "0xae6eb04674d04e982ca9a6add30370ab90e303c71486f43ed3efbe431af1b0e43e9d06c11c3412651f304c473e7dbf39", "0x96ab55e641ed2e677591f7379a3cd126449614181fce403e93e89b1645d82c4af524381ff986cae7f9cebe676878646d", "0xb52423b4a8c37d3c3e2eca8f0ddbf7abe0938855f33a0af50f117fab26415fb0a3da5405908ec5fdc22a2c1f2ca64892", "0x82a69ce1ee92a09cc709d0e3cd22116c9f69d28ea507fe5901f5676000b5179b9abe4c1875d052b0dd42d39925e186bb", "0xa84c8cb84b9d5cfb69a5414f0a5283a5f2e90739e9362a1e8c784b96381b59ac6c18723a4aa45988ee8ef5c1f45cc97d", "0xafd7efce6b36813082eb98257aae22a4c1ae97d51cac7ea9c852d4a66d05ef2732116137d8432e3f117119725a817d24", "0xa0f5fe25af3ce021b706fcff05f3d825384a272284d04735574ce5fb256bf27100fad0b1f1ba0e54ae9dcbb9570ecad3", "0x8751786cb80e2e1ff819fc7fa31c2833d25086534eb12b373d31f826382430acfd87023d2a688c65b5e983927e146336", "0x8cf5c4b17fa4f3d35c78ce41e1dc86988fd1135cd5e6b2bb0c108ee13538d0d09ae7102609c6070f39f937b439b31e33", "0xa9108967a2fedd7c322711eca8159c533dd561bedcb181b646de98bf5c3079449478eab579731bee8d215ae8852c7e21", "0xb54c5171704f42a6f0f4e70767cdb3d96ffc4888c842eece343a01557da405961d53ffdc34d2f902ea25d3e1ed867cad", "0xae8d4b764a7a25330ba205bf77e9f46182cd60f94a336bbd96773cf8064e3d39caf04c310680943dc89ed1fbad2c6e0d", "0xaa5150e911a8e1346868e1b71c5a01e2a4bb8632c195861fb6c3038a0e9b85f0e09b3822e9283654a4d7bb17db2fc5f4", "0x9685d3756ce9069bf8bb716cf7d5063ebfafe37e15b137fc8c3159633c4e006ff4887ddd0ae90360767a25c3f90cba7f", "0x82155fd70f107ab3c8e414eadf226c797e07b65911508c76c554445422325e71af8c9a8e77fd52d94412a6fc29417cd3", "0xabfae52f53a4b6e00760468d973a267f29321997c3dbb5aee36dc1f20619551229c0c45b9d9749f410e7f531b73378e8", "0x81a76d921f8ef88e774fd985e786a4a330d779b93fad7def718c014685ca0247379e2e2a007ad63ee7f729cd9ed6ce1b", "0x81947c84bc5e28e26e2e533af5ae8fe10407a7b77436dbf8f1d5b0bbe86fc659eae10f974659dc7c826c6dabd03e3a4b", "0x92b8c07050d635b8dd4fd09df9054efe4edae6b86a63c292e73cc819a12a21dd7d104ce51fa56af6539dedf6dbe6f7b6", "0xb44c579e3881f32b32d20c82c207307eca08e44995dd2aac3b2692d2c8eb2a325626c80ac81c26eeb38c4137ff95add5", "0x97efab8941c90c30860926dea69a841f2dcd02980bf5413b9fd78d85904588bf0c1021798dbc16c8bbb32cce66c82621", "0x913363012528b50698e904de0588bf55c8ec5cf6f0367cfd42095c4468fcc64954fbf784508073e542fee242d0743867", "0x8ed203cf215148296454012bd10fddaf119203db1919a7b3d2cdc9f80e66729464fdfae42f1f2fc5af1ed53a42b40024", "0xab84312db7b87d711e9a60824f4fe50e7a6190bf92e1628688dfcb38930fe87b2d53f9e14dd4de509b2216856d8d9188", "0x880726def069c160278b12d2258eac8fa63f729cd351a710d28b7e601c6712903c3ac1e7bbd0d21e4a15f13ca49db5aa", "0x980699cd51bac6283959765f5174e543ed1e5f5584b5127980cbc2ef18d984ecabba45042c6773b447b8e694db066028", "0xaeb019cb80dc4cb4207430d0f2cd24c9888998b6f21d9bf286cc638449668d2eec0018a4cf3fe6448673cd6729335e2b", "0xb29852f6aa6c60effdffe96ae88590c88abae732561d35cc19e82d3a51e26cb35ea00986193e07f90060756240f5346e", "0xa0fa855adc5ba469f35800c48414b8921455950a5c0a49945d1ef6e8f2a1881f2e2dfae47de6417270a6bf49deeb091d", "0xb6c7332e3b14813641e7272d4f69ecc7e09081df0037d6dab97ce13a9e58510f5c930d300633f208181d9205c5534001", "0x85a6c050f42fce560b5a8d54a11c3bbb8407abbadd859647a7b0c21c4b579ec65671098b74f10a16245dc779dff7838e", "0x8f3eb34bb68759d53c6677de4de78a6c24dd32c8962a7fb355ed362572ef8253733e6b52bc21c9f92ecd875020a9b8de", "0xa17dd44181e5dab4dbc128e1af93ec22624b57a448ca65d2d9e246797e4af7d079e09c6e0dfb62db3a9957ce92f098d5", "0xa56a1b854c3183082543a8685bb34cae1289f86cfa8123a579049dbd059e77982886bfeb61bf6e05b4b1fe4e620932e7", "0xaedae3033cb2fb7628cb4803435bdd7757370a86f808ae4cecb9a268ad0e875f308c048c80cbcac523de16b609683887", "0x9344905376aa3982b1179497fac5a1d74b14b7038fd15e3b002db4c11c8bfc7c39430db492cdaf58b9c47996c9901f28", "0xa3bfafdae011a19f030c749c3b071f83580dee97dd6f949e790366f95618ca9f828f1daaeabad6dcd664fcef81b6556d", "0x81c03d8429129e7e04434dee2c529194ddb01b414feda3adee2271eb680f6c85ec872a55c9fa9d2096f517e13ed5abcc", "0x98205ef3a72dff54c5a9c82d293c3e45d908946fa74bb749c3aabe1ab994ea93c269bcce1a266d2fe67a8f02133c5985", "0x85a70aeed09fda24412fadbafbbbf5ba1e00ac92885df329e147bfafa97b57629a3582115b780d8549d07d19b7867715", "0xb0fbe81c719f89a57d9ea3397705f898175808c5f75f8eb81c2193a0b555869ba7bd2e6bc54ee8a60cea11735e21c68c", "0xb03a0bd160495ee626ff3a5c7d95bc79d7da7e5a96f6d10116600c8fa20bedd1132f5170f25a22371a34a2d763f2d6d0", "0xa90ab04091fbca9f433b885e6c1d60ab45f6f1daf4b35ec22b09909d493a6aab65ce41a6f30c98239cbca27022f61a8b", "0xb66f92aa3bf2549f9b60b86f99a0bd19cbdd97036d4ae71ca4b83d669607f275260a497208f6476cde1931d9712c2402", "0xb08e1fdf20e6a9b0b4942f14fa339551c3175c1ffc5d0ab5b226b6e6a322e9eb0ba96adc5c8d59ca4259e2bdd04a7eb0", "0xa2812231e92c1ce74d4f5ac3ab6698520288db6a38398bb38a914ac9326519580af17ae3e27cde26607e698294022c81", "0xabfcbbcf1d3b9e84c02499003e490a1d5d9a2841a9e50c7babbef0b2dd20d7483371d4dc629ba07faf46db659459d296", "0xb0fe9f98c3da70927c23f2975a9dc4789194d81932d2ad0f3b00843dd9cbd7fb60747a1da8fe5a79f136a601becf279d", "0xb130a6dba7645165348cb90f023713bed0eefbd90a976b313521c60a36d34f02032e69a2bdcf5361e343ed46911297ec", "0x862f0cffe3020cea7a5fd4703353aa1eb1be335e3b712b29d079ff9f7090d1d8b12013011e1bdcbaa80c44641fd37c9f", "0x8c6f11123b26633e1abb9ed857e0bce845b2b3df91cc7b013b2fc77b477eee445da0285fc6fc793e29d5912977f40916", "0x91381846126ea819d40f84d3005e9fb233dc80071d1f9bb07f102bf015f813f61e5884ffffb4f5cd333c1b1e38a05a58", "0x8add7d908de6e1775adbd39c29a391f06692b936518db1f8fde74eb4f533fc510673a59afb86e3a9b52ade96e3004c57", "0x8780e086a244a092206edcde625cafb87c9ab1f89cc3e0d378bc9ee776313836160960a82ec397bc3800c0a0ec3da283", "0xa6cb4cd9481e22870fdd757fae0785edf4635e7aacb18072fe8dc5876d0bab53fb99ce40964a7d3e8bcfff6f0ab1332f", "0xaf30ff47ecc5b543efba1ba4706921066ca8bb625f40e530fb668aea0551c7647a9d126e8aba282fbcce168c3e7e0130", "0x91b0bcf408ce3c11555dcb80c4410b5bc2386d3c05caec0b653352377efdcb6bab4827f2018671fc8e4a0e90d772acc1", "0xa9430b975ef138b6b2944c7baded8fe102d31da4cfe3bd3d8778bda79189c99d38176a19c848a19e2d1ee0bddd9a13c1", "0xaa5a4eef849d7c9d2f4b018bd01271c1dd83f771de860c4261f385d3bdcc130218495860a1de298f14b703ec32fa235f", "0xb0ce79e7f9ae57abe4ff366146c3b9bfb38b0dee09c28c28f5981a5d234c6810ad4d582751948affb480d6ae1c8c31c4", "0xb75122748560f73d15c01a8907d36d06dc068e82ce22b84b322ac1f727034493572f7907dec34ebc3ddcc976f2f89ed7", "0xb0fc7836369a3e4411d34792d6bd5617c14f61d9bba023dda64e89dc5fb0f423244e9b48ee64869258931daa9753a56f", "0x8956d7455ae9009d70c6e4a0bcd7610e55f37494cf9897a8f9e1b904cc8febc3fd2d642ebd09025cfff4609ad7e3bc52", "0xad741efe9e472026aa49ae3d9914cb9c1a6f37a54f1a6fe6419bebd8c7d68dca105a751c7859f4389505ede40a0de786", "0xb52f418797d719f0d0d0ffb0846788b5cba5d0454a69a2925de4b0b80fa4dd7e8c445e5eac40afd92897ed28ca650566", "0xa0ab65fb9d42dd966cd93b1de01d7c822694669dd2b7a0c04d99cd0f3c3de795f387b9c92da11353412f33af5c950e9a", "0xa0052f44a31e5741a331f7cac515a08b3325666d388880162d9a7b97598fde8b61f9ff35ff220df224eb5c4e40ef0567", "0xa0101cfdc94e42b2b976c0d89612a720e55d145a5ef6ef6f1f78cf6de084a49973d9b5d45915349c34ce712512191e3c", "0xa0dd99fcf3f5cead5aaf08e82212df3a8bb543c407a4d6fab88dc5130c1769df3f147e934a46f291d6c1a55d92b86917", "0xa5939153f0d1931bbda5cf6bdf20562519ea55fbfa978d6dbc6828d298260c0da7a50c37c34f386e59431301a96c2232", "0x9568269f3f5257200f9ca44afe1174a5d3cf92950a7f553e50e279c239e156a9faaa2a67f288e3d5100b4142efe64856", "0xb746b0832866c23288e07f24991bbf687cad794e7b794d3d3b79367566ca617d38af586cdc8d6f4a85a34835be41d54f", "0xa871ce28e39ab467706e32fec1669fda5a4abba2f8c209c6745df9f7a0fa36bbf1919cf14cb89ea26fa214c4c907ae03", "0xa08dacdd758e523cb8484f6bd070642c0c20e184abdf8e2a601f61507e93952d5b8b0c723c34fcbdd70a8485eec29db2", "0x85bdb78d501382bb95f1166b8d032941005661aefd17a5ac32df9a3a18e9df2fc5dc2c1f07075f9641af10353cecc0c9", "0x98d730c28f6fa692a389e97e368b58f4d95382fad8f0baa58e71a3d7baaea1988ead47b13742ce587456f083636fa98e", "0xa557198c6f3d5382be9fb363feb02e2e243b0c3c61337b3f1801c4a0943f18e38ce1a1c36b5c289c8fa2aa9d58742bab", "0x89174f79201742220ac689c403fc7b243eed4f8e3f2f8aba0bf183e6f5d4907cb55ade3e238e3623d9885f03155c4d2b", "0xb891d600132a86709e06f3381158db300975f73ea4c1f7c100358e14e98c5fbe792a9af666b85c4e402707c3f2db321e", "0xb9e5b2529ef1043278c939373fc0dbafe446def52ddd0a8edecd3e4b736de87e63e187df853c54c28d865de18a358bb6", "0x8589b2e9770340c64679062c5badb7bbef68f55476289b19511a158a9a721f197da03ece3309e059fc4468b15ac33aa3", "0xaad8c6cd01d785a881b446f06f1e9cd71bca74ba98674c2dcddc8af01c40aa7a6d469037498b5602e76e9c91a58d3dbd", "0xabaccb1bd918a8465f1bf8dbe2c9ad4775c620b055550b949a399f30cf0d9eb909f3851f5b55e38f9e461e762f88f499", "0xae62339d26db46e85f157c0151bd29916d5cc619bd4b832814b3fd2f00af8f38e7f0f09932ffe5bba692005dab2d9a74", "0x93a6ff30a5c0edf8058c89aba8c3259e0f1b1be1b80e67682de651e5346f7e1b4b4ac3d87cbaebf198cf779524aff6bf", "0x8980a2b1d8f574af45b459193c952400b10a86122b71fca2acb75ee0dbd492e7e1ef5b959baf609a5172115e371f3177", "0x8c2f49f3666faee6940c75e8c7f6f8edc3f704cca7a858bbb7ee5e96bba3b0cf0993996f781ba6be3b0821ef4cb75039", "0xb14b9e348215b278696018330f63c38db100b0542cfc5be11dc33046e3bca6a13034c4ae40d9cef9ea8b34fef0910c4e", "0xb59bc3d0a30d66c16e6a411cb641f348cb1135186d5f69fda8b0a0934a5a2e7f6199095ba319ec87d3fe8f1ec4a06368", "0x8874aca2a3767aa198e4c3fec2d9c62d496bc41ff71ce242e9e082b7f38cdf356089295f80a301a3cf1182bde5308c97", "0xb1820ebd61376d91232423fc20bf008b2ba37e761199f4ef0648ea2bd70282766799b4de814846d2f4d516d525c8daa7", "0xa6b202e5dedc16a4073e04a11af3a8509b23dfe5a1952f899adeb240e75c3f5bde0c424f811a81ea48d343591faffe46", "0xa69becee9c93734805523b92150a59a62eed4934f66056b645728740d42223f2925a1ad38359ba644da24d9414f4cdda", "0xad72f0f1305e37c7e6b48c272323ee883320994cb2e0d850905d6655fafc9f361389bcb9c66b3ff8d2051dbb58c8aa96", "0xb563600bd56fad7c8853af21c6a02a16ed9d8a8bbeea2c31731d63b976d83cb05b9779372d898233e8fd597a75424797", "0xb0abb78ce465bf7051f563c62e8be9c57a2cc997f47c82819300f36e301fefd908894bb2053a9d27ce2d0f8c46d88b5b", "0xa071a85fb8274bac2202e0cb8e0e2028a5e138a82d6e0374d39ca1884a549c7c401312f00071b91f455c3a2afcfe0cda", "0xb931c271513a0f267b9f41444a5650b1918100b8f1a64959c552aff4e2193cc1b9927906c6fa7b8a8c68ef13d79aaa52", "0xa6a1bb9c7d32cb0ca44d8b75af7e40479fbce67d216b48a2bb680d3f3a772003a49d3cd675fc64e9e0f8fabeb86d6d61", "0xb98d609858671543e1c3b8564162ad828808bb50ded261a9f8690ded5b665ed8368c58f947365ed6e84e5a12e27b423d", "0xb3dca58cd69ec855e2701a1d66cad86717ff103ef862c490399c771ad28f675680f9500cb97be48de34bcdc1e4503ffd", "0xb34867c6735d3c49865e246ddf6c3b33baf8e6f164db3406a64ebce4768cb46b0309635e11be985fee09ab7a31d81402", "0xacb966c554188c5b266624208f31fab250b3aa197adbdd14aee5ab27d7fb886eb4350985c553b20fdf66d5d332bfd3fe", "0x943c36a18223d6c870d54c3b051ef08d802b85e9dd6de37a51c932f90191890656c06adfa883c87b906557ae32d09da0", "0x81bca7954d0b9b6c3d4528aadf83e4bc2ef9ea143d6209bc45ae9e7ae9787dbcd8333c41f12c0b6deee8dcb6805e826a", "0xaba176b92256efb68f574e543479e5cf0376889fb48e3db4ebfb7cba91e4d9bcf19dcfec444c6622d9398f06de29e2b9", "0xb9f743691448053216f6ece7cd699871fff4217a1409ceb8ab7bdf3312d11696d62c74b0664ba0a631b1e0237a8a0361", "0xa383c2b6276fa9af346b21609326b53fb14fdf6f61676683076e80f375b603645f2051985706d0401e6fbed7eb0666b6", "0xa9ef2f63ec6d9beb8f3d04e36807d84bda87bdd6b351a3e4a9bf7edcb5618c46c1f58cfbf89e64b40f550915c6988447", "0xa141b2d7a82f5005eaea7ae7d112c6788b9b95121e5b70b7168d971812f3381de8b0082ac1f0a82c7d365922ebd2d26a", "0xb1b76ef8120e66e1535c17038b75255a07849935d3128e3e99e56567b842fb1e8d56ef932d508d2fb18b82f7868fe1a9", "0x8e2e234684c81f21099f5c54f6bbe2dd01e3b172623836c77668a0c49ce1fe218786c3827e4d9ae2ea25c50a8924fb3c", "0xa5caf5ff948bfd3c4ca3ffbdfcd91eec83214a6c6017235f309a0bbf7061d3b0b466307c00b44a1009cf575163898b43", "0x986415a82ca16ebb107b4c50b0c023c28714281db0bcdab589f6cb13d80e473a3034b7081b3c358e725833f6d845cb14", "0xb94836bf406ac2cbacb10e6df5bcdfcc9d9124ae1062767ca4e322d287fd5e353fdcebd0e52407cb3cd68571258a8900", "0x83c6d70a640b33087454a4788dfd9ef3ed00272da084a8d36be817296f71c086b23b576f98178ab8ca6a74f04524b46b", "0xad4115182ad784cfe11bcfc5ce21fd56229cc2ce77ac82746e91a2f0aa53ca6593a22efd2dc4ed8d00f84542643d9c58", "0xab1434c5e5065da826d10c2a2dba0facccab0e52b506ce0ce42fbe47ced5a741797151d9ecc99dc7d6373cfa1779bbf6", "0x8a8b591d82358d55e6938f67ea87a89097ab5f5496f7260adb9f649abb289da12b498c5b2539c2f9614fb4e21b1f66b0", "0x964f355d603264bc1f44c64d6d64debca66f37dff39c971d9fc924f2bc68e6c187b48564a6dc82660a98b035f8addb5d", "0xb66235eaaf47456bc1dc4bde454a028e2ce494ece6b713a94cd6bf27cf18c717fd0c57a5681caaa2ad73a473593cdd7a", "0x9103e3bb74304186fa4e3e355a02da77da4aca9b7e702982fc2082af67127ebb23a455098313c88465bc9b7d26820dd5", "0xb6a42ff407c9dd132670cdb83cbad4b20871716e44133b59a932cd1c3f97c7ac8ff7f61acfaf8628372508d8dc8cad7c", "0x883a9c21c16a167a4171b0f084565c13b6f28ba7c4977a0de69f0a25911f64099e7bbb4da8858f2e93068f4155d04e18", "0x8dbb3220abc6a43220adf0331e3903d3bfd1d5213aadfbd8dfcdf4b2864ce2e96a71f35ecfb7a07c3bbabf0372b50271", "0xb4ad08aee48e176bda390b7d9acf2f8d5eb008f30d20994707b757dc6a3974b2902d29cd9b4d85e032810ad25ac49e97", "0x865bb0f33f7636ec501bb634e5b65751c8a230ae1fa807a961a8289bbf9c7fe8c59e01fbc4c04f8d59b7f539cf79ddd5", "0x86a54d4c12ad1e3605b9f93d4a37082fd26e888d2329847d89afa7802e815f33f38185c5b7292293d788ad7d7da1df97", "0xb26c8615c5e47691c9ff3deca3021714662d236c4d8401c5d27b50152ce7e566266b9d512d14eb63e65bc1d38a16f914", "0x827639d5ce7db43ba40152c8a0eaad443af21dc92636cc8cc2b35f10647da7d475a1e408901cd220552fddad79db74df", "0xa2b79a582191a85dbe22dc384c9ca3de345e69f6aa370aa6d3ff1e1c3de513e30b72df9555b15a46586bd27ea2854d9d", "0xae0d74644aba9a49521d3e9553813bcb9e18f0b43515e4c74366e503c52f47236be92dfbd99c7285b3248c267b1de5a0", "0x80fb0c116e0fd6822a04b9c25f456bdca704e2be7bdc5d141dbf5d1c5eeb0a2c4f5d80db583b03ef3e47517e4f9a1b10", "0xac3a1fa3b4a2f30ea7e0a114cdc479eb51773573804c2a158d603ad9902ae8e39ffe95df09c0d871725a5d7f9ba71a57", "0xb56b2b0d601cba7f817fa76102c68c2e518c6f20ff693aad3ff2e07d6c4c76203753f7f91686b1801e8c4659e4d45c48", "0x89d50c1fc56e656fb9d3915964ebce703cb723fe411ab3c9eaa88ccc5d2b155a9b2e515363d9c600d3c0cee782c43f41", "0xb24207e61462f6230f3cd8ccf6828357d03e725769f7d1de35099ef9ee4dca57dbce699bb49ed994462bee17059d25ce", "0xb886f17fcbcbfcd08ac07f04bb9543ef58510189decaccea4b4158c9174a067cb67d14b6be3c934e6e2a18c77efa9c9c", "0xb9c050ad9cafd41c6e2e192b70d080076eed59ed38ea19a12bd92fa17b5d8947d58d5546aaf5e8e27e1d3b5481a6ce51", "0xaaf7a34d3267e3b1ddbc54c641e3922e89303f7c86ebebc7347ebca4cffad5b76117dac0cbae1a133053492799cd936f", "0xa9ee604ada50adef82e29e893070649d2d4b7136cc24fa20e281ce1a07bd736bf0de7c420369676bcbcecff26fb6e900", "0x9855315a12a4b4cf80ab90b8bd13003223ba25206e52fd4fe6a409232fbed938f30120a3db23eab9c53f308bd8b9db81", "0x8cd488dd7a24f548a3cf03c54dec7ff61d0685cb0f6e5c46c2d728e3500d8c7bd6bba0156f4bf600466fda53e5b20444", "0x890ad4942ebac8f5b16c777701ab80c68f56fa542002b0786f8fea0fb073154369920ac3dbfc07ea598b82f4985b8ced", "0x8de0cf9ddc84c9b92c59b9b044387597799246b30b9f4d7626fc12c51f6e423e08ee4cbfe9289984983c1f9521c3e19d", "0xb474dfb5b5f4231d7775b3c3a8744956b3f0c7a871d835d7e4fd9cc895222c7b868d6c6ce250de568a65851151fac860", "0x86433b6135d9ed9b5ee8cb7a6c40e5c9d30a68774cec04988117302b8a02a11a71a1e03fd8e0264ef6611d219f103007", "0x80b9ed4adbe9538fb1ef69dd44ec0ec5b57cbfea820054d8d445b4261962624b4c70ac330480594bc5168184378379c3", "0x8b2e83562ccd23b7ad2d17f55b1ab7ef5fbef64b3a284e6725b800f3222b8bdf49937f4a873917ada9c4ddfb090938c2", "0xabe78cebc0f5a45d754140d1f685e387489acbfa46d297a8592aaa0d676a470654f417a4f7d666fc0b2508fab37d908e", "0xa9c5f8ff1f8568e252b06d10e1558326db9901840e6b3c26bbd0cd5e850cb5fb3af3f117dbb0f282740276f6fd84126f", "0x975f8dc4fb55032a5df3b42b96c8c0ffecb75456f01d4aef66f973cb7270d4eff32c71520ceefc1adcf38d77b6b80c67", "0xb043306ed2c3d8a5b9a056565afd8b5e354c8c4569fda66b0d797a50a3ce2c08cffbae9bbe292da69f39e89d5dc7911e", "0x8d2afc36b1e44386ba350c14a6c1bb31ff6ea77128a0c5287584ac3584282d18516901ce402b4644a53db1ed8e7fa581", "0x8c294058bed53d7290325c363fe243f6ec4f4ea2343692f4bac8f0cb86f115c069ccb8334b53d2e42c067691ad110dba", "0xb92157b926751aaf7ef82c1aa8c654907dccab6376187ee8b3e8c0c82811eae01242832de953faa13ebaff7da8698b3e", "0xa780c4bdd9e4ba57254b09d745075cecab87feda78c88ffee489625c5a3cf96aa6b3c9503a374a37927d9b78de9bd22b", "0x811f548ef3a2e6a654f7dcb28ac9378de9515ed61e5a428515d9594a83e80b35c60f96a5cf743e6fab0d3cb526149f49", "0x85a4dccf6d90ee8e094731eec53bd00b3887aec6bd81a0740efddf812fd35e3e4fe4f983afb49a8588691c202dabf942", "0xb152c2da6f2e01c8913079ae2b40a09b1f361a80f5408a0237a8131b429677c3157295e11b365b1b1841924b9efb922e", "0x849b9efee8742502ffd981c4517c88ed33e4dd518a330802caff168abae3cd09956a5ee5eda15900243bc2e829016b74", "0x955a933f3c18ec0f1c0e38fa931e4427a5372c46a3906ebe95082bcf878c35246523c23f0266644ace1fa590ffa6d119", "0x911989e9f43e580c886656377c6f856cdd4ff1bd001b6db3bbd86e590a821d34a5c6688a29b8d90f28680e9fdf03ba69", "0xb73b8b4f1fd6049fb68d47cd96a18fcba3f716e0a1061aa5a2596302795354e0c39dea04d91d232aec86b0bf2ba10522", "0x90f87456d9156e6a1f029a833bf3c7dbed98ca2f2f147a8564922c25ae197a55f7ea9b2ee1f81bf7383197c4bad2e20c", "0x903cba8b1e088574cb04a05ca1899ab00d8960580c884bd3c8a4c98d680c2ad11410f2b75739d6050f91d7208cac33a5", "0x9329987d42529c261bd15ecedd360be0ea8966e7838f32896522c965adfc4febf187db392bd441fb43bbd10c38fdf68b", "0x8178ee93acf5353baa349285067b20e9bb41aa32d77b5aeb7384fe5220c1fe64a2461bd7a83142694fe673e8bbf61b7c", "0xa06a8e53abcff271b1394bcc647440f81fb1c1a5f29c27a226e08f961c3353f4891620f2d59b9d1902bf2f5cc07a4553", "0xaaf5fe493b337810889e777980e6bbea6cac39ac66bc0875c680c4208807ac866e9fda9b5952aa1d04539b9f4a4bec57", "0xaa058abb1953eceac14ccfa7c0cc482a146e1232905dcecc86dd27f75575285f06bbae16a8c9fe8e35d8713717f5f19f", "0x8f15dd732799c879ca46d2763453b359ff483ca33adb1d0e0a57262352e0476c235987dc3a8a243c74bc768f93d3014c", "0xa61cc8263e9bc03cce985f1663b8a72928a607121005a301b28a278e9654727fd1b22bc8a949af73929c56d9d3d4a273", "0x98d6dc78502d19eb9f921225475a6ebcc7b44f01a2df6f55ccf6908d65b27af1891be2a37735f0315b6e0f1576c1f8d8", "0x8bd258b883f3b3793ec5be9472ad1ff3dc4b51bc5a58e9f944acfb927349ead8231a523cc2175c1f98e7e1e2b9f363b8", "0xaeacc2ecb6e807ad09bedd99654b097a6f39840e932873ace02eabd64ccfbb475abdcb62939a698abf17572d2034c51e", "0xb8ccf78c08ccd8df59fd6eda2e01de328bc6d8a65824d6f1fc0537654e9bc6bf6f89c422dd3a295cce628749da85c864", "0x8f91fd8cb253ba2e71cc6f13da5e05f62c2c3b485c24f5d68397d04665673167fce1fc1aec6085c69e87e66ec555d3fd", "0xa254baa10cb26d04136886073bb4c159af8a8532e3fd36b1e9c3a2e41b5b2b6a86c4ebc14dbe624ee07b7ccdaf59f9ab", "0x94e3286fe5cd68c4c7b9a7d33ae3d714a7f265cf77cd0e9bc19fc51015b1d1c34ad7e3a5221c459e89f5a043ee84e3a9", "0xa279da8878af8d449a9539bec4b17cea94f0242911f66fab275b5143ab040825f78c89cb32a793930609415cfa3a1078", "0xac846ceb89c9e5d43a2991c8443079dc32298cd63e370e64149cec98cf48a6351c09c856f2632fd2f2b3d685a18bbf8b", "0xa847b27995c8a2e2454aaeb983879fb5d3a23105c33175839f7300b7e1e8ec3efd6450e9fa3f10323609dee7b98c6fd5", "0xa2f432d147d904d185ff4b2de8c6b82fbea278a2956bc406855b44c18041854c4f0ecccd472d1d0dff1d8aa8e281cb1d", "0x94a48ad40326f95bd63dff4755f863a1b79e1df771a1173b17937f9baba57b39e651e7695be9f66a472f098b339364fc", "0xa12a0ccd8f96e96e1bc6494341f7ebce959899341b3a084aa1aa87d1c0d489ac908552b7770b887bb47e7b8cbc3d8e66", "0x81a1f1681bda923bd274bfe0fbb9181d6d164fe738e54e25e8d4849193d311e2c4253614ed673c98af2c798f19a93468", "0xabf71106a05d501e84cc54610d349d7d5eae21a70bd0250f1bebbf412a130414d1c8dbe673ffdb80208fd72f1defa4d4", "0x96266dc2e0df18d8136d79f5b59e489978eee0e6b04926687fe389d4293c14f36f055c550657a8e27be4118b64254901", "0x8df5dcbefbfb4810ae3a413ca6b4bf08619ca53cd50eb1dde2a1c035efffc7b7ac7dff18d403253fd80104bd83dc029e", "0x9610b87ff02e391a43324a7122736876d5b3af2a137d749c52f75d07b17f19900b151b7f439d564f4529e77aa057ad12", "0xa90a5572198b40fe2fcf47c422274ff36c9624df7db7a89c0eb47eb48a73a03c985f4ac5016161c76ca317f64339bce1", "0x98e5e61a6ab6462ba692124dba7794b6c6bde4249ab4fcc98c9edd631592d5bc2fb5e38466691a0970a38e48d87c2e43", "0x918cefb8f292f78d4db81462c633daf73b395e772f47b3a7d2cea598025b1d8c3ec0cbff46cdb23597e74929981cde40", "0xa98918a5dc7cf610fe55f725e4fd24ce581d594cb957bb9b4e888672e9c0137003e1041f83e3f1d7b9caab06462c87d4", "0xb92b74ac015262ca66c33f2d950221e19d940ba3bf4cf17845f961dc1729ae227aa9e1f2017829f2135b489064565c29", "0xa053ee339f359665feb178b4e7ee30a85df37debd17cacc5a27d6b3369d170b0114e67ad1712ed26d828f1df641bcd99", "0x8c3c8bad510b35da5ce5bd84b35c958797fbea024ad1c97091d2ff71d9b962e9222f65a9b776e5b3cc29c36e1063d2ee", "0xaf99dc7330fe7c37e850283eb47cc3257888e7c197cb0d102edf94439e1e02267b6a56306d246c326c4c79f9dc8c6986", "0xafecb2dc34d57a725efbd7eb93d61eb29dbe8409b668ab9ea040791f5b796d9be6d4fc10d7f627bf693452f330cf0435", "0x93334fedf19a3727a81a6b6f2459db859186227b96fe7a391263f69f1a0884e4235de64d29edebc7b99c44d19e7c7d7a", "0x89579c51ac405ad7e9df13c904061670ce4b38372492764170e4d3d667ed52e5d15c7cd5c5991bbfa3a5e4e3fa16363e", "0x9778f3e8639030f7ef1c344014f124e375acb8045bd13d8e97a92c5265c52de9d1ffebaa5bc3e1ad2719da0083222991", "0x88f77f34ee92b3d36791bdf3326532524a67d544297dcf1a47ff00b47c1b8219ff11e34034eab7d23b507caa2fd3c6b9", "0xa699c1e654e7c484431d81d90657892efeb4adcf72c43618e71ca7bd7c7a7ebbb1db7e06e75b75dc4c74efd306b5df3f", "0x81d13153baebb2ef672b5bdb069d3cd669ce0be96b742c94e04038f689ff92a61376341366b286eee6bf3ae85156f694", "0x81efb17de94400fdacc1deec2550cbe3eecb27c7af99d8207e2f9be397e26be24a40446d2a09536bb5172c28959318d9", "0x989b21ebe9ceab02488992673dc071d4d5edec24bff0e17a4306c8cb4b3c83df53a2063d1827edd8ed16d6e837f0d222", "0x8d6005d6536825661b13c5fdce177cb37c04e8b109b7eb2b6d82ea1cb70efecf6a0022b64f84d753d165edc2bba784a3", "0xa32607360a71d5e34af2271211652d73d7756d393161f4cf0da000c2d66a84c6826e09e759bd787d4fd0305e2439d342", "0xaaad8d6f6e260db45d51b2da723be6fa832e76f5fbcb77a9a31e7f090dd38446d3b631b96230d78208cae408c288ac4e", "0xabcfe425255fd3c5cffd3a818af7650190c957b6b07b632443f9e33e970a8a4c3bf79ac9b71f4d45f238a04d1c049857", "0xaeabf026d4c783adc4414b5923dbd0be4b039cc7201219f7260d321f55e9a5b166d7b5875af6129c034d0108fdc5d666", "0xaf49e740c752d7b6f17048014851f437ffd17413c59797e5078eaaa36f73f0017c3e7da020310cfe7d3c85f94a99f203", "0x8854ca600d842566e3090040cd66bb0b3c46dae6962a13946f0024c4a8aca447e2ccf6f240045f1ceee799a88cb9210c", "0xb6c03b93b1ab1b88ded8edfa1b487a1ed8bdce8535244dddb558ffb78f89b1c74058f80f4db2320ad060d0c2a9c351cc", "0xb5bd7d17372faff4898a7517009b61a7c8f6f0e7ed4192c555db264618e3f6e57fb30a472d169fea01bf2bf0362a19a8", "0x96eb1d38319dc74afe7e7eb076fcd230d19983f645abd14a71e6103545c01301b31c47ae931e025f3ecc01fb3d2f31fa", "0xb55a8d30d4403067def9b65e16f867299f8f64c9b391d0846d4780bc196569622e7e5b64ce799b5aefac8f965b2a7a7b", "0x8356d199a991e5cbbff608752b6291731b6b6771aed292f8948b1f41c6543e4ab1bedc82dd26d10206c907c03508df06", "0x97f4137445c2d98b0d1d478049de952610ad698c91c9d0f0e7227d2aae690e9935e914ec4a2ea1fbf3fc1dddfeeacebb", "0xaf5621707e0938320b15ddfc87584ab325fbdfd85c30efea36f8f9bd0707d7ec12c344eff3ec21761189518d192df035", "0x8ac7817e71ea0825b292687928e349da7140285d035e1e1abff0c3704fa8453faaae343a441b7143a74ec56539687cc4", "0x8a5e0a9e4758449489df10f3386029ada828d1762e4fb0a8ffe6b79e5b6d5d713cb64ed95960e126398b0cdb89002bc9", "0x81324be4a71208bbb9bca74b77177f8f1abb9d3d5d9db195d1854651f2cf333cd618d35400da0f060f3e1b025124e4b2", "0x849971d9d095ae067525b3cbc4a7dfae81f739537ade6d6cec1b42fb692d923176197a8770907c58069754b8882822d6", "0x89f830825416802477cc81fdf11084885865ee6607aa15aa4eb28e351c569c49b8a1b9b5e95ddc04fa0ebafe20071313", "0x9240aeeaff37a91af55f860b9badd466e8243af9e8c96a7aa8cf348cd270685ab6301bc135b246dca9eda696f8b0e350", "0xacf74db78cc33138273127599eba35b0fb4e7b9a69fe02dae18fc6692d748ca332bd00b22afa8e654ed587aab11833f3", "0xb091e6d37b157b50d76bd297ad752220cd5c9390fac16dc838f8557aed6d9833fc920b61519df21265406216315e883f", "0xa6446c429ebf1c7793c622250e23594c836b2fbcaf6c5b3d0995e1595a37f50ea643f3e549b0be8bbdadd69044d72ab9", "0x93e675353bd60e996bf1c914d5267eeaa8a52fc3077987ccc796710ef9becc6b7a00e3d82671a6bdfb8145ee3c80245a", "0xa2f731e43251d04ed3364aa2f072d05355f299626f2d71a8a38b6f76cf08c544133f7d72dd0ab4162814b674b9fc7fa6", "0x97a8b791a5a8f6e1d0de192d78615d73d0c38f1e557e4e15d15adc663d649e655bc8da3bcc499ef70112eafe7fb45c7a", "0x98cd624cbbd6c53a94469be4643c13130916b91143425bcb7d7028adbbfede38eff7a21092af43b12d4fab703c116359", "0x995783ce38fd5f6f9433027f122d4cf1e1ff3caf2d196ce591877f4a544ce9113ead60de2de1827eaff4dd31a20d79a8", "0x8cf251d6f5229183b7f3fe2f607a90b4e4b6f020fb4ba2459d28eb8872426e7be8761a93d5413640a661d73e34a5b81f", "0xb9232d99620652a3aa7880cad0876f153ff881c4ed4c0c2e7b4ea81d5d42b70daf1a56b869d752c3743c6d4c947e6641", "0x849716f938f9d37250cccb1bf77f5f9fde53096cdfc6f2a25536a6187029a8f1331cdbed08909184b201f8d9f04b792f", "0x80c7c4de098cbf9c6d17b14eba1805e433b5bc905f6096f8f63d34b94734f2e4ebf4bce8a177efd1186842a61204a062", "0xb790f410cf06b9b8daadceeb4fd5ff40a2deda820c8df2537e0a7554613ae3948e149504e3e79aa84889df50c8678eeb", "0x813aab8bd000299cd37485b73cd7cba06e205f8efb87f1efc0bae8b70f6db2bc7702eb39510ad734854fb65515fe9d0f", "0x94f0ab7388ac71cdb67f6b85dfd5945748afb2e5abb622f0b5ad104be1d4d0062b651f134ba22385c9e32c2dfdcccce1", "0xab6223dca8bd6a4f969e21ccd9f8106fc5251d321f9e90cc42cea2424b3a9c4e5060a47eeef6b23c7976109b548498e8", "0x859c56b71343fce4d5c5b87814c47bf55d581c50fd1871a17e77b5e1742f5af639d0e94d19d909ec7dfe27919e954e0c", "0xaae0d632b6191b8ad71b027791735f1578e1b89890b6c22e37de0e4a6074886126988fe8319ae228ac9ef3b3bcccb730", "0x8ca9f32a27a024c3d595ecfaf96b0461de57befa3b331ab71dc110ec3be5824fed783d9516597537683e77a11d334338", "0xa061df379fb3f4b24816c9f6cd8a94ecb89b4c6dc6cd81e4b8096fa9784b7f97ab3540259d1de9c02eb91d9945af4823", "0x998603102ac63001d63eb7347a4bb2bf4cf33b28079bb48a169076a65c20d511ccd3ef696d159e54cc8e772fb5d65d50", "0x94444d96d39450872ac69e44088c252c71f46be8333a608a475147752dbb99db0e36acfc5198f158509401959c12b709", "0xac1b51b6c09fe055c1d7c9176eea9adc33f710818c83a1fbfa073c8dc3a7eb3513cbdd3f5960b7845e31e3e83181e6ba", "0x803d530523fc9e1e0f11040d2412d02baef3f07eeb9b177fa9bfa396af42eea898a4276d56e1db998dc96ae47b644cb2", "0x85a3c9fc7638f5bf2c3e15ba8c2fa1ae87eb1ceb44c6598c67a2948667a9dfa41e61f66d535b4e7fda62f013a5a8b885", "0xa961cf5654c46a1a22c29baf7a4e77837a26b7f138f410e9d1883480ed5fa42411d522aba32040b577046c11f007388e", "0xad1154142344f494e3061ef45a34fab1aaacf5fdf7d1b26adbb5fbc3d795655fa743444e39d9a4119b4a4f82a6f30441", "0xb1d6c30771130c77806e7ab893b73d4deb590b2ff8f2f8b5e54c2040c1f3e060e2bd99afc668cf706a2df666a508bbf6", "0xa00361fd440f9decabd98d96c575cd251dc94c60611025095d1201ef2dedde51cb4de7c2ece47732e5ed9b3526c2012c", "0xa85c5ab4d17d328bda5e6d839a9a6adcc92ff844ec25f84981e4f44a0e8419247c081530f8d9aa629c7eb4ca21affba6", "0xa4ddd3eab4527a2672cf9463db38bc29f61460e2a162f426b7852b7a7645fbd62084fd39a8e4d60e1958cce436dd8f57", "0x811648140080fe55b8618f4cf17f3c5a250adb0cd53d885f2ddba835d2b4433188e41fc0661faac88e4ff910b16278c0", "0xb85c7f1cfb0ed29addccf7546023a79249e8f15ac2d14a20accbfef4dd9dc11355d599815fa09d2b6b4e966e6ea8cff1", "0xa10b5d8c260b159043b020d5dd62b3467df2671afea6d480ca9087b7e60ed170c82b121819d088315902842d66c8fb45", "0x917e191df1bcf3f5715419c1e2191da6b8680543b1ba41fe84ed07ef570376e072c081beb67b375fca3565a2565bcabb", "0x881fd967407390bfd7badc9ab494e8a287559a01eb07861f527207c127eadea626e9bcc5aa9cca2c5112fbac3b3f0e9c", "0x959fd71149af82cc733619e0e5bf71760ca2650448c82984b3db74030d0e10f8ab1ce1609a6de6f470fe8b5bd90df5b3", "0xa3370898a1c5f33d15adb4238df9a6c945f18b9ada4ce2624fc32a844f9ece4c916a64e9442225b6592afa06d2e015f2", "0x817efb8a791435e4236f7d7b278181a5fa34587578c629dbc14fbf9a5c26772290611395eecd20222a4c58649fc256d8", "0xa04c9876acf2cfdc8ef96de4879742709270fa1d03fe4c8511fbef2d59eb0aaf0336fa2c7dfe41a651157377fa217813", "0x81e15875d7ea7f123e418edf14099f2e109d4f3a6ce0eb65f67fe9fb10d2f809a864a29f60ad3fc949f89e2596b21783", "0xb49f529975c09e436e6bc202fdc16e3fdcbe056db45178016ad6fdece9faad4446343e83aed096209690b21a6910724f", "0x879e8eda589e1a279f7f49f6dd0580788c040d973748ec4942dbe51ea8fbd05983cc919b78f0c6b92ef3292ae29db875", "0x81a2b74b2118923f34139a102f3d95e7eee11c4c2929c2576dee200a5abfd364606158535a6c9e4178a6a83dbb65f3c4", "0x8913f281d8927f2b45fc815d0f7104631cb7f5f7278a316f1327d670d15868daadd2a64e3eb98e1f53fe7e300338cc80", "0xa6f815fba7ef9af7fbf45f93bc952e8b351f5de6568a27c7c47a00cb39a254c6b31753794f67940fc7d2e9cc581529f4", "0xb3722a15c66a0014ce4d082de118def8d39190c15678a472b846225585f3a83756ae1b255b2e3f86a26168878e4773b2", "0x817ae61ab3d0dd5b6e24846b5a5364b1a7dc2e77432d9fed587727520ae2f307264ea0948c91ad29f0aea3a11ff38624", "0xb3db467464415fcad36dc1de2d6ba7686772a577cc2619242ac040d6734881a45d3b40ed4588db124e4289cfeec4bbf6", "0xad66a14f5a54ac69603b16e5f1529851183da77d3cc60867f10aea41339dd5e06a5257982e9e90a352cdd32750f42ee4", "0xadafa3681ef45d685555601a25a55cf23358319a17f61e2179e704f63df83a73bdd298d12cf6cef86db89bd17119e11d", "0xa379dc44cb6dd3b9d378c07b2ec654fec7ca2f272de6ba895e3d00d20c9e4c5550498a843c8ac67e4221db2115bedc1c", "0xb7bf81c267a78efc6b9e5a904574445a6487678d7ef70054e3e93ea6a23f966c2b68787f9164918e3b16d2175459ed92", "0xb41d66a13a4afafd5760062b77f79de7e6ab8ccacde9c6c5116a6d886912fb491dc027af435b1b44aacc6af7b3c887f2", "0x9904d23a7c1c1d2e4bab85d69f283eb0a8e26d46e8b7b30224438015c936729b2f0af7c7c54c03509bb0500acb42d8a4", "0xae30d65e9e20c3bfd603994ae2b175ff691d51f3e24b2d058b3b8556d12ca4c75087809062dddd4aaac81c94d15d8a17", "0x9245162fab42ac01527424f6013310c3eb462982518debef6c127f46ba8a06c705d7dc9f0a41e796ba8d35d60ae6cc64", "0x87fab853638d7a29a20f3ba2b1a7919d023e9415bfa78ebb27973d8cbc7626f584dc5665d2e7ad71f1d760eba9700d88", "0x85aac46ecd330608e5272430970e6081ff02a571e8ea444f1e11785ea798769634a22a142d0237f67b75369d3c484a8a", "0x938c85ab14894cc5dfce3d80456f189a2e98eddbc8828f4ff6b1df1dcb7b42b17ca2ff40226a8a1390a95d63dca698dd", "0xa18ce1f846e3e3c4d846822f60271eecf0f5d7d9f986385ac53c5ace9589dc7c0188910448c19b91341a1ef556652fa9", "0x8611608a9d844f0e9d7584ad6ccf62a5087a64f764caf108db648a776b5390feb51e5120f0ef0e9e11301af3987dd7dc", "0x8106333ba4b4de8d1ae43bc9735d3fea047392e88efd6a2fa6f7b924a18a7a265ca6123c3edc0f36307dd7fb7fe89257", "0xa91426fa500951ff1b051a248c050b7139ca30dde8768690432d597d2b3c4357b11a577be6b455a1c5d145264dcf81fc", "0xb7f9f90e0e450f37b081297f7f651bad0496a8b9afd2a4cf4120a2671aaaa8536dce1af301258bfbfdb122afa44c5048", "0x84126da6435699b0c09fa4032dec73d1fca21d2d19f5214e8b0bea43267e9a8dd1fc44f8132d8315e734c8e2e04d7291", "0xaff064708103884cb4f1a3c1718b3fc40a238d35cf0a7dc24bdf9823693b407c70da50df585bf5bc4e9c07d1c2d203e8", "0xa8b40fc6533752983a5329c31d376c7a5c13ce6879cc7faee648200075d9cd273537001fb4c86e8576350eaac6ba60c2", "0xa02db682bdc117a84dcb9312eb28fcbde12d49f4ce915cc92c610bb6965ec3cc38290f8c5b5ec70afe153956692cda95", "0x86decd22b25d300508472c9ce75d3e465b737e7ce13bc0fcce32835e54646fe12322ba5bc457be18bfd926a1a6ca4a38", "0xa18666ef65b8c2904fd598791f5627207165315a85ee01d5fb0e6b2e10bdd9b00babc447da5bd63445e3337de33b9b89", "0x89bb0c06effadefdaf34ffe4b123e1678a90d4451ee856c863df1e752eef41fd984689ded8f0f878bf8916d5dd8e8024", "0x97cfcba08ebec05d0073992a66b1d7d6fb9d95871f2cdc36db301f78bf8069294d1c259efef5c93d20dc937eedae3a1a", "0xac2643b14ece79dcb2e289c96776a47e2bebd40dd6dc74fd035df5bb727b5596f40e3dd2d2202141e69b0993717ede09", "0xa5e6fd88a2f9174d9bd4c6a55d9c30974be414992f22aa852f552c7648f722ed8077acf5aba030abd47939bb451b2c60", "0x8ad40a612824a7994487731a40b311b7349038c841145865539c6ada75c56de6ac547a1c23df190e0caaafecddd80ccc", "0x953a7cea1d857e09202c438c6108060961f195f88c32f0e012236d7a4b39d840c61b162ec86436e8c38567328bea0246", "0x80d8b47a46dae1868a7b8ccfe7029445bbe1009dad4a6c31f9ef081be32e8e1ac1178c3c8fb68d3e536c84990cc035b1", "0x81ecd99f22b3766ce0aca08a0a9191793f68c754fdec78b82a4c3bdc2db122bbb9ebfd02fc2dcc6e1567a7d42d0cc16a", "0xb1dd0446bccc25846fb95d08c1c9cc52fb51c72c4c5d169ffde56ecfe800f108dc1106d65d5c5bd1087c656de3940b63", "0xb87547f0931e164e96de5c550ca5aa81273648fe34f6e193cd9d69cf729cb432e17aa02e25b1c27a8a0d20a3b795e94e", "0x820a94e69a927e077082aae66f6b292cfbe4589d932edf9e68e268c9bd3d71ef76cf7d169dd445b93967c25db11f58f1", "0xb0d07ddf2595270c39adfa0c8cf2ab1322979b0546aa4d918f641be53cd97f36c879bb75d205e457c011aca3bbd9f731", "0x8700b876b35b4b10a8a9372c5230acecd39539c1bb87515640293ad4464a9e02929d7d6a6a11112e8a29564815ac0de4", "0xa61a601c5bb27dcb97e37c8e2b9ce479c6b192a5e04d9ed5e065833c5a1017ee5f237b77d1a17be5d48f8e7cc0bcacf6", "0x92fb88fe774c1ba1d4a08cae3c0e05467ad610e7a3f1d2423fd47751759235fe0a3036db4095bd6404716aa03820f484", "0xb274f140d77a3ce0796f5e09094b516537ccaf27ae1907099bff172e6368ba85e7c3ef8ea2a07457cac48ae334da95b3", "0xb2292d9181f16581a9a9142490b2bdcdfb218ca6315d1effc8592100d792eb89d5356996c890441f04f2b4a95763503e", "0x8897e73f576d86bc354baa3bd96e553107c48cf5889dcc23c5ba68ab8bcd4e81f27767be2233fdfa13d39f885087e668", "0xa29eac6f0829791c728d71abc49569df95a4446ecbfc534b39f24f56c88fe70301838dfc1c19751e7f3c5c1b8c6af6a0", "0x9346dc3720adc5df500a8df27fd9c75ef38dc5c8f4e8ed66983304750e66d502c3c59b8e955be781b670a0afc70a2167", "0x9566d534e0e30a5c5f1428665590617e95fd05d45f573715f58157854ad596ece3a3cfec61356aee342308d623e029d5", "0xa464fb8bffe6bd65f71938c1715c6e296cc6d0311a83858e4e7eb5873b7f2cf0c584d2101e3407b85b64ca78b2ac93ce", "0xb54088f7217987c87e9498a747569ac5b2f8afd5348f9c45bf3fd9fbf713a20f495f49c8572d087efe778ac7313ad6d3", "0x91fa9f5f8000fe050f5b224d90b59fcce13c77e903cbf98ded752e5b3db16adb2bc1f8c94be48b69f65f1f1ad81d6264", "0x92d04a5b0ac5d8c8e313709b432c9434ecd3e73231f01e9b4e7952b87df60cbfa97b5dedd2200bd033b4b9ea8ba45cc1", "0xa94b90ad3c3d6c4bbe169f8661a790c40645b40f0a9d1c7220f01cf7fc176e04d80bab0ced9323fcafb93643f12b2760", "0x94d86149b9c8443b46196f7e5a3738206dd6f3be7762df488bcbb9f9ee285a64c997ed875b7b16b26604fa59020a8199", "0x82efe4ae2c50a2d7645240c173a047f238536598c04a2c0b69c96e96bd18e075a99110f1206bc213f39edca42ba00cc1", "0xab8667685f831bc14d4610f84a5da27b4ea5b133b4d991741a9e64dceb22cb64a3ce8f1b6e101d52af6296df7127c9ad", "0x83ba433661c05dcc5d562f4a9a261c8110dac44b8d833ae1514b1fc60d8b4ee395b18804baea04cb10adb428faf713c3", "0xb5748f6f660cc5277f1211d2b8649493ed8a11085b871cd33a5aea630abd960a740f08c08be5f9c21574600ac9bf5737", "0xa5c8dd12af48fb710642ad65ebb97ca489e8206741807f7acfc334f8035d3c80593b1ff2090c9bb7bd138f0c48714ca8", "0xa2b382fd5744e3babf454b1d806cc8783efeb4761bc42b6914ea48a46a2eae835efbe0a18262b6bc034379e03cf1262b", "0xb3145ffaf603f69f15a64936d32e3219eea5ed49fdfd2f5bf40ea0dfd974b36fb6ff12164d4c2282d892db4cf3ff3ce1", "0x87a316fb213f4c5e30c5e3face049db66be4f28821bd96034714ec23d3e97849d7b301930f90a4323c7ccf53de23050c", "0xb9de09a919455070fed6220fc179c8b7a4c753062bcd27acf28f5b9947a659c0b364298daf7c85c4ca6fca7f945add1f", "0x806fbd98d411b76979464c40ad88bc07a151628a27fcc1012ba1dfbaf5b5cc9d962fb9b3386008978a12515edce934bc", "0xa15268877fae0d21610ae6a31061ed7c20814723385955fac09fdc9693a94c33dea11db98bb89fdfe68f933490f5c381", "0x8d633fb0c4da86b2e0b37d8fad5972d62bff2ac663c5ec815d095cd4b7e1fe66ebef2a2590995b57eaf941983c7ad7a4", "0x8139e5dd9cf405e8ef65f11164f0440827d98389ce1b418b0c9628be983a9ddd6cf4863036ccb1483b40b8a527acd9ed", "0x88b15fa94a08eac291d2b94a2b30eb851ff24addf2cc30b678e72e32cfcb3424cf4b33aa395d741803f3e578ddf524de", "0xb5eaf0c8506e101f1646bcf049ee38d99ea1c60169730da893fd6020fd00a289eb2f415947e44677af49e43454a7b1be", "0x8489822ad0647a7e06aa2aa5595960811858ddd4542acca419dd2308a8c5477648f4dd969a6740bb78aa26db9bfcc555", "0xb1e9a7b9f3423c220330d45f69e45fa03d7671897cf077f913c252e3e99c7b1b1cf6d30caad65e4228d5d7b80eb86e5e", "0xb28fe9629592b9e6a55a1406903be76250b1c50c65296c10c5e48c64b539fb08fe11f68cf462a6edcbba71b0cee3feb2", "0xa41acf96a02c96cd8744ff6577c244fc923810d17ade133587e4c223beb7b4d99fa56eae311a500d7151979267d0895c", "0x880798938fe4ba70721be90e666dfb62fcab4f3556fdb7b0dc8ec5bc34f6b4513df965eae78527136eb391889fe2caf9", "0x98d4d89d358e0fb7e212498c73447d94a83c1b66e98fc81427ab13acddb17a20f52308983f3a5a8e0aaacec432359604", "0x81430b6d2998fc78ba937a1639c6020199c52da499f68109da227882dc26d005b73d54c5bdcac1a04e8356a8ca0f7017", "0xa8d906a4786455eb74613aba4ce1c963c60095ffb8658d368df9266fdd01e30269ce10bf984e7465f34b4fd83beba26a", "0xaf54167ac1f954d10131d44a8e0045df00d581dd9e93596a28d157543fbe5fb25d213806ed7fb3cba6b8f5b5423562db", "0x8511e373a978a12d81266b9afbd55035d7bc736835cfa921903a92969eeba3624437d1346b55382e61415726ab84a448", "0x8cf43eea93508ae586fa9a0f1354a1e16af659782479c2040874a46317f9e8d572a23238efa318fdfb87cc63932602b7", "0xb0bdd3bacff077173d302e3a9678d1d37936188c7ecc34950185af6b462b7c679815176f3cce5db19aac8b282f2d60ad", "0xa355e9b87f2f2672052f5d4d65b8c1c827d24d89b0d8594641fccfb69aef1b94009105f3242058bb31c8bf51caae5a41", "0xb8baa9e4b950b72ff6b88a6509e8ed1304bc6fd955748b2e59a523a1e0c5e99f52aec3da7fa9ff407a7adf259652466c", "0x840bc3dbb300ea6f27d1d6dd861f15680bd098be5174f45d6b75b094d0635aced539fa03ddbccb453879de77fb5d1fe9", "0xb4bc7e7e30686303856472bae07e581a0c0bfc815657c479f9f5931cff208d5c12930d2fd1ff413ebd8424bcd7a9b571", "0x89b5d514155d7999408334a50822508b9d689add55d44a240ff2bdde2eee419d117031f85e924e2a2c1ca77db9b91eea", "0xa8604b6196f87a04e1350302e8aa745bba8dc162115d22657b37a1d1a98cb14876ddf7f65840b5dbd77e80cd22b4256c", "0x83cb7acdb9e03247515bb2ce0227486ccf803426717a14510f0d59d45e998b245797d356f10abca94f7a14e1a2f0d552", "0xaeb3266a9f16649210ab2df0e1908ac259f34ce1f01162c22b56cf1019096ee4ea5854c36e30bb2feb06c21a71e8a45c", "0x89e72e86edf2aa032a0fc9acf4d876a40865fbb2c8f87cb7e4d88856295c4ac14583e874142fd0c314a49aba68c0aa3c", "0x8c3576eba0583c2a7884976b4ed11fe1fda4f6c32f6385d96c47b0e776afa287503b397fa516a455b4b8c3afeedc76db", "0xa31e5b633bda9ffa174654fee98b5d5930a691c3c42fcf55673d927dbc8d91c58c4e42e615353145431baa646e8bbb30", "0x89f2f3f7a8da1544f24682f41c68114a8f78c86bd36b066e27da13acb70f18d9f548773a16bd8e24789420e17183f137", "0xada27fa4e90a086240c9164544d2528621a415a5497badb79f8019dc3dce4d12eb6b599597e47ec6ac39c81efda43520", "0x90dc1eb21bf21c0187f359566fc4bf5386abea52799306a0e5a1151c0817c5f5bc60c86e76b1929c092c0f3ff48cedd2", "0xb702a53ebcc17ae35d2e735a347d2c700e9cbef8eadbece33cac83df483b2054c126593e1f462cfc00a3ce9d737e2af5", "0x9891b06455ec925a6f8eafffba05af6a38cc5e193acaaf74ffbf199df912c5197106c5e06d72942bbb032ce277b6417f", "0x8c0ee71eb01197b019275bcf96cae94e81d2cdc3115dbf2d8e3080074260318bc9303597e8f72b18f965ad601d31ec43", "0x8aaf580aaf75c1b7a5f99ccf60503506e62058ef43b28b02f79b8536a96be3f019c9f71caf327b4e6730134730d1bef5", "0xae6f9fc21dd7dfa672b25a87eb0a41644f7609fab5026d5cedb6e43a06dbbfd6d6e30322a2598c8dedde88c52eaed626", "0x8159b953ffece5693edadb2e906ebf76ff080ee1ad22698950d2d3bfc36ac5ea78f58284b2ca180664452d55bd54716c", "0xab7647c32ca5e9856ac283a2f86768d68de75ceeba9e58b74c5324f8298319e52183739aba4340be901699d66ac9eb3f", "0xa4d85a5701d89bcfaf1572db83258d86a1a0717603d6f24ac2963ffcf80f1265e5ab376a4529ca504f4396498791253c", "0x816080c0cdbfe61b4d726c305747a9eb58ac26d9a35f501dd32ba43c098082d20faf3ccd41aad24600aa73bfa453dfac", "0x84f3afac024f576b0fd9acc6f2349c2fcefc3f77dbe5a2d4964d14b861b88e9b1810334b908cf3427d9b67a8aee74b18", "0x94b390655557b1a09110018e9b5a14490681ade275bdc83510b6465a1218465260d9a7e2a6e4ec700f58c31dc3659962", "0xa8c66826b1c04a2dd4c682543242e7a57acae37278bd09888a3d17747c5b5fec43548101e6f46d703638337e2fd3277b", "0x86e6f4608a00007fa533c36a5b054c5768ccafe41ad52521d772dcae4c8a4bcaff8f7609be30d8fab62c5988cbbb6830", "0x837da4cf09ae8aa0bceb16f8b3bfcc3b3367aecac9eed6b4b56d7b65f55981ef066490764fb4c108792623ecf8cad383", "0x941ff3011462f9b5bf97d8cbdb0b6f5d37a1b1295b622f5485b7d69f2cb2bcabc83630dae427f0259d0d9539a77d8424", "0xb99e5d6d82aa9cf7d5970e7f710f4039ac32c2077530e4c2779250c6b9b373bc380adb0a03b892b652f649720672fc8c", "0xa791c78464b2d65a15440b699e1e30ebd08501d6f2720adbc8255d989a82fcded2f79819b5f8f201bed84a255211b141", "0x84af7ad4a0e31fcbb3276ab1ad6171429cf39adcf78dc03750dc5deaa46536d15591e26d53e953dfb31e1622bc0743ab", "0xa833e62fe97e1086fae1d4917fbaf09c345feb6bf1975b5cb863d8b66e8d621c7989ab3dbecda36bc9eaffc5eaa6fa66", "0xb4ef79a46a2126f53e2ebe62770feb57fd94600be29459d70a77c5e9cc260fa892be06cd60f886bf48459e48eb50d063", "0xb43b8f61919ea380bf151c294e54d3a3ff98e20d1ee5efbfe38aa2b66fafbc6a49739793bd5cb1c809f8b30466277c3a", "0xab37735af2412d2550e62df9d8b3b5e6f467f20de3890bf56faf1abf2bf3bd1d98dc3fa0ad5e7ab3fce0fa20409eb392", "0x82416b74b1551d484250d85bb151fabb67e29cce93d516125533df585bc80779ab057ea6992801a3d7d5c6dcff87a018", "0x8145d0787f0e3b5325190ae10c1d6bee713e6765fb6a0e9214132c6f78f4582bb2771aaeae40d3dad4bafb56bf7e36d8", "0xb6935886349ecbdd5774e12196f4275c97ec8279fdf28ccf940f6a022ebb6de8e97d6d2173c3fe402cbe9643bed3883b", "0x87ef9b4d3dc71ac86369f8ed17e0dd3b91d16d14ae694bc21a35b5ae37211b043d0e36d8ff07dcc513fb9e6481a1f37f", "0xae1d0ded32f7e6f1dc8fef495879c1d9e01826f449f903c1e5034aeeabc5479a9e323b162b688317d46d35a42d570d86", "0xa40d16497004db4104c6794e2f4428d75bdf70352685944f3fbe17526df333e46a4ca6de55a4a48c02ecf0bde8ba03c0", "0x8d45121efba8cc308a498e8ee39ea6fa5cae9fb2e4aab1c2ff9d448aa8494ccbec9a078f978a86fcd97b5d5e7be7522a", "0xa8173865c64634ba4ac2fa432740f5c05056a9deaf6427cb9b4b8da94ca5ddbc8c0c5d3185a89b8b28878194de9cdfcd", "0xb6ec06a74d690f6545f0f0efba236e63d1fdfba54639ca2617408e185177ece28901c457d02b849fd00f1a53ae319d0a", "0xb69a12df293c014a40070e3e760169b6f3c627caf9e50b35a93f11ecf8df98b2bc481b410eecb7ab210bf213bbe944de", "0x97e7dc121795a533d4224803e591eef3e9008bab16f12472210b73aaf77890cf6e3877e0139403a0d3003c12c8f45636", "0xacdfa6fdd4a5acb7738cc8768f7cba84dbb95c639399b291ae8e4e63df37d2d4096900a84d2f0606bf534a9ccaa4993f", "0x86ee253f3a9446a33e4d1169719b7d513c6b50730988415382faaf751988c10a421020609f7bcdef91be136704b906e2", "0xaac9438382a856caf84c5a8a234282f71b5fc5f65219103b147e7e6cf565522285fbfd7417b513bdad8277a00f652ca1", "0x83f3799d8e5772527930f5dc071a2e0a65471618993ec8990a96ccdeee65270e490bda9d26bb877612475268711ffd80", "0x93f28a81ac8c0ec9450b9d762fae9c7f8feaace87a6ee6bd141ef1d2d0697ef1bbd159fe6e1de640dbdab2b0361fca8a", "0xa0825c95ba69999b90eac3a31a3fd830ea4f4b2b7409bde5f202b61d741d6326852ce790f41de5cb0eccec7af4db30c1", "0x83924b0e66233edd603c3b813d698daa05751fc34367120e3cf384ea7432e256ccee4d4daf13858950549d75a377107d", "0x956fd9fa58345277e06ba2ec72f49ed230b8d3d4ff658555c52d6cddeb84dd4e36f1a614f5242d5ca0192e8daf0543c2", "0x944869912476baae0b114cced4ff65c0e4c90136f73ece5656460626599051b78802df67d7201c55d52725a97f5f29fe", "0x865cb25b64b4531fb6fe4814d7c8cd26b017a6c6b72232ff53defc18a80fe3b39511b23f9e4c6c7249d06e03b2282ed2", "0x81e09ff55214960775e1e7f2758b9a6c4e4cd39edf7ec1adfaad51c52141182b79fe2176b23ddc7df9fd153e5f82d668", "0xb31006896f02bc90641121083f43c3172b1039334501fbaf1672f7bf5d174ddd185f945adf1a9c6cf77be34c5501483d", "0x88b92f6f42ae45e9f05b16e52852826e933efd0c68b0f2418ac90957fd018df661bc47c8d43c2a7d7bfcf669dab98c3c", "0x92fc68f595853ee8683930751789b799f397135d002eda244fe63ecef2754e15849edde3ba2f0cc8b865c9777230b712", "0x99ca06a49c5cd0bb097c447793fcdd809869b216a34c66c78c7e41e8c22f05d09168d46b8b1f3390db9452d91bc96dea", "0xb48b9490a5d65296802431852d548d81047bbefc74fa7dc1d4e2a2878faacdfcb365ae59209cb0ade01901a283cbd15d", "0xaff0fdbef7c188b120a02bc9085d7b808e88f73973773fef54707bf2cd772cd066740b1b6f4127b5c349f657bd97e738", "0x966fd4463b4f43dd8ccba7ad50baa42292f9f8b2e70da23bb6780e14155d9346e275ef03ddaf79e47020dcf43f3738bd", "0x9330c3e1fadd9e08ac85f4839121ae20bbeb0a5103d84fa5aadbd1213805bdcda67bf2fb75fc301349cbc851b5559d20", "0x993bb99867bd9041a71a55ad5d397755cfa7ab6a4618fc526179bfc10b7dc8b26e4372fe9a9b4a15d64f2b63c1052dda", "0xa29b59bcfab51f9b3c490a3b96f0bf1934265c315349b236012adbd64a56d7f6941b2c8cc272b412044bc7731f71e1dc", "0xa65c9cefe1fc35d089fe8580c2e7671ebefdb43014ac291528ff4deefd4883fd4df274af83711dad610dad0d615f9d65", "0x944c78c56fb227ae632805d448ca3884cd3d2a89181cead3d2b7835e63297e6d740aa79a112edb1d4727824991636df5", "0xa73d782da1db7e4e65d7b26717a76e16dd9fab4df65063310b8e917dc0bc24e0d6755df5546c58504d04d9e68c3b474a", "0xaf80f0b87811ae3124f68108b4ca1937009403f87928bbc53480e7c5408d072053ace5eeaf5a5aba814dab8a45502085", "0x88aaf1acfc6e2e19b8387c97da707cb171c69812fefdd4650468e9b2c627bd5ccfb459f4d8e56bdfd84b09ddf87e128f", "0x92c97276ff6f72bab6e9423d02ad6dc127962dbce15a0dd1e4a393b4510c555df6aa27be0f697c0d847033a9ca8b8dfd", "0xa0e07d43d96e2d85b6276b3c60aadb48f0aedf2de8c415756dc597249ea64d2093731d8735231dadc961e5682ac59479", "0xadc9e6718a8f9298957d1da3842a7751c5399bbdf56f8de6c1c4bc39428f4aee6f1ba6613d37bf46b9403345e9d6fc81", "0x951da434da4b20d949b509ceeba02e24da7ed2da964c2fcdf426ec787779c696b385822c7dbea4df3e4a35921f1e912c", "0xa04cbce0d2b2e87bbf038c798a12ec828423ca6aca08dc8d481cf6466e3c9c73d4d4a7fa47df9a7e2e15aae9e9f67208", "0x8f855cca2e440d248121c0469de1f94c2a71b8ee2682bbad3a78243a9e03da31d1925e6760dbc48a1957e040fae9abe8", "0xb642e5b17c1df4a4e101772d73851180b3a92e9e8b26c918050f51e6dd3592f102d20b0a1e96f0e25752c292f4c903ff", "0xa92454c300781f8ae1766dbbb50a96192da7d48ef4cbdd72dd8cbb44c6eb5913c112cc38e9144615fdc03684deb99420", "0x8b74f7e6c2304f8e780df4649ef8221795dfe85fdbdaa477a1542d135b75c8be45bf89adbbb6f3ddf54ca40f02e733e9", "0x85cf66292cbb30cec5fd835ab10c9fcb3aea95e093aebf123e9a83c26f322d76ebc89c4e914524f6c5f6ee7d74fc917d", "0xae0bfe0cdc97c09542a7431820015f2d16067b30dca56288013876025e81daa8c519e5e347268e19aa1a85fa1dc28793", "0x921322fc6a47dc091afa0ad6df18ed14cde38e48c6e71550aa513918b056044983aee402de21051235eecf4ce8040fbe", "0x96c030381e97050a45a318d307dcb3c8377b79b4dd5daf6337cded114de26eb725c14171b9b8e1b3c08fe1f5ea6b49e0", "0x90c23b86b6111818c8baaf53a13eaee1c89203b50e7f9a994bf0edf851919b48edbac7ceef14ac9414cf70c486174a77", "0x8bf6c301240d2d1c8d84c71d33a6dfc6d9e8f1cfae66d4d0f7a256d98ae12b0bcebfa94a667735ee89f810bcd7170cff", "0xa41a4ffbbea0e36874d65c009ee4c3feffff322f6fc0e30d26ee4dbc1f46040d05e25d9d0ecb378cef0d24a7c2c4b850", "0xa8d4cdd423986bb392a0a92c12a8bd4da3437eec6ef6af34cf5310944899287452a2eb92eb5386086d5063381189d10e", "0xa81dd26ec057c4032a4ed7ad54d926165273ed51d09a1267b2e477535cf6966835a257c209e4e92d165d74fa75695fa3", "0x8d7f708c3ee8449515d94fc26b547303b53d8dd55f177bc3b25d3da2768accd9bc8e9f09546090ebb7f15c66e6c9c723", "0x839ba65cffcd24cfffa7ab3b21faabe3c66d4c06324f07b2729c92f15cad34e474b0f0ddb16cd652870b26a756b731d3", "0x87f1a3968afec354d92d77e2726b702847c6afcabb8438634f9c6f7766de4c1504317dc4fa9a4a735acdbf985e119564", "0x91a8a7fd6542f3e0673f07f510d850864b34ac087eb7eef8845a1d14b2b1b651cbdc27fa4049bdbf3fea54221c5c8549", "0xaef3cf5f5e3a2385ead115728d7059e622146c3457d266c612e778324b6e06fbfb8f98e076624d2f3ce1035d65389a07", "0x819915d6232e95ccd7693fdd78d00492299b1983bc8f96a08dcb50f9c0a813ed93ae53c0238345d5bea0beda2855a913", "0x8e9ba68ded0e94935131b392b28218315a185f63bf5e3c1a9a9dd470944509ca0ba8f6122265f8da851b5cc2abce68f1", "0xb28468e9b04ee9d69003399a3cf4457c9bf9d59f36ab6ceeb8e964672433d06b58beeea198fedc7edbaa1948577e9fa2", "0xa633005e2c9f2fd94c8bce2dd5bb708fe946b25f1ec561ae65e54e15cdd88dc339f1a083e01f0d39610c8fe24151aaf0", "0x841d0031e22723f9328dd993805abd13e0c99b0f59435d2426246996b08d00ce73ab906f66c4eab423473b409e972ce0", "0x85758d1b084263992070ec8943f33073a2d9b86a8606672550c17545507a5b3c88d87382b41916a87ee96ff55a7aa535", "0x8581b06b0fc41466ef94a76a1d9fb8ae0edca6d018063acf6a8ca5f4b02d76021902feba58972415691b4bdbc33ae3b4", "0x83539597ff5e327357ee62bc6bf8c0bcaec2f227c55c7c385a4806f0d37fb461f1690bad5066b8a5370950af32fafbef", "0xaee3557290d2dc10827e4791d00e0259006911f3f3fce4179ed3c514b779160613eca70f720bff7804752715a1266ffa", "0xb48d2f0c4e90fc307d5995464e3f611a9b0ef5fe426a289071f4168ed5cc4f8770c9332960c2ca5c8c427f40e6bb389f", "0x847af8973b4e300bb06be69b71b96183fd1a0b9d51b91701bef6fcfde465068f1eb2b1503b07afda380f18d69de5c9e1", "0xa70a6a80ce407f07804c0051ac21dc24d794b387be94eb24e1db94b58a78e1bcfb48cd0006db8fc1f9bedaece7a44fbe", "0xb40e942b8fa5336910ff0098347df716bff9d1fa236a1950c16eeb966b3bc1a50b8f7b0980469d42e75ae13ced53cead", "0xb208fabaa742d7db3148515330eb7a3577487845abdb7bd9ed169d0e081db0a5816595c33d375e56aeac5b51e60e49d3", "0xb7c8194b30d3d6ef5ab66ec88ad7ebbc732a3b8a41731b153e6f63759a93f3f4a537eab9ad369705bd730184bdbbdc34", "0x9280096445fe7394d04aa1bc4620c8f9296e991cc4d6c131bd703cb1cc317510e6e5855ac763f4d958c5edfe7eebeed7", "0xabc2aa4616a521400af1a12440dc544e3c821313d0ab936c86af28468ef8bbe534837e364598396a81cf8d06274ed5a6", "0xb18ca8a3325adb0c8c18a666d4859535397a1c3fe08f95eebfac916a7a99bbd40b3c37b919e8a8ae91da38bc00fa56c0", "0x8a40c33109ecea2a8b3558565877082f79121a432c45ec2c5a5e0ec4d1c203a6788e6b69cb37f1fd5b8c9a661bc5476d", "0x88c47301dd30998e903c84e0b0f2c9af2e1ce6b9f187dab03528d44f834dc991e4c86d0c474a2c63468cf4020a1e24a0", "0x920c832853e6ab4c851eecfa9c11d3acc7da37c823be7aa1ab15e14dfd8beb5d0b91d62a30cec94763bd8e4594b66600", "0x98e1addbe2a6b8edc7f12ecb9be81c3250aeeca54a1c6a7225772ca66549827c15f3950d01b8eb44aecb56fe0fff901a", "0x8cfb0fa1068be0ec088402f5950c4679a2eb9218c729da67050b0d1b2d7079f3ddf4bf0f57d95fe2a8db04bc6bcdb20c", "0xb70f381aafe336b024120453813aeab70baac85b9c4c0f86918797b6aee206e6ed93244a49950f3d8ec9f81f4ac15808", "0xa4c8edf4aa33b709a91e1062939512419711c1757084e46f8f4b7ed64f8e682f4e78b7135920c12f0eb0422fe9f87a6a", "0xb4817e85fd0752d7ebb662d3a51a03367a84bac74ebddfba0e5af5e636a979500f72b148052d333b3dedf9edd2b4031b", "0xa87430169c6195f5d3e314ff2d1c2f050e766fd5d2de88f5207d72dba4a7745bb86d0baca6e9ae156582d0d89e5838c7", "0x991b00f8b104566b63a12af4826b61ce7aa40f4e5b8fff3085e7a99815bdb4471b6214da1e480214fac83f86a0b93cc5", "0xb39966e3076482079de0678477df98578377a094054960ee518ef99504d6851f8bcd3203e8da5e1d4f6f96776e1fe6eb", "0xa448846d9dc2ab7a0995fa44b8527e27f6b3b74c6e03e95edb64e6baa4f1b866103f0addb97c84bef1d72487b2e21796", "0x894bec21a453ae84b592286e696c35bc30e820e9c2fd3e63dd4fbe629e07df16439c891056070faa490155f255bf7187", "0xa9ec652a491b11f6a692064e955f3f3287e7d2764527e58938571469a1e29b5225b9415bd602a45074dfbfe9c131d6ca", "0xb39d37822e6cbe28244b5f42ce467c65a23765bd16eb6447c5b3e942278069793763483dafd8c4dd864f8917aad357fe", "0x88dba51133f2019cb266641c56101e3e5987d3b77647a2e608b5ff9113dfc5f85e2b7c365118723131fbc0c9ca833c9c", "0xb566579d904b54ecf798018efcb824dccbebfc6753a0fd2128ac3b4bd3b038c2284a7c782b5ca6f310eb7ea4d26a3f0a", "0xa97a55c0a492e53c047e7d6f9d5f3e86fb96f3dddc68389c0561515343b66b4bc02a9c0d5722dff1e3445308240b27f7", "0xa044028ab4bcb9e1a2b9b4ca4efbf04c5da9e4bf2fff0e8bd57aa1fc12a71e897999c25d9117413faf2f45395dee0f13", "0xa78dc461decbeaeed8ebd0909369b491a5e764d6a5645a7dac61d3140d7dc0062526f777b0eb866bff27608429ebbdde", "0xb2c2a8991f94c39ca35fea59f01a92cb3393e0eccb2476dfbf57261d406a68bd34a6cff33ed80209991688c183609ef4", "0x84189eefb521aff730a4fd3fd5b10ddfd29f0d365664caef63bb015d07e689989e54c33c2141dd64427805d37a7e546e", "0x85ac80bd734a52235da288ff042dea9a62e085928954e8eacd2c751013f61904ed110e5b3afe1ab770a7e6485efb7b5e", "0x9183a560393dcb22d0d5063e71182020d0fbabb39e32493eeffeb808df084aa243eb397027f150b55a247d1ed0c8513e", "0x81c940944df7ecc58d3c43c34996852c3c7915ed185d7654627f7af62abae7e0048dd444a6c09961756455000bd96d09", "0xaa8c34e164019743fd8284b84f06c3b449aae7996e892f419ee55d82ad548cb300fd651de329da0384243954c0ef6a60", "0x89a7b7bdfc7e300d06a14d463e573d6296d8e66197491900cc9ae49504c4809ff6e61b758579e9091c61085ba1237b83", "0x878d21809ba540f50bd11f4c4d9590fb6f3ab9de5692606e6e2ef4ed9d18520119e385be5e1f4b3f2e2b09c319f0e8fc", "0x8eb248390193189cf0355365e630b782cd15751e672dc478b39d75dc681234dcd9309df0d11f4610dbb249c1e6be7ef9", "0xa1d7fb3aecb896df3a52d6bd0943838b13f1bd039c936d76d03de2044c371d48865694b6f532393b27fd10a4cf642061", "0xa34bca58a24979be442238cbb5ece5bee51ae8c0794dd3efb3983d4db713bc6f28a96e976ac3bd9a551d3ed9ba6b3e22", "0x817c608fc8cacdd178665320b5a7587ca21df8bdd761833c3018b967575d25e3951cf3d498a63619a3cd2ad4406f5f28", "0x86c95707db0495689afd0c2e39e97f445f7ca0edffad5c8b4cacd1421f2f3cc55049dfd504f728f91534e20383955582", "0x99c3b0bb15942c301137765d4e19502f65806f3b126dc01a5b7820c87e8979bce6a37289a8f6a4c1e4637227ad5bf3bf", "0x8aa1518a80ea8b074505a9b3f96829f5d4afa55a30efe7b4de4e5dbf666897fdd2cf31728ca45921e21a78a80f0e0f10", "0x8d74f46361c79e15128ac399e958a91067ef4cec8983408775a87eca1eed5b7dcbf0ddf30e66f51780457413496c7f07", "0xa41cde4a786b55387458a1db95171aca4fd146507b81c4da1e6d6e495527c3ec83fc42fad1dfe3d92744084a664fd431", "0x8c352852c906fae99413a84ad11701f93f292fbf7bd14738814f4c4ceab32db02feb5eb70bc73898b0bc724a39d5d017", "0xa5993046e8f23b71ba87b7caa7ace2d9023fb48ce4c51838813174880d918e9b4d2b0dc21a2b9c6f612338c31a289df8", "0x83576d3324bf2d8afbfb6eaecdc5d767c8e22e7d25160414924f0645491df60541948a05e1f4202e612368e78675de8a", "0xb43749b8df4b15bc9a3697e0f1c518e6b04114171739ef1a0c9c65185d8ec18e40e6954d125cbc14ebc652cf41ad3109", "0xb4eebd5d80a7327a040cafb9ccdb12b2dfe1aa86e6bc6d3ac8a57fadfb95a5b1a7332c66318ff72ba459f525668af056", "0x9198be7f1d413c5029b0e1c617bcbc082d21abe2c60ec8ce9b54ca1a85d3dba637b72fda39dae0c0ae40d047eab9f55a", "0x8d96a0232832e24d45092653e781e7a9c9520766c3989e67bbe86b3a820c4bf621ea911e7cd5270a4bfea78b618411f6", "0x8d7160d0ea98161a2d14d46ef01dff72d566c330cd4fabd27654d300e1bc7644c68dc8eabf2a20a59bfe7ba276545f9b", "0xabb60fce29dec7ba37e3056e412e0ec3e05538a1fc0e2c68877378c867605966108bc5742585ab6a405ce0c962b285b6", "0x8fabffa3ed792f05e414f5839386f6449fd9f7b41a47595c5d71074bd1bb3784cc7a1a7e1ad6b041b455035957e5b2dc", "0x90ff017b4804c2d0533b72461436b10603ab13a55f86fd4ec11b06a70ef8166f958c110519ca1b4cc7beba440729fe2d", "0xb340cfd120f6a4623e3a74cf8c32bfd7cd61a280b59dfd17b15ca8fae4d82f64a6f15fbde4c02f424debc72b7db5fe67", "0x871311c9c7220c932e738d59f0ecc67a34356d1429fe570ca503d340c9996cb5ee2cd188fad0e3bd16e4c468ec1dbebd", "0xa772470262186e7b94239ba921b29f2412c148d6f97c4412e96d21e55f3be73f992f1ad53c71008f0558ec3f84e2b5a7", "0xb2a897dcb7ffd6257f3f2947ec966f2077d57d5191a88840b1d4f67effebe8c436641be85524d0a21be734c63ab5965d", "0xa044f6eacc48a4a061fa149500d96b48cbf14853469aa4d045faf3dca973be1bd4b4ce01646d83e2f24f7c486d03205d", "0x981af5dc2daa73f7fa9eae35a93d81eb6edba4a7f673b55d41f6ecd87a37685d31bb40ef4f1c469b3d72f2f18b925a17", "0x912d2597a07864de9020ac77083eff2f15ceb07600f15755aba61251e8ce3c905a758453b417f04d9c38db040954eb65", "0x9642b7f6f09394ba5e0805734ef6702c3eddf9eea187ba98c676d5bbaec0e360e3e51dc58433aaa1e2da6060c8659cb7", "0x8ab3836e0a8ac492d5e707d056310c4c8e0489ca85eb771bff35ba1d658360084e836a6f51bb990f9e3d2d9aeb18fbb5", "0x879e058e72b73bb1f4642c21ffdb90544b846868139c6511f299aafe59c2d0f0b944dffc7990491b7c4edcd6a9889250", "0xb9e60b737023f61479a4a8fd253ed0d2a944ea6ba0439bbc0a0d3abf09b0ad1f18d75555e4a50405470ae4990626f390", "0xb9c2535d362796dcd673640a9fa2ebdaec274e6f8b850b023153b0a7a30fffc87f96e0b72696f647ebe7ab63099a6963", "0x94aeff145386a087b0e91e68a84a5ede01f978f9dd9fe7bebca78941938469495dc30a96bba9508c0d017873aeea9610", "0x98b179f8a3d9f0d0a983c30682dd425a2ddc7803be59bd626c623c8951a5179117d1d2a68254c95c9952989877d0ee55", "0x889ecf5f0ee56938273f74eb3e9ecfb5617f04fb58e83fe4c0e4aef51615cf345bc56f3f61b17f6eed3249d4afd54451", "0xa0f2b2c39bcea4b50883e2587d16559e246248a66ecb4a4b7d9ab3b51fb39fe98d83765e087eee37a0f86b0ba4144c02", "0xb2a61e247ed595e8a3830f7973b07079cbda510f28ad8c78c220b26cb6acde4fbb5ee90c14a665f329168ee951b08cf0", "0x95bd0fcfb42f0d6d8a8e73d7458498a85bcddd2fb132fd7989265648d82ac2707d6d203fac045504977af4f0a2aca4b7", "0x843e5a537c298666e6cf50fcc044f13506499ef83c802e719ff2c90e85003c132024e04711be7234c04d4b0125512d5d", "0xa46d1797c5959dcd3a5cfc857488f4d96f74277c3d13b98b133620192f79944abcb3a361d939a100187f1b0856eae875", "0xa1c7786736d6707a48515c38660615fcec67eb8a2598f46657855215f804fd72ab122d17f94fcffad8893f3be658dca7", "0xb23dc9e610abc7d8bd21d147e22509a0fa49db5be6ea7057b51aae38e31654b3aa044df05b94b718153361371ba2f622", "0xb00cc8f257d659c22d30e6d641f79166b1e752ea8606f558e4cad6fc01532e8319ea4ee12265ba4140ac45aa4613c004", "0xac7019af65221b0cc736287b32d7f1a3561405715ba9a6a122342e04e51637ba911c41573de53e4781f2230fdcb2475f", "0x81a630bc41b3da8b3eb4bf56cba10cd9f93153c3667f009dc332287baeb707d505fb537e6233c8e53d299ec0f013290c", "0xa6b7aea5c545bb76df0f230548539db92bc26642572cb7dd3d5a30edca2b4c386f44fc8466f056b42de2a452b81aff5b", "0x8271624ff736b7b238e43943c81de80a1612207d32036d820c11fc830c737972ccc9c60d3c2359922b06652311e3c994", "0x8a684106458cb6f4db478170b9ad595d4b54c18bf63b9058f095a2fa1b928c15101472c70c648873d5887880059ed402", "0xa5cc3c35228122f410184e4326cf61a37637206e589fcd245cb5d0cec91031f8f7586b80503070840fdfd8ce75d3c88b", "0x9443fc631aed8866a7ed220890911057a1f56b0afe0ba15f0a0e295ab97f604b134b1ed9a4245e46ee5f9a93aa74f731", "0x984b6f7d79835dffde9558c6bb912d992ca1180a2361757bdba4a7b69dc74b056e303adc69fe67414495dd9c2dd91e64", "0xb15a5c8cba5de080224c274d31c68ed72d2a7126d347796569aef0c4e97ed084afe3da4d4b590b9dda1a07f0c2ff3dfb", "0x991708fe9650a1f9a4e43938b91d45dc68c230e05ee999c95dbff3bf79b1c1b2bb0e7977de454237c355a73b8438b1d9", "0xb4f7edc7468b176a4a7c0273700c444fa95c726af6697028bed4f77eee887e3400f9c42ee15b782c0ca861c4c3b8c98a", "0x8c60dcc16c51087eb477c13e837031d6c6a3dc2b8bf8cb43c23f48006bc7173151807e866ead2234b460c2de93b31956", "0x83ad63e9c910d1fc44bc114accfb0d4d333b7ebe032f73f62d25d3e172c029d5e34a1c9d547273bf6c0fead5c8801007", "0x85de73213cc236f00777560756bdbf2b16841ba4b55902cf2cad9742ecaf5d28209b012ceb41f337456dfeca93010cd7", "0xa7561f8827ccd75b6686ba5398bb8fc3083351c55a589b18984e186820af7e275af04bcd4c28e1dc11be1e8617a0610b", "0x88c0a4febd4068850557f497ea888035c7fc9f404f6cc7794e7cc8722f048ad2f249e7dc62743e7a339eb7473ad3b0cd", "0x932b22b1d3e6d5a6409c34980d176feb85ada1bf94332ef5c9fc4d42b907dabea608ceef9b5595ef3feee195151f18d8", "0xa2867bb3f5ab88fbdae3a16c9143ab8a8f4f476a2643c505bb9f37e5b1fd34d216cab2204c9a017a5a67b7ad2dda10e8", "0xb573d5f38e4e9e8a3a6fd82f0880dc049efa492a946d00283019bf1d5e5516464cf87039e80aef667cb86fdea5075904", "0xb948f1b5ab755f3f5f36af27d94f503b070696d793b1240c1bdfd2e8e56890d69e6904688b5f8ff5a4bdf5a6abfe195f", "0x917eae95ebc4109a2e99ddd8fec7881d2f7aaa0e25fda44dec7ce37458c2ee832f1829db7d2dcfa4ca0f06381c7fe91d", "0x95751d17ed00a3030bce909333799bb7f4ab641acf585807f355b51d6976dceee410798026a1a004ef4dcdff7ec0f5b8", "0xb9b7bd266f449a79bbfe075e429613e76c5a42ac61f01c8f0bbbd34669650682efe01ff9dbbc400a1e995616af6aa278", "0xac1722d097ce9cd7617161f8ec8c23d68f1fb1c9ca533e2a8b4f78516c2fd8fb38f23f834e2b9a03bb06a9d655693ca9", "0xa7ad9e96ffd98db2ecdb6340c5d592614f3c159abfd832fe27ee9293519d213a578e6246aae51672ee353e3296858873", "0x989b8814d5de7937c4acafd000eec2b4cd58ba395d7b25f98cafd021e8efa37029b29ad8303a1f6867923f5852a220eb", "0xa5bfe6282c771bc9e453e964042d44eff4098decacb89aecd3be662ea5b74506e1357ab26f3527110ba377711f3c9f41", "0x8900a7470b656639721d2abbb7b06af0ac4222ab85a1976386e2a62eb4b88bfb5b72cf7921ddb3cf3a395d7eeb192a2e", "0x95a71b55cd1f35a438cf5e75f8ff11c5ec6a2ebf2e4dba172f50bfad7d6d5dca5de1b1afc541662c81c858f7604c1163", "0x82b5d62fea8db8d85c5bc3a76d68dedd25794cf14d4a7bc368938ffca9e09f7e598fdad2a5aac614e0e52f8112ae62b9", "0x997173f07c729202afcde3028fa7f52cefc90fda2d0c8ac2b58154a5073140683e54c49ed1f254481070d119ce0ce02a", "0xaeffb91ccc7a72bbd6ffe0f9b99c9e66e67d59cec2e02440465e9636a613ab3017278cfa72ea8bc4aba9a8dc728cb367", "0x952743b06e8645894aeb6440fc7a5f62dd3acf96dab70a51e20176762c9751ea5f2ba0b9497ccf0114dc4892dc606031", "0x874c63baeddc56fbbca2ff6031f8634b745f6e34ea6791d7c439201aee8f08ef5ee75f7778700a647f3b21068513fce6", "0x85128fec9c750c1071edfb15586435cc2f317e3e9a175bb8a9697bcda1eb9375478cf25d01e7fed113483b28f625122d", "0x85522c9576fd9763e32af8495ae3928ed7116fb70d4378448926bc9790e8a8d08f98cf47648d7da1b6e40d6a210c7924", "0x97d0f37a13cfb723b848099ca1c14d83e9aaf2f7aeb71829180e664b7968632a08f6a85f557d74b55afe6242f2a36e7c", "0xabaa472d6ad61a5fccd1a57c01aa1bc081253f95abbcba7f73923f1f11c4e79b904263890eeb66926de3e2652f5d1c70", "0xb3c04945ba727a141e5e8aec2bf9aa3772b64d8fd0e2a2b07f3a91106a95cbcb249adcd074cbe498caf76fffac20d4ef", "0x82c46781a3d730d9931bcabd7434a9171372dde57171b6180e5516d4e68db8b23495c8ac3ab96994c17ddb1cf249b9fb", "0xa202d8b65613c42d01738ccd68ed8c2dbc021631f602d53f751966e04182743ebc8e0747d600b8a8676b1da9ae7f11ab", "0xae73e7256e9459db04667a899e0d3ea5255211fb486d084e6550b6dd64ca44af6c6b2d59d7aa152de9f96ce9b58d940d", "0xb67d87b176a9722945ec7593777ee461809861c6cfd1b945dde9ee4ff009ca4f19cf88f4bbb5c80c9cbab2fe25b23ac8", "0x8f0b7a317a076758b0dac79959ee4a06c08b07d0f10538a4b53d3da2eda16e2af26922feb32c090330dc4d969cf69bd3", "0x90b36bf56adbd8c4b6cb32febc3a8d5f714370c2ac3305c10fa6d168dffb2a026804517215f9a2d4ec8310cdb6bb459b", "0xaa80c19b0682ead69934bf18cf476291a0beddd8ef4ed75975d0a472e2ab5c70f119722a8574ae4973aceb733d312e57", "0xa3fc9abb12574e5c28dcb51750b4339b794b8e558675eef7d26126edf1de920c35e992333bcbffcbf6a5f5c0d383ce62", "0xa1573ff23ab972acdcd08818853b111fc757fdd35aa070186d3e11e56b172fb49d840bf297ac0dd222e072fc09f26a81", "0x98306f2be4caa92c2b4392212d0cbf430b409b19ff7d5b899986613bd0e762c909fc01999aa94be3bd529d67f0113d7f", "0x8c1fc42482a0819074241746d17dc89c0304a2acdae8ed91b5009e9e3e70ff725ba063b4a3e68fdce05b74f5180c545e", "0xa6c6113ebf72d8cf3163b2b8d7f3fa24303b13f55752522c660a98cd834d85d8c79214d900fa649499365e2e7641f77a", "0xab95eea424f8a2cfd9fb1c78bb724e5b1d71a0d0d1e4217c5d0f98b0d8bbd3f8400a2002abc0a0e4576d1f93f46fefad", "0x823c5a4fd8cf4a75fdc71d5f2dd511b6c0f189b82affeacd2b7cfcad8ad1a5551227dcc9bfdb2e34b2097eaa00efbb51", "0xb97314dfff36d80c46b53d87a61b0e124dc94018a0bb680c32765b9a2d457f833a7c42bbc90b3b1520c33a182580398d", "0xb17566ee3dcc6bb3b004afe4c0136dfe7dd27df9045ae896dca49fb36987501ae069eb745af81ba3fc19ff037e7b1406", "0xb0bdc0f55cfd98d331e3a0c4fbb776a131936c3c47c6bffdc3aaf7d8c9fa6803fbc122c2fefbb532e634228687d52174", "0xaa5d9e60cc9f0598559c28bb9bdd52aa46605ab4ffe3d192ba982398e72cec9a2a44c0d0d938ce69935693cabc0887ea", "0x802b6459d2354fa1d56c592ac1346c428dadea6b6c0a87bf7d309bab55c94e1cf31dd98a7a86bd92a840dd51f218b91b", "0xa526914efdc190381bf1a73dd33f392ecf01350b9d3f4ae96b1b1c3d1d064721c7d6eec5788162c933245a3943f5ee51", "0xb3b8fcf637d8d6628620a1a99dbe619eabb3e5c7ce930d6efd2197e261bf394b74d4e5c26b96c4b8009c7e523ccfd082", "0x8f7510c732502a93e095aba744535f3928f893f188adc5b16008385fb9e80f695d0435bfc5b91cdad4537e87e9d2551c", "0x97b90beaa56aa936c3ca45698f79273a68dd3ccd0076eab48d2a4db01782665e63f33c25751c1f2e070f4d1a8525bf96", "0xb9fb798324b1d1283fdc3e48288e3861a5449b2ab5e884b34ebb8f740225324af86e4711da6b5cc8361c1db15466602f", "0xb6d52b53cea98f1d1d4c9a759c25bf9d8a50b604b144e4912acbdbdc32aab8b9dbb10d64a29aa33a4f502121a6fb481c", "0x9174ffff0f2930fc228f0e539f5cfd82c9368d26b074467f39c07a774367ff6cccb5039ac63f107677d77706cd431680", "0xa33b6250d4ac9e66ec51c063d1a6a31f253eb29bbaed12a0d67e2eccfffb0f3a52750fbf52a1c2aaba8c7692346426e7", "0xa97025fd5cbcebe8ef865afc39cd3ea707b89d4e765ec817fd021d6438e02fa51e3544b1fd45470c58007a08efac6edd", "0xb32a78480edd9ff6ba2f1eec4088db5d6ceb2d62d7e59e904ecaef7bb4a2e983a4588e51692b3be76e6ffbc0b5f911a5", "0xb5ab590ef0bb77191f00495b33d11c53c65a819f7d0c1f9dc4a2caa147a69c77a4fff7366a602d743ee1f395ce934c1e", "0xb3fb0842f9441fb1d0ee0293b6efbc70a8f58d12d6f769b12872db726b19e16f0f65efbc891cf27a28a248b0ef9c7e75", "0x9372ad12856fefb928ccb0d34e198df99e2f8973b07e9d417a3134d5f69e12e79ff572c4e03ccd65415d70639bc7c73e", "0xaa8d6e83d09ce216bfe2009a6b07d0110d98cf305364d5529c170a23e693aabb768b2016befb5ada8dabdd92b4d012bb", "0xa954a75791eeb0ce41c85200c3763a508ed8214b5945a42c79bfdcfb1ec4f86ad1dd7b2862474a368d4ac31911a2b718", "0x8e2081cfd1d062fe3ab4dab01f68062bac802795545fede9a188f6c9f802cb5f884e60dbe866710baadbf55dc77c11a4", "0xa2f06003b9713e7dd5929501ed485436b49d43de80ea5b15170763fd6346badf8da6de8261828913ee0dacd8ff23c0e1", "0x98eecc34b838e6ffd1931ca65eec27bcdb2fdcb61f33e7e5673a93028c5865e0d1bf6d3bec040c5e96f9bd08089a53a4", "0x88cc16019741b341060b95498747db4377100d2a5bf0a5f516f7dec71b62bcb6e779de2c269c946d39040e03b3ae12b7", "0xad1135ccbc3019d5b2faf59a688eef2500697642be8cfbdf211a1ab59abcc1f24483e50d653b55ff1834675ac7b4978f", "0xa946f05ed9972f71dfde0020bbb086020fa35b482cce8a4cc36dd94355b2d10497d7f2580541bb3e81b71ac8bba3c49f", "0xa83aeed488f9a19d8cfd743aa9aa1982ab3723560b1cd337fc2f91ad82f07afa412b3993afb845f68d47e91ba4869840", "0x95eebe006bfc316810cb71da919e5d62c2cebb4ac99d8e8ef67be420302320465f8b69873470982de13a7c2e23516be9", "0xa55f8961295a11e91d1e5deadc0c06c15dacbfc67f04ccba1d069cba89d72aa3b3d64045579c3ea8991b150ac29366ae", "0xb321991d12f6ac07a5de3c492841d1a27b0d3446082fbce93e7e1f9e8d8fe3b45d41253556261c21b70f5e189e1a7a6f", "0xa0b0822f15f652ce7962a4f130104b97bf9529797c13d6bd8e24701c213cc37f18157bd07f3d0f3eae6b7cd1cb40401f", "0x96e2fa4da378aa782cc2d5e6e465fc9e49b5c805ed01d560e9b98abb5c0de8b74a2e7bec3aa5e2887d25cccb12c66f0c", "0x97e4ab610d414f9210ed6f35300285eb3ccff5b0b6a95ed33425100d7725e159708ea78704497624ca0a2dcabce3a2f9", "0x960a375b17bdb325761e01e88a3ea57026b2393e1d887b34b8fa5d2532928079ce88dc9fd06a728b26d2bb41b12b9032", "0x8328a1647398e832aadc05bd717487a2b6fcdaa0d4850d2c4da230c6a2ed44c3e78ec4837b6094f3813f1ee99414713f", "0xaa283834ebd18e6c99229ce4b401eda83f01d904f250fedd4e24f1006f8fa0712a6a89a7296a9bf2ce8de30e28d1408e", "0xb29e097f2caadae3e0f0ae3473c072b0cd0206cf6d2e9b22c1a5ad3e07d433e32bd09ed1f4e4276a2da4268633357b7f", "0x9539c5cbba14538b2fe077ecf67694ef240da5249950baaabea0340718b882a966f66d97f08556b08a4320ceb2cc2629", "0xb4529f25e9b42ae8cf8338d2eface6ba5cd4b4d8da73af502d081388135c654c0b3afb3aa779ffc80b8c4c8f4425dd2b", "0x95be0739c4330619fbe7ee2249c133c91d6c07eab846c18c5d6c85fc21ac5528c5d56dcb0145af68ed0c6a79f68f2ccd", "0xac0c83ea802227bfc23814a24655c9ff13f729619bcffdb487ccbbf029b8eaee709f8bddb98232ef33cd70e30e45ca47", "0xb503becb90acc93b1901e939059f93e671900ca52c6f64ae701d11ac891d3a050b505d89324ce267bc43ab8275da6ffe", "0x98e3811b55b1bacb70aa409100abb1b870f67e6d059475d9f278c751b6e1e2e2d6f2e586c81a9fb6597fda06e7923274", "0xb0b0f61a44053fa6c715dbb0731e35d48dba257d134f851ee1b81fd49a5c51a90ebf5459ec6e489fce25da4f184fbdb1", "0xb1d2117fe811720bb997c7c93fe9e4260dc50fca8881b245b5e34f724aaf37ed970cdad4e8fcb68e05ac8cf55a274a53", "0xa10f502051968f14b02895393271776dee7a06db9de14effa0b3471825ba94c3f805302bdddac4d397d08456f620999d", "0xa3dbad2ef060ae0bb7b02eaa4a13594f3f900450faa1854fc09620b01ac94ab896321dfb1157cf2374c27e5718e8026a", "0xb550fdec503195ecb9e079dcdf0cad559d64d3c30818ef369b4907e813e689da316a74ad2422e391b4a8c2a2bef25fc0", "0xa25ba865e2ac8f28186cea497294c8649a201732ecb4620c4e77b8e887403119910423df061117e5f03fc5ba39042db1", "0xb3f88174e03fdb443dd6addd01303cf88a4369352520187c739fc5ae6b22fa99629c63c985b4383219dab6acc5f6f532", "0x97a7503248e31e81b10eb621ba8f5210c537ad11b539c96dfb7cf72b846c7fe81bd7532c5136095652a9618000b7f8d3", "0xa8bcdc1ce5aa8bfa683a2fc65c1e79de8ff5446695dcb8620f7350c26d2972a23da22889f9e2b1cacb3f688c6a2953dc", "0x8458c111df2a37f5dd91a9bee6c6f4b79f4f161c93fe78075b24a35f9817da8dde71763218d627917a9f1f0c4709c1ed", "0xac5f061a0541152b876cbc10640f26f1cc923c9d4ae1b6621e4bb3bf2cec59bbf87363a4eb72fb0e5b6d4e1c269b52d5", "0xa9a25ca87006e8a9203cbb78a93f50a36694aa4aad468b8d80d3feff9194455ca559fcc63838128a0ab75ad78c07c13a", "0xa450b85f5dfffa8b34dfd8bc985f921318efacf8857cf7948f93884ba09fb831482ee90a44224b1a41e859e19b74962f", "0x8ed91e7f92f5c6d7a71708b6132f157ac226ecaf8662af7d7468a4fa25627302efe31e4620ad28719318923e3a59bf82", "0xab524165fd4c71b1fd395467a14272bd2b568592deafa039d8492e9ef36c6d3f96927c95c72d410a768dc0b6d1fbbc9b", "0xb662144505aa8432c75ffb8d10318526b6d5777ac7af9ebfad87d9b0866c364f7905a6352743bd8fd79ffd9d5dd4f3e6", "0xa48f1677550a5cd40663bb3ba8f84caaf8454f332d0ceb1d94dbea52d0412fe69c94997f7749929712fd3995298572f7", "0x8391cd6e2f6b0c242de1117a612be99776c3dc95cb800b187685ea5bf7e2722275eddb79fd7dfc8be8e389c4524cdf70", "0x875d3acb9af47833b72900bc0a2448999d638f153c5e97e8a14ec02d0c76f6264353a7e275e1f1a5855daced523d243b", "0x91f1823657d30b59b2f627880a9a9cb530f5aca28a9fd217fe6f2f5133690dfe7ad5a897872e400512db2e788b3f7628", "0xad3564332aa56cea84123fc7ca79ea70bb4fef2009fa131cb44e4b15e8613bd11ca1d83b9d9bf456e4b7fee9f2e8b017", "0x8c530b84001936d5ab366c84c0b105241a26d1fb163669f17c8f2e94776895c2870edf3e1bc8ccd04d5e65531471f695", "0x932d01fa174fdb0c366f1230cffde2571cc47485f37f23ba5a1825532190cc3b722aeb1f15aed62cf83ccae9403ba713", "0x88b28c20585aca50d10752e84b901b5c2d58efef5131479fbbe53de7bce2029e1423a494c0298e1497669bd55be97a5d", "0xb914148ca717721144ebb3d3bf3fcea2cd44c30c5f7051b89d8001502f3856fef30ec167174d5b76265b55d70f8716b5", "0x81d0173821c6ddd2a068d70766d9103d1ee961c475156e0cbd67d54e668a796310474ef698c7ab55abe6f2cf76c14679", "0x8f28e8d78e2fe7fa66340c53718e0db4b84823c8cfb159c76eac032a62fb53da0a5d7e24ca656cf9d2a890cb2a216542", "0x8a26360335c73d1ab51cec3166c3cf23b9ea51e44a0ad631b0b0329ef55aaae555420348a544e18d5760969281759b61", "0x94f326a32ed287545b0515be9e08149eb0a565025074796d72387cc3a237e87979776410d78339e23ef3172ca43b2544", "0xa785d2961a2fa5e70bffa137858a92c48fe749fee91b02599a252b0cd50d311991a08efd7fa5e96b78d07e6e66ffe746", "0x94af9030b5ac792dd1ce517eaadcec1482206848bea4e09e55cc7f40fd64d4c2b3e9197027c5636b70d6122c51d2235d", "0x9722869f7d1a3992850fe7be405ec93aa17dc4d35e9e257d2e469f46d2c5a59dbd504056c85ab83d541ad8c13e8bcd54", "0xb13c4088b61a06e2c03ac9813a75ff1f68ffdfee9df6a8f65095179a475e29cc49119cad2ce05862c3b1ac217f3aace9", "0x8c64d51774753623666b10ca1b0fe63ae42f82ed6aa26b81dc1d48c86937c5772eb1402624c52a154b86031854e1fb9f", "0xb47e4df18002b7dac3fee945bf9c0503159e1b8aafcce2138818e140753011b6d09ef1b20894e08ba3006b093559061b", "0x93cb5970076522c5a0483693f6a35ffd4ea2aa7aaf3730c4eccd6af6d1bebfc1122fc4c67d53898ae13eb6db647be7e2", "0xa68873ef80986795ea5ed1a597d1cd99ed978ec25e0abb57fdcc96e89ef0f50aeb779ff46e3dce21dc83ada3157a8498", "0x8cab67f50949cc8eee6710e27358aea373aae3c92849f8f0b5531c080a6300cdf2c2094fe6fecfef6148de0d28446919", "0x993e932bcb616dbaa7ad18a4439e0565211d31071ef1b85a0627db74a05d978c60d507695eaeea5c7bd9868a21d06923", "0xacdadff26e3132d9478a818ef770e9fa0d2b56c6f5f48bd3bd674436ccce9bdfc34db884a73a30c04c5f5e9764cb2218", "0xa0d3e64c9c71f84c0eef9d7a9cb4fa184224b969db5514d678e93e00f98b41595588ca802643ea225512a4a272f5f534", "0x91c9140c9e1ba6e330cb08f6b2ce4809cd0d5a0f0516f70032bf30e912b0ed684d07b413b326ab531ee7e5b4668c799b", "0x87bc2ee7a0c21ba8334cd098e35cb703f9af57f35e091b8151b9b63c3a5b0f89bd7701dbd44f644ea475901fa6d9ef08", "0x9325ccbf64bf5d71b303e31ee85d486298f9802c5e55b2c3d75427097bf8f60fa2ab4fcaffa9b60bf922c3e24fbd4b19", "0x95d0506e898318f3dc8d28d16dfd9f0038b54798838b3c9be2a2ae3c2bf204eb496166353fc042220b0bd4f6673b9285", "0x811de529416331fe9c416726d45df9434c29dcd7e949045eb15740f47e97dde8f31489242200e19922cac2a8b7c6fd1f", "0xade632d04a4c8bbab6ca7df370b2213cb9225023e7973f0e29f4f5e52e8aeaabc65171306bbdd12a67b195dfbb96d48f", "0x88b7f029e079b6ae956042c0ea75d53088c5d0efd750dd018adaeacf46be21bf990897c58578c491f41afd3978d08073", "0x91f477802de507ffd2be3f4319903119225b277ad24f74eb50f28b66c14d32fae53c7edb8c7590704741af7f7f3e3654", "0x809838b32bb4f4d0237e98108320d4b079ee16ed80c567e7548bd37e4d7915b1192880f4812ac0e00476d246aec1dbc8", "0x84183b5fc4a7997a8ae5afedb4d21dce69c480d5966b5cbdafd6dd10d29a9a6377f3b90ce44da0eb8b176ac3af0253bb", "0x8508abbf6d3739a16b9165caf0f95afb3b3ac1b8c38d6d374cf0c91296e2c1809a99772492b539cda184510bce8a0271", "0x8722054e59bab2062e6419a6e45fc803af77fde912ef2cd23055ad0484963de65a816a2debe1693d93c18218d2b8e81a", "0x8e895f80e485a7c4f56827bf53d34b956281cdc74856c21eb3b51f6288c01cc3d08565a11cc6f3e2604775885490e8c5", "0xafc92714771b7aa6e60f3aee12efd9c2595e9659797452f0c1e99519f67c8bc3ac567119c1ddfe82a3e961ee9defea9a", "0x818ff0fd9cefd32db87b259e5fa32967201016fc02ef44116cdca3c63ce5e637756f60477a408709928444a8ad69c471", "0x8251e29af4c61ae806fc5d032347fb332a94d472038149225298389495139ce5678fae739d02dfe53a231598a992e728", "0xa0ea39574b26643f6f1f48f99f276a8a64b5481989cfb2936f9432a3f8ef5075abfe5c067dc5512143ce8bf933984097", "0xaf67a73911b372bf04e57e21f289fc6c3dfac366c6a01409b6e76fea4769bdb07a6940e52e8d7d3078f235c6d2f632c6", "0xb5291484ef336024dd2b9b4cf4d3a6b751133a40656d0a0825bcc6d41c21b1c79cb50b0e8f4693f90c29c8f4358641f9", "0x8bc0d9754d70f2cb9c63f991902165a87c6535a763d5eece43143b5064ae0bcdce7c7a8f398f2c1c29167b2d5a3e6867", "0x8d7faff53579ec8f6c92f661c399614cc35276971752ce0623270f88be937c414eddcb0997e14724a783905a026c8883", "0x9310b5f6e675fdf60796f814dbaa5a6e7e9029a61c395761e330d9348a7efab992e4e115c8be3a43d08e90d21290c892", "0xb5eb4f3eb646038ad2a020f0a42202532d4932e766da82b2c1002bf9c9c2e5336b54c8c0ffcc0e02d19dde2e6a35b6cc", "0x91dabfd30a66710f1f37a891136c9be1e23af4abf8cb751f512a40c022a35f8e0a4fb05b17ec36d4208de02d56f0d53a", "0xb3ded14e82d62ac7a5a036122a62f00ff8308498f3feae57d861babaff5a6628d43f0a0c5fc903f10936bcf4e2758ceb", "0xa88e8348fed2b26acca6784d19ef27c75963450d99651d11a950ea81d4b93acd2c43e0ecce100eaf7e78508263d5baf3", "0xb1f5bbf7c4756877b87bb42163ac570e08c6667c4528bf68b5976680e19beeff7c5effd17009b0718797077e2955457a", "0xad2e7b516243f915d4d1415326e98b1a7390ae88897d0b03b66c2d9bd8c3fba283d7e8fe44ed3333296a736454cef6d8", "0x8f82eae096d5b11f995de6724a9af895f5e1c58d593845ad16ce8fcae8507e0d8e2b2348a0f50a1f66a17fd6fac51a5c", "0x890e4404d0657c6c1ee14e1aac132ecf7a568bb3e04137b85ac0f84f1d333bd94993e8750f88eee033a33fb00f85dcc7", "0x82ac7d3385e035115f1d39a99fc73e5919de44f5e6424579776d118d711c8120b8e5916372c6f27bed4cc64cac170b6c", "0x85ee16d8901c272cfbbe966e724b7a891c1bd5e68efd5d863043ad8520fc409080af61fd726adc680b3f1186fe0ac8b8", "0x86dc564c9b545567483b43a38f24c41c6551a49cabeebb58ce86404662a12dbfafd0778d30d26e1c93ce222e547e3898", "0xa29f5b4522db26d88f5f95f18d459f8feefab02e380c2edb65aa0617a82a3c1a89474727a951cef5f15050bcf7b380fb", "0xa1ce039c8f6cac53352899edb0e3a72c76da143564ad1a44858bd7ee88552e2fe6858d1593bbd74aeee5a6f8034b9b9d", "0x97f10d77983f088286bd7ef3e7fdd8fa275a56bec19919adf33cf939a90c8f2967d2b1b6fc51195cb45ad561202a3ed7", "0xa25e2772e8c911aaf8712bdac1dd40ee061c84d3d224c466cfaae8e5c99604053f940cde259bd1c3b8b69595781dbfec", "0xb31bb95a0388595149409c48781174c340960d59032ab2b47689911d03c68f77a2273576fbe0c2bf4553e330656058c7", "0xb8b2e9287ad803fb185a13f0d7456b397d4e3c8ad5078f57f49e8beb2e85f661356a3392dbd7bcf6a900baa5582b86a1", "0xa3d0893923455eb6e96cc414341cac33d2dbc88fba821ac672708cce131761d85a0e08286663a32828244febfcae6451", "0x82310cb42f647d99a136014a9f881eb0b9791efd2e01fc1841907ad3fc8a9654d3d1dab6689c3607214b4dc2aca01cee", "0x874022d99c16f60c22de1b094532a0bc6d4de700ad01a31798fac1d5088b9a42ad02bef8a7339af7ed9c0d4f16b186ee", "0x94981369e120265aed40910eebc37eded481e90f4596b8d57c3bec790ab7f929784bd33ddd05b7870aad6c02e869603b", "0xa4f1f50e1e2a73f07095e0dd31cb45154f24968dae967e38962341c1241bcd473102fff1ff668b20c6547e9732d11701", "0xae2328f3b0ad79fcda807e69a1b5278145225083f150f67511dafc97e079f860c3392675f1752ae7e864c056e592205b", "0x875d8c971e593ca79552c43d55c8c73b17cd20c81ff2c2fed1eb19b1b91e4a3a83d32df150dbfd5db1092d0aebde1e1f", "0xadd2e80aa46aae95da73a11f130f4bda339db028e24c9b11e5316e75ba5e63bc991d2a1da172c7c8e8fee038baae3433", "0xb46dbe1cb3424002aa7de51e82f600852248e251465c440695d52538d3f36828ff46c90ed77fc1d11534fe3c487df8ef", "0xa5e5045d28b4e83d0055863c30c056628c58d4657e6176fd0536f5933f723d60e851bb726d5bf3c546b8ce4ac4a57ef8", "0x91fec01e86dd1537e498fff7536ea3ca012058b145f29d9ada49370cd7b7193ac380e116989515df1b94b74a55c45df3", "0xa7428176d6918cd916a310bdc75483c72de660df48cac4e6e7478eef03205f1827ea55afc0df5d5fa7567d14bbea7fc9", "0x851d89bef45d9761fe5fdb62972209335193610015e16a675149519f9911373bac0919add226ef118d9f3669cfdf4734", "0xb74acf5c149d0042021cb2422ea022be4c4f72a77855f42393e71ffd12ebb3eec16bdf16f812159b67b79a9706e7156d", "0x99f35dce64ec99aa595e7894b55ce7b5a435851b396e79036ffb249c28206087db4c85379df666c4d95857db02e21ff9", "0xb6b9a384f70db9e298415b8ab394ee625dafff04be2886476e59df8d052ca832d11ac68a9b93fba7ab055b7bc36948a4", "0x898ee4aefa923ffec9e79f2219c7389663eb11eb5b49014e04ed4a336399f6ea1691051d86991f4c46ca65bcd4fdf359", "0xb0f948217b0d65df7599a0ba4654a5e43c84db477936276e6f11c8981efc6eaf14c90d3650107ed4c09af4cc8ec11137", "0xaa6286e27ac54f73e63dbf6f41865dd94d24bc0cf732262fcaff67319d162bb43af909f6f8ee27b1971939cfbba08141", "0x8bca7cdf730cf56c7b2c8a2c4879d61361a6e1dba5a3681a1a16c17a56e168ace0e99cf0d15826a1f5e67e6b8a8a049a", "0xa746d876e8b1ce225fcafca603b099b36504846961526589af977a88c60d31ba2cc56e66a3dec8a77b3f3531bf7524c9", "0xa11e2e1927e6704cdb8874c75e4f1842cef84d7d43d7a38e339e61dc8ba90e61bbb20dd3c12e0b11d2471d58eed245be", "0xa36395e22bc1d1ba8b0459a235203177737397da5643ce54ded3459d0869ff6d8d89f50c73cb62394bf66a959cde9b90", "0x8b49f12ba2fdf9aca7e5f81d45c07d47f9302a2655610e7634d1e4bd16048381a45ef2c95a8dd5b0715e4b7cf42273af", "0x91cffa2a17e64eb7f76bccbe4e87280ee1dd244e04a3c9eac12e15d2d04845d876eb24fe2ec6d6d266cce9efb281077f", "0xa6b8afabf65f2dee01788114e33a2f3ce25376fb47a50b74da7c3c25ff1fdc8aa9f41307534abbf48acb6f7466068f69", "0x8d13db896ccfea403bd6441191995c1a65365cab7d0b97fbe9526da3f45a877bd1f4ef2edef160e8a56838cd1586330e", "0x98c717de9e01bef8842c162a5e757fe8552d53269c84862f4d451e7c656ae6f2ae473767b04290b134773f63be6fdb9d", "0x8c2036ace1920bd13cf018e82848c49eb511fad65fd0ff51f4e4b50cf3bfc294afb63cba682c16f52fb595a98fa84970", "0xa3520fdff05dbad9e12551b0896922e375f9e5589368bcb2cc303bde252743b74460cb5caf99629325d3620f13adc796", "0x8d4f83a5bfec05caf5910e0ce538ee9816ee18d0bd44c1d0da2a87715a23cd2733ad4d47552c6dc0eb397687d611dd19", "0xa7b39a0a6a02823452d376533f39d35029867b3c9a6ad6bca181f18c54132d675613a700f9db2440fb1b4fa13c8bf18a", "0x80bcb114b2544b80f404a200fc36860ed5e1ad31fe551acd4661d09730c452831751baa9b19d7d311600d267086a70bc", "0x90dcce03c6f88fc2b08f2b42771eedde90cc5330fe0336e46c1a7d1b5a6c1641e5fcc4e7b3d5db00bd8afca9ec66ed81", "0xaec15f40805065c98e2965b1ae12a6c9020cfdb094c2d0549acfc7ea2401a5fb48d3ea7d41133cf37c4e096e7ff53eb9", "0x80e129b735dba49fa627a615d6c273119acec8e219b2f2c4373a332b5f98d66cbbdd688dfbe72a8f8bfefaccc02c50c1", "0xa9b596da3bdfe23e6799ece5f7975bf7a1979a75f4f546deeaf8b34dfe3e0d623217cb4cf4ccd504cfa3625b88cd53f1", "0xabcbbb70b16f6e517c0ab4363ab76b46e4ff58576b5f8340e5c0e8cc0e02621b6e23d742d73b015822a238b17cfd7665", "0xa046937cc6ea6a2e1adae543353a9fe929c1ae4ad655be1cc051378482cf88b041e28b1e9a577e6ccff2d3570f55e200", "0x831279437282f315e65a60184ef158f0a3dddc15a648dc552bdc88b3e6fe8288d3cfe9f0031846d81350f5e7874b4b33", "0x993d7916fa213c6d66e7c4cafafc1eaec9a2a86981f91c31eb8a69c5df076c789cbf498a24c84e0ee77af95b42145026", "0x823907a3b6719f8d49b3a4b7c181bd9bb29fcf842d7c70660c4f351852a1e197ca46cf5e879b47fa55f616fa2b87ce5e", "0x8d228244e26132b234930ee14c75d88df0943cdb9c276a8faf167d259b7efc1beec2a87c112a6c608ad1600a239e9aae", "0xab6e55766e5bfb0cf0764ed909a8473ab5047d3388b4f46faeba2d1425c4754c55c6daf6ad4751e634c618b53e549529", "0xab0cab6860e55a84c5ad2948a7e0989e2b4b1fd637605634b118361497332df32d9549cb854b2327ca54f2bcb85eed8f", "0xb086b349ae03ef34f4b25a57bcaa5d1b29bd94f9ebf87e22be475adfe475c51a1230c1ebe13506cb72c4186192451658", "0x8a0b49d8a254ca6d91500f449cbbfbb69bb516c6948ac06808c65595e46773e346f97a5ce0ef7e5a5e0de278af22709c", "0xac49de11edaaf04302c73c578cc0824bdd165c0d6321be1c421c1950e68e4f3589aa3995448c9699e93c6ebae8803e27", "0x884f02d841cb5d8f4c60d1402469216b114ab4e93550b5bc1431756e365c4f870a9853449285384a6fa49e12ce6dc654", "0xb75f3a28fa2cc8d36b49130cb7448a23d73a7311d0185ba803ad55c8219741d451c110f48b786e96c728bc525903a54f", "0x80ae04dbd41f4a35e33f9de413b6ad518af0919e5a30cb0fa1b061b260420780bb674f828d37fd3b52b5a31673cbd803", "0xb9a8011eb5fcea766907029bf743b45262db3e49d24f84503687e838651ed11cb64c66281e20a0ae9f6aa51acc552263", "0x90bfdd75e2dc9cf013e22a5d55d2d2b8a754c96103a17524488e01206e67f8b6d52b1be8c4e3d5307d4fe06d0e51f54c", "0xb4af353a19b06203a815ec43e79a88578cc678c46f5a954b85bc5c53b84059dddba731f3d463c23bfd5273885c7c56a4", "0xaa125e96d4553b64f7140e5453ff5d2330318b69d74d37d283e84c26ad672fa00e3f71e530eb7e28be1e94afb9c4612e", "0xa18e060aee3d49cde2389b10888696436bb7949a79ca7d728be6456a356ea5541b55492b2138da90108bd1ce0e6f5524", "0x93e55f92bdbccc2de655d14b1526836ea2e52dba65eb3f87823dd458a4cb5079bf22ce6ef625cb6d6bfdd0995ab9a874", "0x89f5a683526b90c1c3ceebbb8dc824b21cff851ce3531b164f6626e326d98b27d3e1d50982e507d84a99b1e04e86a915", "0x83d1c38800361633a3f742b1cb2bfc528129496e80232611682ddbe403e92c2ac5373aea0bca93ecb5128b0b2b7a719e", "0x8ecba560ac94905e19ce8d9c7af217bf0a145d8c8bd38e2db82f5e94cc3f2f26f55819176376b51f154b4aab22056059", "0xa7e2a4a002b60291924850642e703232994acb4cfb90f07c94d1e0ecd2257bb583443283c20fc6017c37e6bfe85b7366", "0x93ed7316fa50b528f1636fc6507683a672f4f4403e55e94663f91221cc198199595bd02eef43d609f451acc9d9b36a24", "0xa1220a8ebc5c50ceed76a74bc3b7e0aa77f6884c71b64b67c4310ac29ce5526cb8992d6abc13ef6c8413ce62486a6795", "0xb2f6eac5c869ad7f4a25161d3347093e2f70e66cd925032747e901189355022fab3038bca4d610d2f68feb7e719c110b", "0xb703fa11a4d511ca01c7462979a94acb40b5d933759199af42670eb48f83df202fa0c943f6ab3b4e1cc54673ea3aab1e", "0xb5422912afbfcb901f84791b04f1ddb3c3fbdc76d961ee2a00c5c320e06d3cc5b5909c3bb805df66c5f10c47a292b13d", "0xad0934368da823302e1ac08e3ede74b05dfdbfffca203e97ffb0282c226814b65c142e6e15ec1e754518f221f01b30f7", "0xa1dd302a02e37df15bf2f1147efe0e3c06933a5a767d2d030e1132f5c3ce6b98e216b6145eb39e1e2f74e76a83165b8d", "0xa346aab07564432f802ae44738049a36f7ca4056df2d8f110dbe7fef4a3e047684dea609b2d03dc6bf917c9c2a47608f", "0xb96c5f682a5f5d02123568e50f5d0d186e4b2c4c9b956ec7aabac1b3e4a766d78d19bd111adb5176b898e916e49be2aa", "0x8a96676d56876fc85538db2e806e1cba20fd01aeb9fa3cb43ca6ca94a2c102639f65660db330e5d74a029bb72d6a0b39", "0xab0048336bd5c3def1a4064eadd49e66480c1f2abb4df46e03afbd8a3342c2c9d74ee35d79f08f4768c1646681440984", "0x888427bdf76caec90814c57ee1c3210a97d107dd88f7256f14f883ad0f392334b82be11e36dd8bfec2b37935177c7831", "0xb622b282becf0094a1916fa658429a5292ba30fb48a4c8066ce1ddcefb71037948262a01c95bab6929ed3a76ba5db9fe", "0xb5b9e005c1f456b6a368a3097634fb455723abe95433a186e8278dceb79d4ca2fbe21f8002e80027b3c531e5bf494629", "0xa3c6707117a1e48697ed41062897f55d8119403eea6c2ee88f60180f6526f45172664bfee96bf61d6ec0b7fbae6aa058", "0xb02a9567386a4fbbdb772d8a27057b0be210447348efe6feb935ceec81f361ed2c0c211e54787dc617cdffed6b4a6652", "0xa9b8364e40ef15c3b5902e5534998997b8493064fa2bea99600def58279bb0f64574c09ba11e9f6f669a8354dd79dc85", "0x9998a2e553a9aa9a206518fae2bc8b90329ee59ab23005b10972712389f2ec0ee746033c733092ffe43d73d33abbb8ef", "0x843a4b34d9039bf79df96d79f2d15e8d755affb4d83d61872daf540b68c0a3888cf8fc00d5b8b247b38524bcb3b5a856", "0x84f7128920c1b0bb40eee95701d30e6fc3a83b7bb3709f16d97e72acbb6057004ee7ac8e8f575936ca9dcb7866ab45f7", "0x918d3e2222e10e05edb34728162a899ad5ada0aaa491aeb7c81572a9c0d506e31d5390e1803a91ff3bd8e2bb15d47f31", "0x9442d18e2489613a7d47bb1cb803c8d6f3259d088cd079460976d87f7905ee07dea8f371b2537f6e1d792d36d7e42723", "0xb491976970fe091995b2ed86d629126523ccf3e9daf8145302faca71b5a71a5da92e0e05b62d7139d3efac5c4e367584", "0xaa628006235dc77c14cef4c04a308d66b07ac92d377df3de1a2e6ecfe3144f2219ad6d7795e671e1cb37a3641910b940", "0x99d386adaea5d4981d7306feecac9a555b74ffdc218c907c5aa7ac04abaead0ec2a8237300d42a3fbc464673e417ceed", "0x8f78e8b1556f9d739648ea3cab9606f8328b52877fe72f9305545a73b74d49884044ba9c1f1c6db7d9b7c7b7c661caba", "0x8fb357ae49932d0babdf74fc7aa7464a65d3b6a2b3acf4f550b99601d3c0215900cfd67f2b6651ef94cfc323bac79fae", "0x9906f2fa25c0290775aa001fb6198113d53804262454ae8b83ef371b5271bde189c0460a645829cb6c59f9ee3a55ce4d", "0x8f4379b3ebb50e052325b27655ca6a82e6f00b87bf0d2b680d205dd2c7afdc9ff32a9047ae71a1cdf0d0ce6b9474d878", "0xa85534e88c2bd43c043792eaa75e50914b21741a566635e0e107ae857aed0412035f7576cf04488ade16fd3f35fdbb87", "0xb4ce93199966d3c23251ca7f28ec5af7efea1763d376b0385352ffb2e0a462ef95c69940950278cf0e3dafd638b7bd36", "0xb10cb3d0317dd570aa73129f4acf63c256816f007607c19b423fb42f65133ce21f2f517e0afb41a5378cccf893ae14d0", "0xa9b231c9f739f7f914e5d943ed9bff7eba9e2c333fbd7c34eb1648a362ee01a01af6e2f7c35c9fe962b11152cddf35de", "0x99ff6a899e156732937fb81c0cced80ae13d2d44c40ba99ac183aa246103b31ec084594b1b7feb96da58f4be2dd5c0ed", "0x8748d15d18b75ff2596f50d6a9c4ce82f61ecbcee123a6ceae0e43cab3012a29b6f83cf67b48c22f6f9d757c6caf76b2", "0xb88ab05e4248b7fb634cf640a4e6a945d13e331237410f7217d3d17e3e384ddd48897e7a91e4516f1b9cbd30f35f238b", "0x8d826deaeeb84a3b2d2c04c2300ca592501f992810582d6ae993e0d52f6283a839dba66c6c72278cff5871802b71173b", "0xb36fed027c2f05a5ef625ca00b0364b930901e9e4420975b111858d0941f60e205546474bb25d6bfa6928d37305ae95f", "0xaf2fcfc6b87967567e8b8a13a4ed914478185705724e56ce68fb2df6d1576a0cf34a61e880997a0d35dc2c3276ff7501", "0xac351b919cd1fbf106feb8af2c67692bfcddc84762d18cea681cfa7470a5644839caace27efee5f38c87d3df306f4211", "0x8d6665fb1d4d8d1fa23bd9b8a86e043b8555663519caac214d1e3e3effbc6bee7f2bcf21e645f77de0ced279d69a8a8b", "0xa9fc1c2061756b2a1a169c1b149f212ff7f0d2488acd1c5a0197eba793cffa593fc6d1d1b40718aa75ca3ec77eff10e1", "0xaff64f0fa009c7a6cf0b8d7a22ddb2c8170c3cb3eec082e60d5aadb00b0040443be8936d728d99581e33c22178c41c87", "0x82e0b181adc5e3b1c87ff8598447260e839d53debfae941ebea38265575546c3a74a14b4325a030833a62ff6c52d9365", "0xb7ad43cbb22f6f892c2a1548a41dc120ab1f4e1b8dea0cb6272dd9cb02054c542ecabc582f7e16de709d48f5166cae86", "0x985e0c61094281532c4afb788ecb2dfcba998e974b5d4257a22040a161883908cdd068fe80f8eb49b8953cfd11acf43a", "0xae46895c6d67ea6d469b6c9c07b9e5d295d9ae73b22e30da4ba2c973ba83a130d7eef39717ec9d0f36e81d56bf742671", "0x8600177ea1f7e7ef90514b38b219a37dedfc39cb83297e4c7a5b479817ef56479d48cf6314820960c751183f6edf8b0e", "0xb9208ec1c1d7a1e99b59c62d3e4e61dfb706b0e940d09d3abfc3454c19749083260614d89cfd7e822596c3cdbcc6bb95", "0xa1e94042c796c2b48bc724352d2e9f3a22291d9a34705993357ddb6adabd76da6fc25dac200a8cb0b5bbd99ecddb7af6", "0xb29c3adedd0bcad8a930625bc4dfdc3552a9afd5ca6dd9c0d758f978068c7982b50b711aa0eb5b97f2b84ee784637835", "0xaf0632a238bb1f413c7ea8e9b4c3d68f2827bd2e38cd56024391fba6446ac5d19a780d0cfd4a78fe497d537b766a591a", "0xaaf6e7f7d54f8ef5e2e45dd59774ecbeecf8683aa70483b2a75be6a6071b5981bbaf1627512a65d212817acdfab2e428", "0x8c751496065da2e927cf492aa5ca9013b24f861d5e6c24b30bbf52ec5aaf1905f40f9a28175faef283dd4ed4f2182a09", "0x8952377d8e80a85cf67d6b45499f3bad5fd452ea7bcd99efc1b066c4720d8e5bff1214cea90fd1f972a7f0baac3d29be", "0xa1946ee543d1a6e21f380453be4d446e4130950c5fc3d075794eb8260f6f52d0a795c1ff91d028a648dc1ce7d9ab6b47", "0x89f3fefe37af31e0c17533d2ca1ce0884cc1dc97c15cbfab9c331b8debd94781c9396abef4bb2f163d09277a08d6adf0", "0xa2753f1e6e1a154fb117100a5bd9052137add85961f8158830ac20541ab12227d83887d10acf7fd36dcaf7c2596d8d23", "0x814955b4198933ee11c3883863b06ff98c7eceb21fc3e09df5f916107827ccf3323141983e74b025f46ae00284c9513b", "0x8cc5c6bb429073bfef47cae7b3bfccb0ffa076514d91a1862c6bda4d581e0df87db53cc6c130bf8a7826304960f5a34e", "0x909f22c1f1cdc87f7be7439c831a73484a49acbf8f23d47087d7cf867c64ef61da3bde85dc57d705682b4c3fc710d36e", "0x8048fee7f276fcd504aed91284f28e73693615e0eb3858fa44bcf79d7285a9001c373b3ef71d9a3054817ba293ebe28c", "0x94400e5cf5d2700ca608c5fe35ce14623f71cc24959f2bc27ca3684092850f76b67fb1f07ca9e5b2ca3062cf8ad17bd4", "0x81c2ae7d4d1b17f8b6de6a0430acc0d58260993980fe48dc2129c4948269cdc74f9dbfbf9c26b19360823fd913083d48", "0x8c41fe765128e63f6889d6a979f6a4342300327c8b245a8cfe3ecfbcac1e09c3da30e2a1045b24b78efc6d6d50c8c6ac", "0xa5dd4ae51ae48c8be4b218c312ade226cffce671cf121cb77810f6c0990768d6dd767badecb5c69921d5574d5e8433d3", "0xb7642e325f4ba97ae2a39c1c9d97b35aafd49d53dba36aed3f3cb0ca816480b3394079f46a48252d46596559c90f4d58", "0xae87375b40f35519e7bd4b1b2f73cd0b329b0c2cb9d616629342a71c6c304338445eda069b78ea0fbe44087f3de91e09", "0xb08918cb6f736855e11d3daca1ddfbdd61c9589b203b5493143227bf48e2c77c2e8c94b0d1aa2fab2226e0eae83f2681", "0xac36b84a4ac2ebd4d6591923a449c564e3be8a664c46092c09e875c2998eba16b5d32bfd0882fd3851762868e669f0b1", "0xa44800a3bb192066fa17a3f29029a23697240467053b5aa49b9839fb9b9b8b12bcdcbfc557f024b61f4f51a9aacdefcb", "0x9064c688fec23441a274cdf2075e5a449caf5c7363cc5e8a5dc9747183d2e00a0c69f2e6b3f6a7057079c46014c93b3b", "0xaa367b021469af9f5b764a79bb3afbe2d87fe1e51862221672d1a66f954b165778b7c27a705e0f93841fab4c8468344d", "0xa1a8bfc593d4ab71f91640bc824de5c1380ab2591cfdafcbc78a14b32de3c0e15f9d1b461d85c504baa3d4232c16bb53", "0x97df48da1799430f528184d30b6baa90c2a2f88f34cdfb342d715339c5ebd6d019aa693cea7c4993daafc9849063a3aa", "0xabd923831fbb427e06e0dd335253178a9e5791395c84d0ab1433c07c53c1209161097e9582fb8736f8a60bde62d8693e", "0x84cd1a43f1a438b43dc60ffc775f646937c4f6871438163905a3cebf1115f814ccd38a6ccb134130bff226306e412f32", "0x91426065996b0743c5f689eb3ca68a9f7b9e4d01f6c5a2652b57fa9a03d8dc7cd4bdbdab0ca5a891fee1e97a7f00cf02", "0xa4bee50249db3df7fd75162b28f04e57c678ba142ce4d3def2bc17bcb29e4670284a45f218dad3969af466c62a903757", "0x83141ebcc94d4681404e8b67a12a46374fded6df92b506aff3490d875919631408b369823a08b271d006d5b93136f317", "0xa0ea1c8883d58d5a784da3d8c8a880061adea796d7505c1f903d07c287c5467f71e4563fc0faafbc15b5a5538b0a7559", "0x89d9d480574f201a87269d26fb114278ed2c446328df431dc3556e3500e80e4cd01fcac196a2459d8646361ebda840df", "0x8bf302978973632dd464bec819bdb91304712a3ec859be071e662040620422c6e75eba6f864f764cffa2799272efec39", "0x922f666bc0fd58b6d7d815c0ae4f66d193d32fc8382c631037f59eeaeae9a8ca6c72d08e72944cf9e800b8d639094e77", "0x81ad8714f491cdff7fe4399f2eb20e32650cff2999dd45b9b3d996d54a4aba24cc6c451212e78c9e5550368a1a38fb3f", "0xb58fcf4659d73edb73175bd9139d18254e94c3e32031b5d4b026f2ed37aa19dca17ec2eb54c14340231615277a9d347e", "0xb365ac9c2bfe409b710928c646ea2fb15b28557e0f089d39878e365589b9d1c34baf5566d20bb28b33bb60fa133f6eff", "0x8fcae1d75b53ab470be805f39630d204853ca1629a14158bac2f52632277d77458dec204ff84b7b2d77e641c2045be65", "0xa03efa6bebe84f4f958a56e2d76b5ba4f95dd9ed7eb479edc7cc5e646c8d4792e5b0dfc66cc86aa4b4afe2f7a4850760", "0xaf1c823930a3638975fb0cc5c59651771b2719119c3cd08404fbd4ce77a74d708cefbe3c56ea08c48f5f10e6907f338f", "0x8260c8299b17898032c761c325ac9cabb4c5b7e735de81eacf244f647a45fb385012f4f8df743128888c29aefcaaad16", "0xab2f37a573c82e96a8d46198691cd694dfa860615625f477e41f91b879bc58a745784fccd8ffa13065834ffd150d881d", "0x986c746c9b4249352d8e5c629e8d7d05e716b3c7aab5e529ca969dd1e984a14b5be41528baef4c85d2369a42d7209216", "0xb25e32da1a8adddf2a6080725818b75bc67240728ad1853d90738485d8924ea1e202df0a3034a60ffae6f965ec55cf63", "0xa266e627afcebcefea6b6b44cbc50f5c508f7187e87d047b0450871c2a030042c9e376f3ede0afcf9d1952f089582f71", "0x86c3bbca4c0300606071c0a80dbdec21ce1dd4d8d4309648151c420854032dff1241a1677d1cd5de4e4de4385efda986", "0xb9a21a1fe2d1f3273a8e4a9185abf2ff86448cc98bfa435e3d68306a2b8b4a6a3ea33a155be3cb62a2170a86f77679a5", "0xb117b1ea381adce87d8b342cba3a15d492ff2d644afa28f22424cb9cbc820d4f7693dfc1a4d1b3697046c300e1c9b4c8", "0x9004c425a2e68870d6c69b658c344e3aa3a86a8914ee08d72b2f95c2e2d8a4c7bb0c6e7e271460c0e637cec11117bf8e", "0x86a18aa4783b9ebd9131580c8b17994825f27f4ac427b0929a1e0236907732a1c8139e98112c605488ee95f48bbefbfc", "0x84042243b955286482ab6f0b5df4c2d73571ada00716d2f737ca05a0d2e88c6349e8ee9e67934cfee4a1775dbf7f4800", "0x92c2153a4733a62e4e1d5b60369f3c26777c7d01cd3c8679212660d572bd3bac9b8a8a64e1f10f7dbf5eaa7579c4e423", "0x918454b6bb8e44a2afa144695ba8d48ae08d0cdfef4ad078f67709eddf3bb31191e8b006f04e82ea45a54715ef4d5817", "0xacf0b54f6bf34cf6ed6c2b39cf43194a40d68de6bcf1e4b82c34c15a1343e9ac3737885e1a30b78d01fa3a5125463db8", "0xa7d60dbe4b6a7b054f7afe9ee5cbbfeca0d05dc619e6041fa2296b549322529faddb8a11e949562309aecefb842ac380", "0x91ffb53e6d7e5f11159eaf13e783d6dbdfdb1698ed1e6dbf3413c6ea23492bbb9e0932230a9e2caac8fe899a17682795", "0xb6e8d7be5076ee3565d5765a710c5ecf17921dd3cf555c375d01e958a365ae087d4a88da492a5fb81838b7b92bf01143", "0xa8c6b763de2d4b2ed42102ef64eccfef31e2fb2a8a2776241c82912fa50fc9f77f175b6d109a97ede331307c016a4b1a", "0x99839f86cb700c297c58bc33e28d46b92931961548deac29ba8df91d3e11721b10ea956c8e16984f9e4acf1298a79b37", "0x8c2e2c338f25ea5c25756b7131cde0d9a2b35abf5d90781180a00fe4b8e64e62590dc63fe10a57fba3a31c76d784eb01", "0x9687d7df2f41319ca5469d91978fed0565a5f11f829ebadaa83db92b221755f76c6eacd7700735e75c91e257087512e3", "0x8795fdfb7ff8439c58b9bf58ed53873d2780d3939b902b9ddaaa4c99447224ced9206c3039a23c2c44bcc461e2bb637f", "0xa803697b744d2d087f4e2307218d48fa88620cf25529db9ce71e2e3bbcc65bac5e8bb9be04777ef7bfb5ed1a5b8e6170", "0x80f3d3efbbb9346ddd413f0a8e36b269eb5d7ff6809d5525ff9a47c4bcab2c01b70018b117f6fe05253775612ff70c6b", "0x9050e0e45bcc83930d4c505af35e5e4d7ca01cd8681cba92eb55821aececcebe32bb692ebe1a4daac4e7472975671067", "0x8d206812aac42742dbaf233e0c080b3d1b30943b54b60283515da005de05ea5caa90f91fedcfcba72e922f64d7040189", "0xa2d44faaeb2eff7915c83f32b13ca6f31a6847b1c1ce114ea240bac3595eded89f09b2313b7915ad882292e2b586d5b4", "0x961776c8576030c39f214ea6e0a3e8b3d32f023d2600958c098c95c8a4e374deeb2b9dc522adfbd6bda5949bdc09e2a2", "0x993fa7d8447407af0fbcd9e6d77f815fa5233ab00674efbcf74a1f51c37481445ae291cc7b76db7c178f9cb0e570e0fc", "0xabd5b1c78e05f9d7c8cc99bdaef8b0b6a57f2daf0f02bf492bec48ea4a27a8f1e38b5854da96efff11973326ff980f92", "0x8f15af4764bc275e6ccb892b3a4362cacb4e175b1526a9a99944e692fe6ccb1b4fc19abf312bb2a089cb1f344d91a779", "0xa09b27ccd71855512aba1d0c30a79ffbe7f6707a55978f3ced50e674b511a79a446dbc6d7946add421ce111135a460af", "0x94b2f98ce86a9271fbd4153e1fc37de48421fe3490fb3840c00f2d5a4d0ba8810c6a32880b002f6374b59e0a7952518b", "0x8650ac644f93bbcb88a6a0f49fee2663297fd4bc6fd47b6a89b9d8038d32370438ab3a4775ec9b58cb10aea8a95ef7b6", "0x95e5c2f2e84eed88c6980bbba5a1c0bb375d5a628bff006f7516d45bb7d723da676add4fdd45956f312e7bab0f052644", "0xb3278a3fa377ac93af7cfc9453f8cb594aae04269bbc99d2e0e45472ff4b6a2f97a26c4c57bf675b9d86f5e77a5d55d1", "0xb4bcbe6eb666a206e2ea2f877912c1d3b5bdbd08a989fc4490eb06013e1a69ad1ba08bcdac048bf29192312be399077b", "0xa76d70b78c99fffcbf9bb9886eab40f1ea4f99a309710b660b64cbf86057cbcb644d243f6e341711bb7ef0fedf0435a7", "0xb2093c1ee945dca7ac76ad5aed08eae23af31dd5a77c903fd7b6f051f4ab84425d33a03c3d45bf2907bc93c02d1f3ad8", "0x904b1f7534e053a265b22d20be859912b9c9ccb303af9a8d6f1d8f6ccdc5c53eb4a45a1762b880d8444d9be0cd55e7f9", "0x8f664a965d65bc730c9ef1ec7467be984d4b8eb46bd9b0d64e38e48f94e6e55dda19aeac82cbcf4e1473440e64c4ca18", "0x8bcee65c4cc7a7799353d07b114c718a2aae0cd10a3f22b7eead5185d159dafd64852cb63924bf87627d176228878bce", "0x8c78f2e3675096fef7ebaa898d2615cd50d39ca3d8f02b9bdfb07e67da648ae4be3da64838dffc5935fd72962c4b96c7", "0x8c40afd3701629421fec1df1aac4e849384ef2e80472c0e28d36cb1327acdf2826f99b357f3d7afdbc58a6347fc40b3c", "0xa197813b1c65a8ea5754ef782522a57d63433ef752215ecda1e7da76b0412ee619f58d904abd2e07e0c097048b6ae1dd", "0xa670542629e4333884ad7410f9ea3bd6f988df4a8f8a424ca74b9add2312586900cf9ae8bd50411f9146e82626b4af56", "0xa19875cc07ab84e569d98b8b67fb1dbbdfb59093c7b748fae008c8904a6fd931a63ca8d03ab5fea9bc8d263568125a9b", "0xb57e7f68e4eb1bd04aafa917b1db1bdab759a02aa8a9cdb1cba34ba8852b5890f655645c9b4e15d5f19bf37e9f2ffe9f", "0x8abe4e2a4f6462b6c64b3f10e45db2a53c2b0d3c5d5443d3f00a453e193df771eda635b098b6c8604ace3557514027af", "0x8459e4fb378189b22b870a6ef20183deb816cefbf66eca1dc7e86d36a2e011537db893729f500dc154f14ce24633ba47", "0x930851df4bc7913c0d8c0f7bd3b071a83668987ed7c397d3d042fdc0d9765945a39a3bae83da9c88cb6b686ed8aeeb26", "0x8078c9e5cd05e1a8c932f8a1d835f61a248b6e7133fcbb3de406bf4ffc0e584f6f9f95062740ba6008d98348886cf76b", "0xaddff62bb29430983fe578e3709b0949cdc0d47a13a29bc3f50371a2cb5c822ce53e2448cfaa01bcb6e0aa850d5a380e", "0x9433add687b5a1e12066721789b1db2edf9b6558c3bdc0f452ba33b1da67426abe326e9a34d207bfb1c491c18811bde1", "0x822beda3389963428cccc4a2918fa9a8a51cf0919640350293af70821967108cded5997adae86b33cb917780b097f1ca", "0xa7a9f52bda45e4148ed56dd176df7bd672e9b5ed18888ccdb405f47920fdb0844355f8565cefb17010b38324edd8315f", "0xb35c3a872e18e607b2555c51f9696a17fa18da1f924d503b163b4ec9fe22ed0c110925275cb6c93ce2d013e88f173d6a", "0xadf34b002b2b26ab84fc1bf94e05bd8616a1d06664799ab149363c56a6e0c807fdc473327d25632416e952ea327fcd95", "0xae4a6b9d22a4a3183fac29e2551e1124a8ce4a561a9a2afa9b23032b58d444e6155bb2b48f85c7b6d70393274e230db7", "0xa2ea3be4fc17e9b7ce3110284038d46a09e88a247b6971167a7878d9dcf36925d613c382b400cfa4f37a3ebea3699897", "0x8e5863786b641ce3140fbfe37124d7ad3925472e924f814ebfc45959aaf3f61dc554a597610b5defaecc85b59a99b50f", "0xaefde3193d0f700d0f515ab2aaa43e2ef1d7831c4f7859f48e52693d57f97fa9e520090f3ed700e1c966f4b76048e57f", "0x841a50f772956622798e5cd208dc7534d4e39eddee30d8ce133383d66e5f267e389254a0cdae01b770ecd0a9ca421929", "0x8fbc2bfd28238c7d47d4c03b1b910946c0d94274a199575e5b23242619b1de3497784e646a92aa03e3e24123ae4fcaba", "0x926999579c8eec1cc47d7330112586bdca20b4149c8b2d066f527c8b9f609e61ce27feb69db67eea382649c6905efcf9", "0xb09f31f305efcc65589adf5d3690a76cf339efd67cd43a4e3ced7b839507466e4be72dd91f04e89e4bbef629d46e68c0", "0xb917361f6b95f759642638e0b1d2b3a29c3bdef0b94faa30de562e6078c7e2d25976159df3edbacbf43614635c2640b4", "0x8e7e8a1253bbda0e134d62bfe003a2669d471b47bd2b5cde0ff60d385d8e62279d54022f5ac12053b1e2d3aaa6910b4c", "0xb69671a3c64e0a99d90b0ed108ce1912ff8ed983e4bddd75a370e9babde25ee1f5efb59ec707edddd46793207a8b1fe7", "0x910b2f4ebd37b7ae94108922b233d0920b4aba0bd94202c70f1314418b548d11d8e9caa91f2cd95aff51b9432d122b7f", "0x82f645c90dfb52d195c1020346287c43a80233d3538954548604d09fbab7421241cde8593dbc4acc4986e0ea39a27dd9", "0x8fee895f0a140d88104ce442fed3966f58ff9d275e7373483f6b4249d64a25fb5374bbdc6bce6b5ab0270c2847066f83", "0x84f5bd7aab27b2509397aeb86510dd5ac0a53f2c8f73799bf720f2f87a52277f8d6b0f77f17bc80739c6a7119b7eb062", "0x9903ceced81099d7e146e661bcf01cbaccab5ba54366b85e2177f07e2d8621e19d9c9c3eee14b9266de6b3f9b6ea75ae", "0xb9c16ea2a07afa32dd6c7c06df0dec39bca2067a9339e45475c98917f47e2320f6f235da353fd5e15b477de97ddc68dd", "0x9820a9bbf8b826bec61ebf886de2c4f404c1ebdc8bab82ee1fea816d9de29127ce1852448ff717a3fe8bbfe9e92012e5", "0x817224d9359f5da6f2158c2c7bf9165501424f063e67ba9859a07ab72ee2ee62eb00ca6da821cfa19065c3282ca72c74", "0x94b95c465e6cb00da400558a3c60cfec4b79b27e602ca67cbc91aead08de4b6872d8ea096b0dc06dca4525c8992b8547", "0xa2b539a5bccd43fa347ba9c15f249b417997c6a38c63517ca38394976baa08e20be384a360969ff54e7e721db536b3e5", "0x96caf707e34f62811ee8d32ccf28d8d6ec579bc33e424d0473529af5315c456fd026aa910c1fed70c91982d51df7d3ca", "0x8a77b73e890b644c6a142bdbac59b22d6a676f3b63ddafb52d914bb9d395b8bf5aedcbcc90429337df431ebd758a07a6", "0x8857830a7351025617a08bc44caec28d2fae07ebf5ffc9f01d979ce2a53839a670e61ae2783e138313929129790a51a1", "0xaa3e420321ed6f0aa326d28d1a10f13facec6f605b6218a6eb9cbc074801f3467bf013a456d1415a5536f12599efa3d3", "0x824aed0951957b00ea2f3d423e30328a3527bf6714cf9abbae84cf27e58e5c35452ba89ccc011de7c68c75d6e021d8f1", "0xa2e87cc06bf202e953fb1081933d8b4445527dde20e38ed1a4f440144fd8fa464a2b73e068b140562e9045e0f4bd3144", "0xae3b8f06ad97d7ae3a5e5ca839efff3e4824dc238c0c03fc1a8d2fc8aa546cdfd165b784a31bb4dec7c77e9305b99a4b", "0xb30c3e12395b1fb8b776f3ec9f87c70e35763a7b2ddc68f0f60a4982a84017f27c891a98561c830038deb033698ed7fc", "0x874e507757cd1177d0dff0b0c62ce90130324442a33da3b2c8ee09dbca5d543e3ecfe707e9f1361e7c7db641c72794bb", "0xb53012dd10b5e7460b57c092eaa06d6502720df9edbbe3e3f61a9998a272bf5baaac4a5a732ad4efe35d6fac6feca744", "0x85e6509d711515534d394e6cacbed6c81da710074d16ef3f4950bf2f578d662a494d835674f79c4d6315bced4defc5f0", "0xb6132b2a34b0905dcadc6119fd215419a7971fe545e52f48b768006944b4a9d7db1a74b149e2951ea48c083b752d0804", "0x989867da6415036d19b4bacc926ce6f4df7a556f50a1ba5f3c48eea9cefbb1c09da81481c8009331ee83f0859185e164", "0x960a6c36542876174d3fbc1505413e29f053ed87b8d38fef3af180491c7eff25200b45dd5fe5d4d8e63c7e8c9c00f4c8", "0x9040b59bd739d9cc2e8f6e894683429e4e876a8106238689ff4c22770ae5fdae1f32d962b30301fa0634ee163b524f35", "0xaf3fcd0a45fe9e8fe256dc7eab242ef7f582dd832d147444483c62787ac820fafc6ca55d639a73f76bfa5e7f5462ab8f", "0xb934c799d0736953a73d91e761767fdb78454355c4b15c680ce08accb57ccf941b13a1236980001f9e6195801cffd692", "0x8871e8e741157c2c326b22cf09551e78da3c1ec0fc0543136f581f1550f8bab03b0a7b80525c1e99812cdbf3a9698f96", "0xa8a977f51473a91d178ee8cfa45ffef8d6fd93ab1d6e428f96a3c79816d9c6a93cd70f94d4deda0125fd6816e30f3bea", "0xa7688b3b0a4fc1dd16e8ba6dc758d3cfe1b7cf401c31739484c7fa253cce0967df1b290769bcefc9d23d3e0cb19e6218", "0x8ae84322662a57c6d729e6ff9d2737698cc2da2daeb1f39e506618750ed23442a6740955f299e4a15dda6db3e534d2c6", "0xa04a961cdccfa4b7ef83ced17ab221d6a043b2c718a0d6cc8e6f798507a31f10bf70361f70a049bc8058303fa7f96864", "0xb463e39732a7d9daec8a456fb58e54b30a6e160aa522a18b9a9e836488cce3342bcbb2e1deab0f5e6ec0a8796d77197d", "0xb1434a11c6750f14018a2d3bcf94390e2948f4f187e93bb22070ca3e5393d339dc328cbfc3e48815f51929465ffe7d81", "0x84ff81d73f3828340623d7e3345553610aa22a5432217ef0ebd193cbf4a24234b190c65ca0873c22d10ea7b63bd1fbed", "0xb6fe2723f0c47757932c2ddde7a4f8434f665612f7b87b4009c2635d56b6e16b200859a8ade49276de0ef27a2b6c970a", "0x9742884ed7cd52b4a4a068a43d3faa02551a424136c85a9313f7cb58ea54c04aa83b0728fd741d1fe39621e931e88f8f", "0xb7d2d65ea4d1ad07a5dee39e40d6c03a61264a56b1585b4d76fc5b2a68d80a93a42a0181d432528582bf08d144c2d6a9", "0x88c0f66bada89f8a43e5a6ead2915088173d106c76f724f4a97b0f6758aed6ae5c37c373c6b92cdd4aea8f6261f3a374", "0x81f9c43582cb42db3900747eb49ec94edb2284999a499d1527f03315fd330e5a509afa3bff659853570e9886aab5b28b", "0x821f9d27d6beb416abf9aa5c79afb65a50ed276dbda6060103bc808bcd34426b82da5f23e38e88a55e172f5c294b4d40", "0x8ba307b9e7cb63a6c4f3851b321aebfdb6af34a5a4c3bd949ff7d96603e59b27ff4dc4970715d35f7758260ff942c9e9", "0xb142eb6c5f846de33227d0bda61d445a7c33c98f0a8365fe6ab4c1fabdc130849be597ef734305894a424ea715372d08", "0xa732730ae4512e86a741c8e4c87fee8a05ee840fec0e23b2e037d58dba8dde8d10a9bc5191d34d00598941becbbe467f", "0xadce6f7c30fd221f6b10a0413cc76435c4bb36c2d60bca821e5c67409fe9dbb2f4c36ef85eb3d734695e4be4827e9fd3", "0xa74f00e0f9b23aff7b2527ce69852f8906dab9d6abe62ecd497498ab21e57542e12af9918d4fd610bb09e10b0929c510", "0xa593b6b0ef26448ce4eb3ab07e84238fc020b3cb10d542ff4b16d4e2be1bcde3797e45c9cf753b8dc3b0ffdb63984232", "0xaed3913afccf1aa1ac0eb4980eb8426d0baccebd836d44651fd72af00d09fac488a870223c42aca3ceb39752070405ae", "0xb2c44c66a5ea7fde626548ba4cef8c8710191343d3dadfd3bb653ce715c0e03056a5303a581d47dde66e70ea5a2d2779", "0x8e5029b2ccf5128a12327b5103f7532db599846e422531869560ceaff392236434d87159f597937dbf4054f810c114f4", "0x82beed1a2c4477e5eb39fc5b0e773b30cfec77ef2b1bf17eadaf60eb35b6d0dd9d8cf06315c48d3546badb3f21cd0cca", "0x90077bd6cc0e4be5fff08e5d07a5a158d36cebd1d1363125bc4fae0866ffe825b26f933d4ee5427ba5cd0c33c19a7b06", "0xa7ec0d8f079970e8e34f0ef3a53d3e0e45428ddcef9cc776ead5e542ef06f3c86981644f61c5a637e4faf001fb8c6b3e", "0xae6d4add6d1a6f90b22792bc9d40723ee6850c27d0b97eefafd5b7fd98e424aa97868b5287cc41b4fbd7023bca6a322c", "0x831aa917533d077da07c01417feaa1408846363ba2b8d22c6116bb858a95801547dd88b7d7fa1d2e3f0a02bdeb2e103d", "0x96511b860b07c8a5ed773f36d4aa9d02fb5e7882753bf56303595bcb57e37ccc60288887eb83bef08c657ec261a021a2", "0x921d2a3e7e9790f74068623de327443666b634c8443aba80120a45bba450df920b2374d96df1ce3fb1b06dd06f8cf6e3", "0xaa74451d51fe82b4581ead8e506ec6cd881010f7e7dd51fc388eb9a557db5d3c6721f81c151d08ebd9c2591689fbc13e", "0xa972bfbcf4033d5742d08716c927c442119bdae336bf5dff914523b285ccf31953da2733759aacaa246a9af9f698342c", "0xad1fcd0cae0e76840194ce4150cb8a56ebed728ec9272035f52a799d480dfc85840a4d52d994a18b6edb31e79be6e8ad", "0xa2c69fe1d36f235215432dad48d75887a44c99dfa0d78149acc74087da215a44bdb5f04e6eef88ff7eff80a5a7decc77", "0xa94ab2af2b6ee1bc6e0d4e689ca45380d9fbd3c5a65b9bd249d266a4d4c07bf5d5f7ef2ae6000623aee64027892bf8fe", "0x881ec1fc514e926cdc66480ac59e139148ff8a2a7895a49f0dff45910c90cdda97b66441a25f357d6dd2471cddd99bb3", "0x884e6d3b894a914c8cef946a76d5a0c8351843b2bffa2d1e56c6b5b99c84104381dd1320c451d551c0b966f4086e60f9", "0x817c6c10ce2677b9fc5223500322e2b880583254d0bb0d247d728f8716f5e05c9ff39f135854342a1afecd9fbdcf7c46", "0xaaf4a9cb686a14619aa1fc1ac285dd3843ac3dd99f2b2331c711ec87b03491c02f49101046f3c5c538dc9f8dba2a0ac2", "0x97ecea5ce53ca720b5d845227ae61d70269a2f53540089305c86af35f0898bfd57356e74a8a5e083fa6e1ea70080bd31", "0xa22d811e1a20a75feac0157c418a4bfe745ccb5d29466ffa854dca03e395b6c3504a734341746b2846d76583a780b32e", "0x940cbaa0d2b2db94ae96b6b9cf2deefbfd059e3e5745de9aec4a25f0991b9721e5cd37ef71c631575d1a0c280b01cd5b", "0xae33cb4951191258a11044682de861bf8d92d90ce751b354932dd9f3913f542b6a0f8a4dc228b3cd9244ac32c4582832", "0xa580df5e58c4274fe0f52ac2da1837e32f5c9db92be16c170187db4c358f43e5cfdda7c5911dcc79d77a5764e32325f5", "0x81798178cb9d8affa424f8d3be67576ba94d108a28ccc01d330c51d5a63ca45bb8ca63a2f569b5c5fe1303cecd2d777f", "0x89975b91b94c25c9c3660e4af4047a8bacf964783010820dbc91ff8281509379cb3b24c25080d5a01174dd9a049118d5", "0xa7327fcb3710ed3273b048650bde40a32732ef40a7e58cf7f2f400979c177944c8bc54117ba6c80d5d4260801dddab79", "0x92b475dc8cb5be4b90c482f122a51bcb3b6c70593817e7e2459c28ea54a7845c50272af38119406eaadb9bcb993368d0", "0x9645173e9ecefc4f2eae8363504f7c0b81d85f8949a9f8a6c01f2d49e0a0764f4eacecf3e94016dd407fc14494fce9f9", "0x9215fd8983d7de6ae94d35e6698226fc1454977ae58d42d294be9aad13ac821562ad37d5e7ee5cdfe6e87031d45cd197", "0x810360a1c9b88a9e36f520ab5a1eb8bed93f52deefbe1312a69225c0a08edb10f87cc43b794aced9c74220cefcc57e7d", "0xad7e810efd61ed4684aeda9ed8bb02fb9ae4b4b63fda8217d37012b94ff1b91c0087043bfa4e376f961fff030c729f3b", "0x8b07c95c6a06db8738d10bb03ec11b89375c08e77f0cab7e672ce70b2685667ca19c7e1c8b092821d31108ea18dfd4c7", "0x968825d025ded899ff7c57245250535c732836f7565eab1ae23ee7e513201d413c16e1ba3f5166e7ac6cf74de8ceef4f", "0x908243370c5788200703ade8164943ad5f8c458219186432e74dbc9904a701ea307fd9b94976c866e6c58595fd891c4b", "0x959969d16680bc535cdc6339e6186355d0d6c0d53d7bbfb411641b9bf4b770fd5f575beef5deec5c4fa4d192d455c350", "0xad177f4f826a961adeac76da40e2d930748effff731756c797eddc4e5aa23c91f070fb69b19221748130b0961e68a6bb", "0x82f8462bcc25448ef7e0739425378e9bb8a05e283ce54aae9dbebaf7a3469f57833c9171672ad43a79778366c72a5e37", "0xa28fb275b1845706c2814d9638573e9bc32ff552ebaed761fe96fdbce70395891ca41c400ae438369264e31a2713b15f", "0x8a9c613996b5e51dadb587a787253d6081ea446bf5c71096980bf6bd3c4b69905062a8e8a3792de2d2ece3b177a71089", "0x8d5aefef9f60cb27c1db2c649221204dda48bb9bf8bf48f965741da051340e8e4cab88b9d15c69f3f84f4c854709f48a", "0x93ebf2ca6ad85ab6deace6de1a458706285b31877b1b4d7dcb9d126b63047efaf8c06d580115ec9acee30c8a7212fa55", "0xb3ee46ce189956ca298057fa8223b7fd1128cf52f39159a58bca03c71dd25161ac13f1472301f72aef3e1993fe1ab269", "0xa24d7a8d066504fc3f5027ccb13120e2f22896860e02c45b5eba1dbd512d6a17c28f39155ea581619f9d33db43a96f92", "0xae9ceacbfe12137db2c1a271e1b34b8f92e4816bad1b3b9b6feecc34df0f8b3b0f7ed0133acdf59c537d43d33fc8d429", "0x83967e69bf2b361f86361bd705dce0e1ad26df06da6c52b48176fe8dfcbeb03c462c1a4c9e649eff8c654b18c876fdef", "0x9148e6b814a7d779c19c31e33a068e97b597de1f8100513db3c581190513edc4d544801ce3dd2cf6b19e0cd6daedd28a", "0x94ccdafc84920d320ed22de1e754adea072935d3c5f8c2d1378ebe53d140ea29853f056fb3fb1e375846061a038cc9bc", "0xafb43348498c38b0fa5f971b8cdd3a62c844f0eb52bc33daf2f67850af0880fce84ecfb96201b308d9e6168a0d443ae3", "0x86d5736520a83538d4cd058cc4b4e84213ed00ebd6e7af79ae787adc17a92ba5359e28ba6c91936d967b4b28d24c3070", "0xb5210c1ff212c5b1e9ef9126e08fe120a41e386bb12c22266f7538c6d69c7fd8774f11c02b81fd4e88f9137b020801fe", "0xb78cfd19f94d24e529d0f52e18ce6185cb238edc6bd43086270fd51dd99f664f43dd4c7d2fe506762fbd859028e13fcf", "0xa6e7220598c554abdcc3fdc587b988617b32c7bb0f82c06205467dbedb58276cc07cae317a190f19d19078773f4c2bbb", "0xb88862809487ee430368dccd85a5d72fa4d163ca4aad15c78800e19c1a95be2192719801e315d86cff7795e0544a77e4", "0x87ecb13a03921296f8c42ceb252d04716f10e09c93962239fcaa0a7fef93f19ab3f2680bc406170108bc583e9ff2e721", "0xa810cd473832b6581c36ec4cb403f2849357ba2d0b54df98ef3004b8a530c078032922a81d40158f5fb0043d56477f6e", "0xa247b45dd85ca7fbb718b328f30a03f03c84aef2c583fbdc9fcc9eb8b52b34529e8c8f535505c10598b1b4dac3d7c647", "0x96ee0b91313c68bac4aa9e065ce9e1d77e51ca4cff31d6a438718c58264dee87674bd97fc5c6b8008be709521e4fd008", "0x837567ad073e42266951a9a54750919280a2ac835a73c158407c3a2b1904cf0d17b7195a393c71a18ad029cbd9cf79ee", "0xa6a469c44b67ebf02196213e7a63ad0423aab9a6e54acc6fcbdbb915bc043586993454dc3cd9e4be8f27d67c1050879b", "0x8712d380a843b08b7b294f1f06e2f11f4ad6bcc655fdde86a4d8bc739c23916f6fad2b902fe47d6212f03607907e9f0e", "0x920adfb644b534789943cdae1bdd6e42828dda1696a440af2f54e6b97f4f97470a1c6ea9fa6a2705d8f04911d055acd1", "0xa161c73adf584a0061e963b062f59d90faac65c9b3a936b837a10d817f02fcabfa748824607be45a183dd40f991fe83f", "0x874f4ecd408c76e625ea50bc59c53c2d930ee25baf4b4eca2440bfbffb3b8bc294db579caa7c68629f4d9ec24187c1ba", "0x8bff18087f112be7f4aa654e85c71fef70eee8ae480f61d0383ff6f5ab1a0508f966183bb3fc4d6f29cb7ca234aa50d3", "0xb03b46a3ca3bc743a173cbc008f92ab1aedd7466b35a6d1ca11e894b9482ea9dc75f8d6db2ddd1add99bfbe7657518b7", "0x8b4f3691403c3a8ad9e097f02d130769628feddfa8c2b3dfe8cff64e2bed7d6e5d192c1e2ba0ac348b8585e94acd5fa1", "0xa0d9ca4a212301f97591bf65d5ef2b2664766b427c9dd342e23cb468426e6a56be66b1cb41fea1889ac5d11a8e3c50a5", "0x8c93ed74188ca23b3df29e5396974b9cc135c91fdefdea6c0df694c8116410e93509559af55533a3776ac11b228d69b1", "0x82dd331fb3f9e344ebdeeb557769b86a2cc8cc38f6c298d7572a33aea87c261afa9dbd898989139b9fc16bc1e880a099", "0xa65faedf326bcfd8ef98a51410c78b021d39206704e8291cd1f09e096a66b9b0486be65ff185ca224c45918ac337ddeb", "0xa188b37d363ac072a766fd5d6fa27df07363feff1342217b19e3c37385e42ffde55e4be8355aceaa2f267b6d66b4ac41", "0x810fa3ba3e96d843e3bafd3f2995727f223d3567c8ba77d684c993ba1773c66551eb5009897c51b3fe9b37196984f5ec", "0x87631537541852da323b4353af45a164f68b304d24c01183bf271782e11687f3fcf528394e1566c2a26cb527b3148e64", "0xb721cb2b37b3c477a48e3cc0044167d51ff568a5fd2fb606e5aec7a267000f1ddc07d3db919926ae12761a8e017c767c", "0x904dfad4ba2cc1f6e60d1b708438a70b1743b400164cd981f13c064b8328d5973987d4fb9cf894068f29d3deaf624dfb", "0xa70491538893552c20939fae6be2f07bfa84d97e2534a6bbcc0f1729246b831103505e9f60e97a8fa7d2e6c1c2384579", "0x8726cf1b26b41f443ff7485adcfddc39ace2e62f4d65dd0bb927d933e262b66f1a9b367ded5fbdd6f3b0932553ac1735", "0xae8a11cfdf7aa54c08f80cb645e3339187ab3886babe9fae5239ba507bb3dd1c0d161ca474a2df081dcd3d63e8fe445e", "0x92328719e97ce60e56110f30a00ac5d9c7a2baaf5f8d22355d53c1c77941e3a1fec7d1405e6fbf8959665fe2ba7a8cad", "0x8d9d6255b65798d0018a8cccb0b6343efd41dc14ff2058d3eed9451ceaad681e4a0fa6af67b0a04318aa628024e5553d", "0xb70209090055459296006742d946a513f0cba6d83a05249ee8e7a51052b29c0ca9722dc4af5f9816a1b7938a5dac7f79", "0xaab7b766b9bf91786dfa801fcef6d575dc6f12b77ecc662eb4498f0312e54d0de9ea820e61508fc8aeee5ab5db529349", "0xa8104b462337748b7f086a135d0c3f87f8e51b7165ca6611264b8fb639d9a2f519926cb311fa2055b5fadf03da70c678", "0xb0d2460747d5d8b30fc6c6bd0a87cb343ddb05d90a51b465e8f67d499cfc5e3a9e365da05ae233bbee792cdf90ec67d5", "0xaa55f5bf3815266b4a149f85ed18e451c93de9163575e3ec75dd610381cc0805bb0a4d7c4af5b1f94d10231255436d2c", "0x8d4c6a1944ff94426151909eb5b99cfd92167b967dabe2bf3aa66bb3c26c449c13097de881b2cfc1bf052862c1ef7b03", "0x8862296162451b9b6b77f03bf32e6df71325e8d7485cf3335d66fd48b74c2a8334c241db8263033724f26269ad95b395", "0x901aa96deb26cda5d9321190ae6624d357a41729d72ef1abfd71bebf6139af6d690798daba53b7bc5923462115ff748a", "0x96c195ec4992728a1eb38cdde42d89a7bce150db43adbc9e61e279ea839e538deec71326b618dd39c50d589f78fc0614", "0xb6ff8b8aa0837b99a1a8b46fb37f20ad4aecc6a98381b1308697829a59b8442ffc748637a88cb30c9b1f0f28a926c4f6", "0x8d807e3dca9e7bef277db1d2cfb372408dd587364e8048b304eff00eacde2c723bfc84be9b98553f83cba5c7b3cba248", "0x8800c96adb0195c4fc5b24511450dee503c32bf47044f5e2e25bd6651f514d79a2dd9b01cd8c09f3c9d3859338490f57", "0x89fe366096097e38ec28dd1148887112efa5306cc0c3da09562aafa56f4eb000bf46ff79bf0bdd270cbde6bf0e1c8957", "0xaf409a90c2776e1e7e3760b2042507b8709e943424606e31e791d42f17873a2710797f5baaab4cc4a19998ef648556b0", "0x8d761863c9b6edbd232d35ab853d944f5c950c2b643f84a1a1327ebb947290800710ff01dcfa26dc8e9828481240e8b1", "0x90b95e9be1e55c463ed857c4e0617d6dc3674e99b6aa62ed33c8e79d6dfcf7d122f4f4cc2ee3e7c5a49170cb617d2e2e", "0xb3ff381efefabc4db38cc4727432e0301949ae4f16f8d1dea9b4f4de611cf5a36d84290a0bef160dac4e1955e516b3b0", "0xa8a84564b56a9003adcadb3565dc512239fc79572762cda7b5901a255bc82656bb9c01212ad33d6bef4fbbce18dacc87", "0x90a081890364b222eef54bf0075417f85e340d2fec8b7375995f598aeb33f26b44143ebf56fca7d8b4ebb36b5747b0eb", "0xade6ee49e1293224ddf2d8ab7f14bb5be6bc6284f60fd5b3a1e0cf147b73cff57cf19763b8a36c5083badc79c606b103", "0xb2fa99806dd2fa3de09320b615a2570c416c9bcdb052e592b0aead748bbe407ec9475a3d932ae48b71c2627eb81986a6", "0x91f3b7b73c8ccc9392542711c45fe6f236057e6efad587d661ad5cb4d6e88265f86b807bb1151736b1009ab74fd7acb4", "0x8800e2a46af96696dfbdcbf2ca2918b3dcf28ad970170d2d1783b52b8d945a9167d052beeb55f56c126da7ffa7059baa", "0x9862267a1311c385956b977c9aa08548c28d758d7ba82d43dbc3d0a0fd1b7a221d39e8399997fea9014ac509ff510ac4", "0xb7d24f78886fd3e2d283e18d9ad5a25c1a904e7d9b9104bf47da469d74f34162e27e531380dbbe0a9d051e6ffd51d6e7", "0xb0f445f9d143e28b9df36b0f2c052da87ee2ca374d9d0fbe2eff66ca6fe5fe0d2c1951b428d58f7314b7e74e45d445ea", "0xb63fc4083eabb8437dafeb6a904120691dcb53ce2938b820bb553da0e1eecd476f72495aacb72600cf9cad18698fd3db", "0xb9ffd8108eaebd582d665f8690fe8bb207fd85185e6dd9f0b355a09bac1bbff26e0fdb172bc0498df025414e88fe2eda", "0x967ed453e1f1a4c5b7b6834cc9f75c13f6889edc0cc91dc445727e9f408487bbf05c337103f61397a10011dfbe25d61d", "0x98ceb673aff36e1987d5521a3984a07079c3c6155974bb8b413e8ae1ce84095fe4f7862fba7aefa14753eb26f2a5805f", "0x85f01d28603a8fdf6ce6a50cb5c44f8a36b95b91302e3f4cd95c108ce8f4d212e73aec1b8d936520d9226802a2bd9136", "0x88118e9703200ca07910345fbb789e7a8f92bd80bbc79f0a9e040e8767d33df39f6eded403a9b636eabf9101e588482a", "0x90833a51eef1b10ed74e8f9bbd6197e29c5292e469c854eed10b0da663e2bceb92539710b1858bbb21887bd538d28d89", "0xb513b905ec19191167c6193067b5cfdf5a3d3828375360df1c7e2ced5815437dfd37f0c4c8f009d7fb29ff3c8793f560", "0xb1b6d405d2d18f9554b8a358cc7e2d78a3b34269737d561992c8de83392ac9a2857be4bf15de5a6c74e0c9d0f31f393c", "0xb828bd3e452b797323b798186607849f85d1fb20c616833c0619360dfd6b3e3aa000fd09dafe4b62d74abc41072ff1a9", "0x8efde67d0cca56bb2c464731879c9ac46a52e75bac702a63200a5e192b4f81c641f855ca6747752b84fe469cb7113b6c", "0xb2762ba1c89ac3c9a983c242e4d1c2610ff0528585ed5c0dfc8a2c0253551142af9b59f43158e8915a1da7cc26b9df67", "0x8a3f1157fb820d1497ef6b25cd70b7e16bb8b961b0063ad340d82a79ee76eb2359ca9e15e6d42987ed7f154f5eeaa2da", "0xa75e29f29d38f09c879f971c11beb5368affa084313474a5ecafa2896180b9e47ea1995c2733ec46f421e395a1d9cffe", "0x8e8c3dd3e7196ef0b4996b531ec79e4a1f211db5d5635e48ceb80ff7568b2ff587e845f97ee703bb23a60945ad64314a", "0x8e7f32f4a3e3c584af5e3d406924a0aa34024c42eca74ef6cc2a358fd3c9efaf25f1c03aa1e66bb94b023a2ee2a1cace", "0xab7dce05d59c10a84feb524fcb62478906b3fa045135b23afbede3bb32e0c678d8ebe59feabccb5c8f3550ea76cae44b", "0xb38bb4b44d827f6fd3bd34e31f9186c59e312dbfadd4a7a88e588da10146a78b1f8716c91ad8b806beb8da65cab80c4c", "0x9490ce9442bbbd05438c7f5c4dea789f74a7e92b1886a730544b55ba377840740a3ae4f2f146ee73f47c9278b0e233bc", "0x83c003fab22a7178eed1a668e0f65d4fe38ef3900044e9ec63070c23f2827d36a1e73e5c2b883ec6a2afe2450171b3b3", "0x9982f02405978ddc4fca9063ebbdb152f524c84e79398955e66fe51bc7c1660ec1afc3a86ec49f58d7b7dde03505731c", "0xab337bd83ccdd2322088ffa8d005f450ced6b35790f37ab4534313315ee84312adc25e99cce052863a8bedee991729ed", "0x8312ce4bec94366d88f16127a17419ef64285cd5bf9e5eda010319b48085966ed1252ed2f5a9fd3e0259b91bb65f1827", "0xa60d5a6327c4041b0c00a1aa2f0af056520f83c9ce9d9ccd03a0bd4d9e6a1511f26a422ea86bd858a1f77438adf07e6c", "0xb84a0a0b030bdad83cf5202aa9afe58c9820e52483ab41f835f8c582c129ee3f34aa096d11c1cd922eda02ea1196a882", "0x8077d105317f4a8a8f1aadeb05e0722bb55f11abcb490c36c0904401107eb3372875b0ac233144829e734f0c538d8c1d", "0x9202503bd29a6ec198823a1e4e098f9cfe359ed51eb5174d1ca41368821bfeebcbd49debfd02952c41359d1c7c06d2b1", "0xabc28c155e09365cb77ffead8dc8f602335ef93b2f44e4ef767ce8fc8ef9dd707400f3a722e92776c2e0b40192c06354", "0xb0f6d1442533ca45c9399e0a63a11f85ff288d242cea6cb3b68c02e77bd7d158047cae2d25b3bcd9606f8f66d9b32855", "0xb01c3d56a0db84dc94575f4b6ee2de4beca3230e86bed63e2066beb22768b0a8efb08ebaf8ac3dedb5fe46708b084807", "0x8c8634b0432159f66feaabb165842d1c8ac378f79565b1b90c381aa8450eb4231c3dad11ec9317b9fc2b155c3a771e32", "0x8e67f623d69ecd430c9ee0888520b6038f13a2b6140525b056dc0951f0cfed2822e62cf11d952a483107c5c5acac4826", "0x9590bb1cba816dd6acd5ac5fba5142c0a19d53573e422c74005e0bcf34993a8138c83124cad35a3df65879dba6134edd", "0x801cd96cde0749021a253027118d3ea135f3fcdbe895db08a6c145641f95ebd368dd6a1568d995e1d0084146aebe224a", "0x848b5d196427f6fc1f762ee3d36e832b64a76ec1033cfedc8b985dea93932a7892b8ef1035c653fb9dcd9ab2d9a44ac8", "0xa1017eb83d5c4e2477e7bd2241b2b98c4951a3b391081cae7d75965cadc1acaec755cf350f1f3d29741b0828e36fedea", "0x8d6d2785e30f3c29aad17bd677914a752f831e96d46caf54446d967cb2432be2c849e26f0d193a60bee161ea5c6fe90a", "0x935c0ba4290d4595428e034b5c8001cbd400040d89ab00861108e8f8f4af4258e41f34a7e6b93b04bc253d3b9ffc13bf", "0xaac02257146246998477921cef2e9892228590d323b839f3e64ea893b991b463bc2f47e1e5092ddb47e70b2f5bce7622", "0xb921fde9412970a5d4c9a908ae8ce65861d06c7679af577cf0ad0d5344c421166986bee471fd6a6cecb7d591f06ec985", "0x8ef4c37487b139d6756003060600bb6ebac7ea810b9c4364fc978e842f13ac196d1264fbe5af60d76ff6d9203d8e7d3f", "0x94b65e14022b5cf6a9b95f94be5ace2711957c96f4211c3f7bb36206bd39cfbd0ea82186cab5ad0577a23214a5c86e9e", "0xa31c166d2a2ca1d5a75a5920fef7532681f62191a50d8555fdaa63ba4581c3391cc94a536fc09aac89f64eafceec3f90", "0x919a8cc128de01e9e10f5d83b08b52293fdd41bde2b5ae070f3d95842d4a16e5331cf2f3d61c765570c8022403610fa4", "0xb23d6f8331eef100152d60483cfa14232a85ee712c8538c9b6417a5a7c5b353c2ac401390c6c215cb101f5cee6b5f43e", "0xab357160c08a18319510a571eafff154298ce1020de8e1dc6138a09fcb0fcbcdd8359f7e9386bda00b7b9cdea745ffdc", "0xab55079aea34afa5c0bd1124b9cdfe01f325b402fdfa017301bf87812eaa811ea5798c3aaf818074d420d1c782b10ada", "0xade616010dc5009e7fc4f8d8b00dc716686a5fa0a7816ad9e503e15839d3b909b69d9dd929b7575376434ffec0d2bea8", "0x863997b97ed46898a8a014599508fa3079f414b1f4a0c4fdc6d74ae8b444afa350f327f8bfc2a85d27f9e2d049c50135", "0x8d602ff596334efd4925549ed95f2aa762b0629189f0df6dbb162581657cf3ea6863cd2287b4d9c8ad52813d87fcd235", "0xb70f68c596dcdeed92ad5c6c348578b26862a51eb5364237b1221e840c47a8702f0fbc56eb520a22c0eed99795d3903e", "0x9628088f8e0853cefadee305a8bf47fa990c50fa96a82511bbe6e5dc81ef4b794e7918a109070f92fc8384d77ace226f", "0x97e26a46e068b605ce96007197ecd943c9a23881862f4797a12a3e96ba2b8d07806ad9e2a0646796b1889c6b7d75188c", "0xb1edf467c068cc163e2d6413cc22b16751e78b3312fe47b7ea82b08a1206d64415b2c8f2a677fa89171e82cc49797150", "0xa44d15ef18745b251429703e3cab188420e2d974de07251501799b016617f9630643fcd06f895634d8ecdd579e1bf000", "0xabd126df3917ba48c618ee4dbdf87df506193462f792874439043fa1b844466f6f4e0ff2e42516e63b5b23c0892b2695", "0xa2a67f57c4aa3c2aa1eeddbfd5009a89c26c2ce8fa3c96a64626aba19514beb125f27df8559506f737de3eae0f1fc18f", "0xa633e0132197e6038197304b296ab171f1d8e0d0f34dcf66fe9146ac385b0239232a8470b9205a4802ab432389f4836d", "0xa914b3a28509a906c3821463b936455d58ff45dcbe158922f9efb2037f2eb0ce8e92532d29b5d5a3fcd0d23fa773f272", "0xa0e1412ce4505daf1a2e59ce4f0fc0e0023e335b50d2b204422f57cd65744cc7a8ed35d5ef131a42c70b27111d3115b7", "0xa2339e2f2b6072e88816224fdd612c04d64e7967a492b9f8829db15367f565745325d361fd0607b0def1be384d010d9e", "0xa7309fc41203cb99382e8193a1dcf03ac190a7ce04835304eb7e341d78634e83ea47cb15b885601956736d04cdfcaa01", "0x81f3ccd6c7f5b39e4e873365f8c37b214e8ab122d04a606fbb7339dc3298c427e922ec7418002561d4106505b5c399ee", "0x92c121cf914ca549130e352eb297872a63200e99b148d88fbc9506ad882bec9d0203d65f280fb5b0ba92e336b7f932e8", "0xa4b330cf3f064f5b131578626ad7043ce2a433b6f175feb0b52d36134a454ca219373fd30d5e5796410e005b69082e47", "0x86fe5774112403ad83f9c55d58317eeb17ad8e1176d9f2f69c2afb7ed83bc718ed4e0245ceab4b377f5f062dcd4c00e7", "0x809d152a7e2654c7fd175b57f7928365a521be92e1ed06c05188a95864ddb25f7cab4c71db7d61bbf4cae46f3a1d96ce", "0xb82d663e55c2a5ada7e169e9b1a87bc1c0177baf1ec1c96559b4cb1c5214ce1ddf2ab8d345014cab6402f3774235cf5a", "0x86580af86df1bd2c385adb8f9a079e925981b7184db66fc5fe5b14cddb82e7d836b06eaeef14924ac529487b23dae111", "0xb5f5f4c5c94944ecc804df6ab8687d64e27d988cbfeae1ba7394e0f6adbf778c5881ead7cd8082dd7d68542b9bb4ecd5", "0xa6016916146c2685c46e8fdd24186394e2d5496e77e08c0c6a709d4cd7dfa97f1efcef94922b89196819076a91ad37b5", "0xb778e7367ded3b6eab53d5fc257f7a87e8faf74a593900f2f517220add2125be3f6142022660d8181df8d164ad9441ce", "0x8581b2d36abe6f553add4d24be761bec1b8efaa2929519114346615380b3c55b59e6ad86990e312f7e234d0203bdf59b", "0x9917e74fd45c3f71a829ff5498a7f6b5599b48c098dda2339bf04352bfc7f368ccf1a407f5835901240e76452ae807d7", "0xafd196ce6f9335069138fd2e3d133134da253978b4ce373152c0f26affe77a336505787594022e610f8feb722f7cc1fb", "0xa477491a1562e329764645e8f24d8e228e5ef28c9f74c6b5b3abc4b6a562c15ffb0f680d372aed04d9e1bf944dece7be", "0x9767440d58c57d3077319d3a330e5322b9ba16981ec74a5a14d53462eab59ae7fd2b14025bfc63b268862094acb444e6", "0x80986d921be3513ef69264423f351a61cb48390c1be8673aee0f089076086aaebea7ebe268fd0aa7182695606116f679", "0xa9554c5c921c07b450ee04e34ec58e054ac1541b26ce2ce5a393367a97348ba0089f53db6660ad76b60278b66fd12e3e", "0x95097e7d2999b3e84bf052c775581cf361325325f4a50192521d8f4693c830bed667d88f482dc1e3f833aa2bd22d2cbf", "0x9014c91d0f85aefd28436b5228c12f6353c055a9326c7efbf5e071e089e2ee7c070fcbc84c5fafc336cbb8fa6fec1ca1", "0x90f57ba36ee1066b55d37384942d8b57ae00f3cf9a3c1d6a3dfee1d1af42d4b5fa9baeb0cd7e46687d1d6d090ddb931d", "0x8e4b1db12fd760a17214c9e47f1fce6e43c0dbb4589a827a13ac61aaae93759345697bb438a00edab92e0b7b62414683", "0x8022a959a513cdc0e9c705e0fc04eafd05ff37c867ae0f31f6d01cddd5df86138a426cab2ff0ac8ff03a62e20f7e8f51", "0x914e9a38829834c7360443b8ed86137e6f936389488eccf05b4b4db7c9425611705076ecb3f27105d24b85c852be7511", "0x957fb10783e2bd0db1ba66b18e794df710bc3b2b05776be146fa5863c15b1ebdd39747b1a95d9564e1772cdfc4f37b8a", "0xb6307028444daed8ed785ac9d0de76bc3fe23ff2cc7e48102553613bbfb5afe0ebe45e4212a27021c8eb870721e62a1f", "0x8f76143597777d940b15a01b39c5e1b045464d146d9a30a6abe8b5d3907250e6c7f858ff2308f8591e8b0a7b3f3c568a", "0x96163138ac0ce5fd00ae9a289648fd9300a0ca0f63a88481d703ecd281c06a52a3b5178e849e331f9c85ca4ba398f4cc", "0xa63ef47c3e18245b0482596a09f488a716df3cbd0f9e5cfabed0d742843e65db8961c556f45f49762f3a6ac8b627b3ef", "0x8cb595466552e7c4d42909f232d4063e0a663a8ef6f6c9b7ce3a0542b2459cde04e0e54c7623d404acb5b82775ac04f6", "0xb47fe69960eb45f399368807cff16d941a5a4ebad1f5ec46e3dc8a2e4d598a7e6114d8f0ca791e9720fd786070524e2b", "0x89eb5ff83eea9df490e5beca1a1fbbbbcf7184a37e2c8c91ede7a1e654c81e8cd41eceece4042ea7918a4f4646b67fd6", "0xa84f5d155ed08b9054eecb15f689ba81e44589e6e7207a99790c598962837ca99ec12344105b16641ca91165672f7153", "0xa6cc8f25c2d5b2d2f220ec359e6a37a52b95fa6af6e173c65e7cd55299eff4aa9e6d9e6f2769e6459313f1f2aecb0fab", "0xafcde944411f017a9f7979755294981e941cc41f03df5e10522ef7c7505e5f1babdd67b3bf5258e8623150062eb41d9b", "0x8fab39f39c0f40182fcd996ade2012643fe7731808afbc53f9b26900b4d4d1f0f5312d9d40b3df8baa4739970a49c732", "0xae193af9726da0ebe7df1f9ee1c4846a5b2a7621403baf8e66c66b60f523e719c30c6b4f897bb14b27d3ff3da8392eeb", "0x8ac5adb82d852eba255764029f42e6da92dcdd0e224d387d1ef94174038db9709ac558d90d7e7c57ad4ce7f89bbfc38c", "0xa2066b3458fdf678ee487a55dd5bfb74fde03b54620cb0e25412a89ee28ad0d685e309a51e3e4694be2fa6f1593a344c", "0x88d031745dd0ae07d61a15b594be5d4b2e2a29e715d081649ad63605e3404b0c3a5353f0fd9fad9c05c18e93ce674fa1", "0x8283cfb0ef743a043f2b77ecaeba3005e2ca50435585b5dd24777ee6bce12332f85e21b446b536da38508807f0f07563", "0xb376de22d5f6b0af0b59f7d9764561f4244cf8ffe22890ecd3dcf2ff1832130c9b821e068c9d8773136f4796721e5963", "0xae3afc50c764f406353965363840bf28ee85e7064eb9d5f0bb3c31c64ab10f48c853e942ee2c9b51bae59651eaa08c2f", "0x948b204d103917461a01a6c57a88f2d66b476eae5b00be20ec8c747650e864bc8a83aee0aff59cb7584b7a3387e0ee48", "0x81ab098a082b07f896c5ffd1e4446cb7fb44804cbbf38d125208b233fc82f8ec9a6a8d8dd1c9a1162dc28ffeec0dde50", "0xa149c6f1312821ced2969268789a3151bdda213451760b397139a028da609c4134ac083169feb0ee423a0acafd10eceb", "0xb0ac9e27a5dadaf523010f730b28f0ebac01f460d3bbbe277dc9d44218abb5686f4fac89ae462682fef9edbba663520a", "0x8d0e0073cca273daaaa61b6fc54bfe5a009bc3e20ae820f6c93ba77b19eca517d457e948a2de5e77678e4241807157cb", "0xad61d3a2edf7c7533a04964b97499503fd8374ca64286dba80465e68fe932e96749b476f458c6fc57cb1a7ca85764d11", "0x90eb5e121ae46bc01a30881eaa556f46bd8457a4e80787cf634aab355082de34ac57d7f497446468225f7721e68e2a47", "0x8cdac557de7c42d1f3780e33dec1b81889f6352279be81c65566cdd4952d4c15d79e656cbd46035ab090b385e90245ef", "0x82b67e61b88b84f4f4d4f65df37b3e3dcf8ec91ea1b5c008fdccd52da643adbe6468a1cfdb999e87d195afe2883a3b46", "0x8503b467e8f5d6048a4a9b78496c58493a462852cab54a70594ae3fd064cfd0deb4b8f336a262155d9fedcaa67d2f6fd", "0x8db56c5ac763a57b6ce6832930c57117058e3e5a81532b7d19346346205e2ec614eb1a2ee836ef621de50a7bc9b7f040", "0xad344699198f3c6e8c0a3470f92aaffc805b76266734414c298e10b5b3797ca53578de7ccb2f458f5e0448203f55282b", "0x80602032c43c9e2a09154cc88b83238343b7a139f566d64cb482d87436b288a98f1ea244fd3bff8da3c398686a900c14", "0xa6385bd50ecd548cfb37174cdbb89e10025b5cadaf3cff164c95d7aef5a33e3d6a9bf0c681b9e11db9ef54ebeee2a0c1", "0xabf2d95f4aa34b0581eb9257a0cc8462b2213941a5deb8ba014283293e8b36613951b61261cc67bbd09526a54cbbff76", "0xa3d5de52f48df72c289ff713e445991f142390798cd42bd9d9dbefaee4af4f5faf09042d126b975cf6b98711c3072553", "0x8e627302ff3d686cff8872a1b7c2a57b35f45bf2fc9aa42b049d8b4d6996a662b8e7cbac6597f0cb79b0cc4e29fbf133", "0x8510702e101b39a1efbf4e504e6123540c34b5689645e70d0bac1ecc1baf47d86c05cef6c4317a4e99b4edaeb53f2d00", "0xaa173f0ecbcc6088f878f8726d317748c81ebf501bba461f163b55d66099b191ec7c55f7702f351a9c8eb42cfa3280e2", "0xb560a697eafab695bcef1416648a0a664a71e311ecbe5823ae903bd0ed2057b9d7574b9a86d3fe22aa3e6ddce38ea513", "0x8df6304a3d9cf40100f3f687575419c998cd77e5cc27d579cf4f8e98642de3609af384a0337d145dd7c5635172d26a71", "0x8105c7f3e4d30a29151849673853b457c1885c186c132d0a98e63096c3774bc9deb956cf957367e633d0913680bda307", "0x95373fc22c0917c3c2044ac688c4f29a63ed858a45c0d6d2d0fe97afd6f532dcb648670594290c1c89010ecc69259bef", "0x8c2fae9bcadab341f49b55230310df93cac46be42d4caa0d42e45104148a91e527af1b4209c0d972448162aed28fab64", "0xb05a77baab70683f76209626eaefdda2d36a0b66c780a20142d23c55bd479ddd4ad95b24579384b6cf62c8eb4c92d021", "0x8e6bc6a7ea2755b4aaa19c1c1dee93811fcde514f03485fdc3252f0ab7f032c315614f6336e57cea25dcfb8fb6084eeb", "0xb656a27d06aade55eadae2ad2a1059198918ea6cc3fd22c0ed881294d34d5ac7b5e4700cc24350e27d76646263b223aa", "0xa296469f24f6f56da92d713afcd4dd606e7da1f79dc4e434593c53695847eefc81c7c446486c4b3b8c8d00c90c166f14", "0x87a326f57713ac2c9dffeb3af44b9f3c613a8f952676fc46343299122b47ee0f8d792abaa4b5db6451ced5dd153aabd0", "0xb689e554ba9293b9c1f6344a3c8fcb6951d9f9eac4a2e2df13de021aade7c186be27500e81388e5b8bcab4c80f220a31", "0x87ae0aa0aa48eac53d1ca5a7b93917de12db9e40ceabf8fdb40884ae771cfdf095411deef7c9f821af0b7070454a2608", "0xa71ffa7eae8ace94e6c3581d4cb2ad25d48cbd27edc9ec45baa2c8eb932a4773c3272b2ffaf077b40f76942a1f3af7f2", "0x94c218c91a9b73da6b7a495b3728f3028df8ad9133312fc0c03e8c5253b7ccb83ed14688fd4602e2fd41f29a0bc698bd", "0xae1e77b90ca33728af07a4c03fb2ef71cd92e2618e7bf8ed4d785ce90097fc4866c29999eb84a6cf1819d75285a03af2", "0xb7a5945b277dab9993cf761e838b0ac6eaa903d7111fca79f9fde3d4285af7a89bf6634a71909d095d7619d913972c9c", "0x8c43b37be02f39b22029b20aca31bff661abce4471dca88aa3bddefd9c92304a088b2dfc8c4795acc301ca3160656af2", "0xb32e5d0fba024554bd5fe8a793ebe8003335ddd7f585876df2048dcf759a01285fecb53daae4950ba57f3a282a4d8495", "0x85ea7fd5e10c7b659df5289b2978b2c89e244f269e061b9a15fcab7983fc1962b63546e82d5731c97ec74b6804be63ef", "0x96b89f39181141a7e32986ac02d7586088c5a9662cec39843f397f3178714d02f929af70630c12cbaba0268f8ba2d4fa", "0x929ab1a2a009b1eb37a2817c89696a06426529ebe3f306c586ab717bd34c35a53eca2d7ddcdef36117872db660024af9", "0xa696dccf439e9ca41511e16bf3042d7ec0e2f86c099e4fc8879d778a5ea79e33aa7ce96b23dc4332b7ba26859d8e674d", "0xa8fe69a678f9a194b8670a41e941f0460f6e2dbc60470ab4d6ae2679cc9c6ce2c3a39df2303bee486dbfde6844e6b31a", "0x95f58f5c82de2f2a927ca99bf63c9fc02e9030c7e46d0bf6b67fe83a448d0ae1c99541b59caf0e1ccab8326231af09a5", "0xa57badb2c56ca2c45953bd569caf22968f76ed46b9bac389163d6fe22a715c83d5e94ae8759b0e6e8c2f27bff7748f3f", "0x868726fd49963b24acb5333364dffea147e98f33aa19c7919dc9aca0fd26661cfaded74ede7418a5fadbe7f5ae67b67b", "0xa8d8550dcc64d9f1dd7bcdab236c4122f2b65ea404bb483256d712c7518f08bb028ff8801f1da6aed6cbfc5c7062e33b", "0x97e25a87dae23155809476232178538d4bc05d4ff0882916eb29ae515f2a62bfce73083466cc0010ca956aca200aeacc", "0xb4ea26be3f4bd04aa82d7c4b0913b97bcdf5e88b76c57eb1a336cbd0a3eb29de751e1bc47c0e8258adec3f17426d0c71", "0x99ee555a4d9b3cf2eb420b2af8e3bc99046880536116d0ce7193464ac40685ef14e0e3c442f604e32f8338cb0ef92558", "0x8c64efa1da63cd08f319103c5c7a761221080e74227bbc58b8fb35d08aa42078810d7af3e60446cbaff160c319535648", "0x8d9fd88040076c28420e3395cbdfea402e4077a3808a97b7939d49ecbcf1418fe50a0460e1c1b22ac3f6e7771d65169a", "0xae3c19882d7a9875d439265a0c7003c8d410367627d21575a864b9cb4918de7dbdb58a364af40c5e045f3df40f95d337", "0xb4f7bfacab7b2cafe393f1322d6dcc6f21ffe69cd31edc8db18c06f1a2b512c27bd0618091fd207ba8df1808e9d45914", "0x94f134acd0007c623fb7934bcb65ef853313eb283a889a3ffa79a37a5c8f3665f3d5b4876bc66223610c21dc9b919d37", "0xaa15f74051171daacdc1f1093d3f8e2d13da2833624b80a934afec86fc02208b8f55d24b7d66076444e7633f46375c6a", "0xa32d6bb47ef9c836d9d2371807bafbbbbb1ae719530c19d6013f1d1f813c49a60e4fa51d83693586cba3a840b23c0404", "0xb61b3599145ea8680011aa2366dc511a358b7d67672d5b0c5be6db03b0efb8ca5a8294cf220ea7409621f1664e00e631", "0x859cafc3ee90b7ececa1ed8ef2b2fc17567126ff10ca712d5ffdd16aa411a5a7d8d32c9cab1fbf63e87dce1c6e2f5f53", "0xa2fef1b0b2874387010e9ae425f3a9676d01a095d017493648bcdf3b31304b087ccddb5cf76abc4e1548b88919663b6b", "0x939e18c73befc1ba2932a65ede34c70e4b91e74cc2129d57ace43ed2b3af2a9cc22a40fbf50d79a63681b6d98852866d", "0xb3b4259d37b1b14aee5b676c9a0dd2d7f679ab95c120cb5f09f9fbf10b0a920cb613655ddb7b9e2ba5af4a221f31303c", "0x997255fe51aaca6e5a9cb3359bcbf25b2bb9e30649bbd53a8a7c556df07e441c4e27328b38934f09c09d9500b5fabf66", "0xabb91be2a2d860fd662ed4f1c6edeefd4da8dc10e79251cf87f06029906e7f0be9b486462718f0525d5e049472692cb7", "0xb2398e593bf340a15f7801e1d1fbda69d93f2a32a889ec7c6ae5e8a37567ac3e5227213c1392ee86cfb3b56ec2787839", "0x8ddf10ccdd72922bed36829a36073a460c2118fc7a56ff9c1ac72581c799b15c762cb56cb78e3d118bb9f6a7e56cb25e", "0x93e6bc0a4708d16387cacd44cf59363b994dc67d7ada7b6d6dbd831c606d975247541b42b2a309f814c1bfe205681fc6", "0xb93fc35c05998cffda2978e12e75812122831523041f10d52f810d34ff71944979054b04de0117e81ddf5b0b4b3e13c0", "0x92221631c44d60d68c6bc7b287509f37ee44cbe5fdb6935cee36b58b17c7325098f98f7910d2c3ca5dc885ad1d6dabc7", "0xa230124424a57fad3b1671f404a94d7c05f4c67b7a8fbacfccea28887b78d7c1ed40b92a58348e4d61328891cd2f6cee", "0xa6a230edb8518a0f49d7231bc3e0bceb5c2ac427f045819f8584ba6f3ae3d63ed107a9a62aad543d7e1fcf1f20605706", "0x845be1fe94223c7f1f97d74c49d682472585d8f772762baad8a9d341d9c3015534cc83d102113c51a9dea2ab10d8d27b", "0xb44262515e34f2db597c8128c7614d33858740310a49cdbdf9c8677c5343884b42c1292759f55b8b4abc4c86e4728033", "0x805592e4a3cd07c1844bc23783408310accfdb769cca882ad4d07d608e590a288b7370c2cb327f5336e72b7083a0e30f", "0x95153e8b1140df34ee864f4ca601cb873cdd3efa634af0c4093fbaede36f51b55571ab271e6a133020cd34db8411241f", "0x82878c1285cfa5ea1d32175c9401f3cc99f6bb224d622d3fd98cc7b0a27372f13f7ab463ce3a33ec96f9be38dbe2dfe3", "0xb7588748f55783077c27fc47d33e20c5c0f5a53fc0ac10194c003aa09b9f055d08ec971effa4b7f760553997a56967b3", "0xb36b4de6d1883b6951f59cfae381581f9c6352fcfcf1524fccdab1571a20f80441d9152dc6b48bcbbf00371337ca0bd5", "0x89c5523f2574e1c340a955cbed9c2f7b5fbceb260cb1133160dabb7d41c2f613ec3f6e74bbfab3c4a0a6f0626dbe068f", "0xa52f58cc39f968a9813b1a8ddc4e83f4219e4dd82c7aa1dd083bea7edf967151d635aa9597457f879771759b876774e4", "0x8300a67c2e2e123f89704abfde095463045dbd97e20d4c1157bab35e9e1d3d18f1f4aaba9cbe6aa2d544e92578eaa1b6", "0xac6a7f2918768eb6a43df9d3a8a04f8f72ee52f2e91c064c1c7d75cad1a3e83e5aba9fe55bb94f818099ac91ccf2e961", "0x8d64a2b0991cf164e29835c8ddef6069993a71ec2a7de8157bbfa2e00f6367be646ed74cbaf524f0e9fe13fb09fa15fd", "0x8b2ffe5a545f9f680b49d0a9797a4a11700a2e2e348c34a7a985fc278f0f12def6e06710f40f9d48e4b7fbb71e072229", "0x8ab8f71cd337fa19178924e961958653abf7a598e3f022138b55c228440a2bac4176cea3aea393549c03cd38a13eb3fc", "0x8419d28318c19ea4a179b7abb43669fe96347426ef3ac06b158d79c0acf777a09e8e770c2fb10e14b3a0421705990b23", "0x8bacdac310e1e49660359d0a7a17fe3d334eb820e61ae25e84cb52f863a2f74cbe89c2e9fc3283745d93a99b79132354", "0xb57ace3fa2b9f6b2db60c0d861ace7d7e657c5d35d992588aeed588c6ce3a80b6f0d49f8a26607f0b17167ab21b675e4", "0x83e265cde477f2ecc164f49ddc7fb255bb05ff6adc347408353b7336dc3a14fdedc86d5a7fb23f36b8423248a7a67ed1", "0xa60ada971f9f2d79d436de5d3d045f5ab05308cae3098acaf5521115134b2a40d664828bb89895840db7f7fb499edbc5", "0xa63eea12efd89b62d3952bf0542a73890b104dd1d7ff360d4755ebfa148fd62de668edac9eeb20507967ea37fb220202", "0xa0275767a270289adc991cc4571eff205b58ad6d3e93778ddbf95b75146d82517e8921bd0d0564e5b75fa0ccdab8e624", "0xb9b03fd3bf07201ba3a039176a965d736b4ef7912dd9e9bf69fe1b57c330a6aa170e5521fe8be62505f3af81b41d7806", "0xa95f640e26fb1106ced1729d6053e41a16e4896acac54992279ff873e5a969aad1dcfa10311e28b8f409ac1dab7f03bb", "0xb144778921742418053cb3c70516c63162c187f00db2062193bb2c14031075dbe055d020cde761b26e8c58d0ea6df2c1", "0x8432fbb799e0435ef428d4fefc309a05dd589bce74d7a87faf659823e8c9ed51d3e42603d878e80f439a38be4321c2fa", "0xb08ddef14e42d4fd5d8bf39feb7485848f0060d43b51ed5bdda39c05fe154fb111d29719ee61a23c392141358c0cfcff", "0x8ae3c5329a5e025b86b5370e06f5e61177df4bda075856fade20a17bfef79c92f54ed495f310130021ba94fb7c33632b", "0x92b6d3c9444100b4d7391febfc1dddaa224651677c3695c47a289a40d7a96d200b83b64e6d9df51f534564f272a2c6c6", "0xb432bc2a3f93d28b5e506d68527f1efeb2e2570f6be0794576e2a6ef9138926fdad8dd2eabfa979b79ab7266370e86bc", "0x8bc315eacedbcfc462ece66a29662ca3dcd451f83de5c7626ef8712c196208fb3d8a0faf80b2e80384f0dd9772f61a23", "0xa72375b797283f0f4266dec188678e2b2c060dfed5880fc6bb0c996b06e91a5343ea2b695adaab0a6fd183b040b46b56", "0xa43445036fbaa414621918d6a897d3692fdae7b2961d87e2a03741360e45ebb19fcb1703d23f1e15bb1e2babcafc56ac", "0xb9636b2ffe305e63a1a84bd44fb402442b1799bd5272638287aa87ca548649b23ce8ce7f67be077caed6aa2dbc454b78", "0x99a30bf0921d854c282b83d438a79f615424f28c2f99d26a05201c93d10378ab2cd94a792b571ddae5d4e0c0013f4006", "0x8648e3c2f93d70b392443be116b48a863e4b75991bab5db656a4ef3c1e7f645e8d536771dfe4e8d1ceda3be8d32978b0", "0xab50dc9e6924c1d2e9d2e335b2d679fc7d1a7632e84964d3bac0c9fe57e85aa5906ec2e7b0399d98ddd022e9b19b5904", "0xab729328d98d295f8f3272afaf5d8345ff54d58ff9884da14f17ecbdb7371857fdf2f3ef58080054e9874cc919b46224", "0x83fa5da7592bd451cad3ad7702b4006332b3aae23beab4c4cb887fa6348317d234bf62a359e665b28818e5410c278a09", "0x8bdbff566ae9d368f114858ef1f009439b3e9f4649f73efa946e678d6c781d52c69af195df0a68170f5f191b2eac286b", "0x91245e59b4425fd4edb2a61d0d47c1ccc83d3ced8180de34887b9655b5dcda033d48cde0bdc3b7de846d246c053a02e8", "0xa2cb00721e68f1cad8933947456f07144dc69653f96ceed845bd577d599521ba99cdc02421118971d56d7603ed118cbf", "0xaf8cd66d303e808b22ec57860dd909ca64c27ec2c60e26ffecfdc1179d8762ffd2739d87b43959496e9fee4108df71df", "0x9954136812dffcd5d3f167a500e7ab339c15cfc9b3398d83f64b0daa3dd5b9a851204f424a3493b4e326d3de81e50a62", "0x93252254d12511955f1aa464883ad0da793f84d900fea83e1df8bca0f2f4cf5b5f9acbaec06a24160d33f908ab5fea38", "0x997cb55c26996586ba436a95566bd535e9c22452ca5d2a0ded2bd175376557fa895f9f4def4519241ff386a063f2e526", "0xa12c78ad451e0ac911260ade2927a768b50cb4125343025d43474e7f465cdc446e9f52a84609c5e7e87ae6c9b3f56cda", "0xa789d4ca55cbba327086563831b34487d63d0980ba8cf55197c016702ed6da9b102b1f0709ce3da3c53ff925793a3d73", "0xa5d76acbb76741ce85be0e655b99baa04f7f587347947c0a30d27f8a49ae78cce06e1cde770a8b618d3db402be1c0c4b", "0x873c0366668c8faddb0eb7c86f485718d65f8c4734020f1a18efd5fa123d3ea8a990977fe13592cd01d17e60809cb5ff", "0xb659b71fe70f37573ff7c5970cc095a1dc0da3973979778f80a71a347ef25ad5746b2b9608bad4ab9a4a53a4d7df42d7", "0xa34cbe05888e5e5f024a2db14cb6dcdc401a9cbd13d73d3c37b348f68688f87c24ca790030b8f84fef9e74b4eab5e412", "0x94ce8010f85875c045b0f014db93ef5ab9f1f6842e9a5743dce9e4cb872c94affd9e77c1f1d1ab8b8660b52345d9acb9", "0xadefa9b27a62edc0c5b019ddd3ebf45e4de846165256cf6329331def2e088c5232456d3de470fdce3fa758bfdd387512", "0xa6b83821ba7c1f83cc9e4529cf4903adb93b26108e3d1f20a753070db072ad5a3689643144bdd9c5ea06bb9a7a515cd0", "0xa3a9ddedc2a1b183eb1d52de26718151744db6050f86f3580790c51d09226bf05f15111691926151ecdbef683baa992c", "0xa64bac89e7686932cdc5670d07f0b50830e69bfb8c93791c87c7ffa4913f8da881a9d8a8ce8c1a9ce5b6079358c54136", "0xa77b5a63452cb1320b61ab6c7c2ef9cfbcade5fd4727583751fb2bf3ea330b5ca67757ec1f517bf4d503ec924fe32fbd", "0x8746fd8d8eb99639d8cd0ca34c0d9c3230ed5a312aab1d3d925953a17973ee5aeb66e68667e93caf9cb817c868ea8f3d", "0x88a2462a26558fc1fbd6e31aa8abdc706190a17c27fdc4217ffd2297d1b1f3321016e5c4b2384c5454d5717dc732ed03", "0xb78893a97e93d730c8201af2e0d3b31cb923d38dc594ffa98a714e627c473d42ea82e0c4d2eeb06862ee22a9b2c54588", "0x920cc8b5f1297cf215a43f6fc843e379146b4229411c44c0231f6749793d40f07b9af7699fd5d21fd69400b97febe027", "0xa0f0eafce1e098a6b58c7ad8945e297cd93aaf10bc55e32e2e32503f02e59fc1d5776936577d77c0b1162cb93b88518b", "0x98480ba0064e97a2e7a6c4769b4d8c2a322cfc9a3b2ca2e67e9317e2ce04c6e1108169a20bd97692e1cb1f1423b14908", "0x83dbbb2fda7e287288011764a00b8357753a6a44794cc8245a2275237f11affdc38977214e463ad67aec032f3dfa37e9", "0x86442fff37598ce2b12015ff19b01bb8a780b40ad353d143a0f30a06f6d23afd5c2b0a1253716c855dbf445cc5dd6865", "0xb8a4c60c5171189414887847b9ed9501bff4e4c107240f063e2d254820d2906b69ef70406c585918c4d24f1dd052142b", "0x919f33a98e84015b2034b57b5ffe9340220926b2c6e45f86fd79ec879dbe06a148ae68b77b73bf7d01bd638a81165617", "0x95c13e78d89474a47fbc0664f6f806744b75dede95a479bbf844db4a7f4c3ae410ec721cb6ffcd9fa9c323da5740d5ae", "0xab7151acc41fffd8ec6e90387700bcd7e1cde291ea669567295bea1b9dd3f1df2e0f31f3588cd1a1c08af8120aca4921", "0x80e74c5c47414bd6eeef24b6793fb1fa2d8fb397467045fcff887c52476741d5bc4ff8b6d3387cb53ad285485630537f", "0xa296ad23995268276aa351a7764d36df3a5a3cffd7dbeddbcea6b1f77adc112629fdeffa0918b3242b3ccd5e7587e946", "0x813d2506a28a2b01cb60f49d6bd5e63c9b056aa56946faf2f33bd4f28a8d947569cfead3ae53166fc65285740b210f86", "0x924b265385e1646287d8c09f6c855b094daaee74b9e64a0dddcf9ad88c6979f8280ba30c8597b911ef58ddb6c67e9fe3", "0x8d531513c70c2d3566039f7ca47cd2352fd2d55b25675a65250bdb8b06c3843db7b2d29c626eed6391c238fc651cf350", "0x82b338181b62fdc81ceb558a6843df767b6a6e3ceedc5485664b4ea2f555904b1a45fbb35f6cf5d96f27da10df82a325", "0x92e62faaedea83a37f314e1d3cb4faaa200178371d917938e59ac35090be1db4b4f4e0edb78b9c991de202efe4f313d8", "0x99d645e1b642c2dc065bac9aaa0621bc648c9a8351efb6891559c3a41ba737bd155fb32d7731950514e3ecf4d75980e4", "0xb34a13968b9e414172fb5d5ece9a39cf2eb656128c3f2f6cc7a9f0c69c6bae34f555ecc8f8837dc34b5e470e29055c78", "0xa2a0bb7f3a0b23a2cbc6585d59f87cd7e56b2bbcb0ae48f828685edd9f7af0f5edb4c8e9718a0aaf6ef04553ba71f3b7", "0x8e1a94bec053ed378e524b6685152d2b52d428266f2b6eadd4bcb7c4e162ed21ab3e1364879673442ee2162635b7a4d8", "0x9944adaff14a85eab81c73f38f386701713b52513c4d4b838d58d4ffa1d17260a6d056b02334850ea9a31677c4b078bd", "0xa450067c7eceb0854b3eca3db6cf38669d72cb7143c3a68787833cbca44f02c0be9bfbe082896f8a57debb13deb2afb1", "0x8be4ad3ac9ef02f7df09254d569939757101ee2eda8586fefcd8c847adc1efe5bdcb963a0cafa17651befaafb376a531", "0x90f6de91ea50255f148ac435e08cf2ac00c772a466e38155bd7e8acf9197af55662c7b5227f88589b71abe9dcf7ba343", "0x86e5a24f0748b106dee2d4d54e14a3b0af45a96cbee69cac811a4196403ebbee17fd24946d7e7e1b962ac7f66dbaf610", "0xafdd96fbcda7aa73bf9eeb2292e036c25753d249caee3b9c013009cc22e10d3ec29e2aa6ddbb21c4e949b0c0bccaa7f4", "0xb5a4e7436d5473647c002120a2cb436b9b28e27ad4ebdd7c5f122b91597c507d256d0cbd889d65b3a908531936e53053", "0xb632414c3da704d80ac2f3e5e0e9f18a3637cdc2ebeb613c29300745582427138819c4e7b0bec3099c1b8739dac1807b", "0xa28df1464d3372ce9f37ef1db33cc010f752156afae6f76949d98cd799c0cf225c20228ae86a4da592d65f0cffe3951b", "0x898b93d0a31f7d3f11f253cb7a102db54b669fd150da302d8354d8e02b1739a47cb9bd88015f3baf12b00b879442464e", "0x96fb88d89a12049091070cb0048a381902965e67a8493e3991eaabe5d3b7ff7eecd5c94493a93b174df3d9b2c9511755", "0xb899cb2176f59a5cfba3e3d346813da7a82b03417cad6342f19cc8f12f28985b03bf031e856a4743fd7ebe16324805b0", "0xa60e2d31bc48e0c0579db15516718a03b73f5138f15037491f4dae336c904e312eda82d50862f4debd1622bb0e56d866", "0x979fc8b987b5cef7d4f4b58b53a2c278bd25a5c0ea6f41c715142ea5ff224c707de38451b0ad3aa5e749aa219256650a", "0xb2a75bff18e1a6b9cf2a4079572e41205741979f57e7631654a3c0fcec57c876c6df44733c9da3d863db8dff392b44a3", "0xb7a0f0e811222c91e3df98ff7f286b750bc3b20d2083966d713a84a2281744199e664879401e77470d44e5a90f3e5181", "0x82b74ba21c9d147fbc338730e8f1f8a6e7fc847c3110944eb17a48bea5e06eecded84595d485506d15a3e675fd0e5e62", "0xa7f44eef817d5556f0d1abcf420301217d23c69dd2988f44d91ea1f1a16c322263cbacd0f190b9ba22b0f141b9267b4f", "0xaadb68164ede84fc1cb3334b3194d84ba868d5a88e4c9a27519eef4923bc4abf81aab8114449496c073c2a6a0eb24114", "0xb5378605fabe9a8c12a5dc55ef2b1de7f51aedb61960735c08767a565793cea1922a603a6983dc25f7cea738d0f7c40d", "0xa97a4a5cd8d51302e5e670aee78fe6b5723f6cc892902bbb4f131e82ca1dfd5de820731e7e3367fb0c4c1922a02196e3", "0x8bdfeb15c29244d4a28896f2b2cb211243cd6a1984a3f5e3b0ebe5341c419beeab3304b390a009ffb47588018034b0ea", "0xa9af3022727f2aa2fca3b096968e97edad3f08edcbd0dbca107b892ae8f746a9c0485e0d6eb5f267999b23a845923ed0", "0x8e7594034feef412f055590fbb15b6322dc4c6ab7a4baef4685bd13d71a83f7d682b5781bdfa0d1c659489ce9c2b8000", "0x84977ca6c865ebee021c58106c1a4ad0c745949ecc5332948002fd09bd9b890524878d0c29da96fd11207621136421fe", "0x8687551a79158e56b2375a271136756313122132a6670fa51f99a1b5c229ed8eea1655a734abae13228b3ebfd2a825dd", "0xa0227d6708979d99edfc10f7d9d3719fd3fc68b0d815a7185b60307e4c9146ad2f9be2b8b4f242e320d4288ceeb9504c", "0x89f75583a16735f9dd8b7782a130437805b34280ccea8dac6ecaee4b83fe96947e7b53598b06fecfffdf57ffc12cc445", "0xa0056c3353227f6dd9cfc8e3399aa5a8f1d71edf25d3d64c982910f50786b1e395c508d3e3727ac360e3e040c64b5298", "0xb070e61a6d813626144b312ded1788a6d0c7cec650a762b2f8df6e4743941dd82a2511cd956a3f141fc81e15f4e092da", "0xb4e6db232e028a1f989bb5fc13416711f42d389f63564d60851f009dcffac01acfd54efa307aa6d4c0f932892d4e62b0", "0x89b5991a67db90024ddd844e5e1a03ef9b943ad54194ae0a97df775dde1addf31561874f4e40fbc37a896630f3bbda58", "0xad0e8442cb8c77d891df49cdb9efcf2b0d15ac93ec9be1ad5c3b3cca1f4647b675e79c075335c1f681d56f14dc250d76", "0xb5d55a6ae65bb34dd8306806cb49b5ccb1c83a282ee47085cf26c4e648e19a52d9c422f65c1cd7e03ca63e926c5e92ea", "0xb749501347e5ec07e13a79f0cb112f1b6534393458b3678a77f02ca89dca973fa7b30e55f0b25d8b92b97f6cb0120056", "0x94144b4a3ffc5eec6ba35ce9c245c148b39372d19a928e236a60e27d7bc227d18a8cac9983851071935d8ffb64b3a34f", "0x92bb4f9f85bc8c028a3391306603151c6896673135f8a7aefedd27acb322c04ef5dac982fc47b455d6740023e0dd3ea3", "0xb9633a4a101461a782fc2aa092e9dbe4e2ad00987578f18cd7cf0021a909951d60fe79654eb7897806795f93c8ff4d1c", "0x809f0196753024821b48a016eca5dbb449a7c55750f25981bb7a4b4c0e0846c09b8f6128137905055fc43a3f0deb4a74", "0xa27dc9cdd1e78737a443570194a03d89285576d3d7f3a3cf15cc55b3013e42635d4723e2e8fe1d0b274428604b630db9", "0x861f60f0462e04cd84924c36a28163def63e777318d00884ab8cb64c8df1df0bce5900342163edb60449296484a6c5bf", "0xb7bc23fb4e14af4c4704a944253e760adefeca8caee0882b6bbd572c84434042236f39ae07a8f21a560f486b15d82819", "0xb9a6eb492d6dd448654214bd01d6dc5ff12067a11537ab82023fc16167507ee25eed2c91693912f4155d1c07ed9650b3", "0x97678af29c68f9a5e213bf0fb85c265303714482cfc4c2c00b4a1e8a76ed08834ee6af52357b143a1ca590fb0265ea5a", "0x8a15b499e9eca5b6cac3070b5409e8296778222018ad8b53a5d1f6b70ad9bb10c68a015d105c941ed657bf3499299e33", "0xb487fefede2e8091f2c7bfe85770db2edff1db83d4effe7f7d87bff5ab1ace35e9b823a71adfec6737fede8d67b3c467", "0x8b51b916402aa2c437fce3bcad6dad3be8301a1a7eab9d163085b322ffb6c62abf28637636fe6114573950117fc92898", "0xb06a2106d031a45a494adec0881cb2f82275dff9dcdd2bc16807e76f3bec28a6734edd3d54f0be8199799a78cd6228ad", "0xaf0a185391bbe2315eb97feac98ad6dd2e5d931d012c621abd6e404a31cc188b286fef14871762190acf086482b2b5e2", "0x8e78ee8206506dd06eb7729e32fceda3bebd8924a64e4d8621c72e36758fda3d0001af42443851d6c0aea58562870b43", "0xa1ba52a569f0461aaf90b49b92be976c0e73ec4a2c884752ee52ffb62dd137770c985123d405dfb5de70692db454b54a", "0x8d51b692fa1543c51f6b62b9acb8625ed94b746ef96c944ca02859a4133a5629da2e2ce84e111a7af8d9a5b836401c64", "0xa7a20d45044cf6492e0531d0b8b26ffbae6232fa05a96ed7f06bdb64c2b0f5ca7ec59d5477038096a02579e633c7a3ff", "0x84df867b98c53c1fcd4620fef133ee18849c78d3809d6aca0fb6f50ff993a053a455993f216c42ab6090fa5356b8d564", "0xa7227c439f14c48e2577d5713c97a5205feb69acb0b449152842e278fa71e8046adfab468089c8b2288af1fc51fa945b", "0x855189b3a105670779997690876dfaa512b4a25a24931a912c2f0f1936971d2882fb4d9f0b3d9daba77eaf660e9d05d5", "0xb5696bd6706de51c502f40385f87f43040a5abf99df705d6aac74d88c913b8ecf7a99a63d7a37d9bdf3a941b9e432ff5", "0xab997beb0d6df9c98d5b49864ef0b41a2a2f407e1687dfd6089959757ba30ed02228940b0e841afe6911990c74d536c4", "0xb36b65f85546ebfdbe98823d5555144f96b4ab39279facd19c0de3b8919f105ba0315a0784dce4344b1bc62d8bb4a5a3", "0xb8371f0e4450788720ac5e0f6cd3ecc5413d33895083b2c168d961ec2b5c3de411a4cc0712481cbe8df8c2fa1a7af006", "0x98325d8026b810a8b7a114171ae59a57e8bbc9848e7c3df992efc523621729fd8c9f52114ce01d7730541a1ada6f1df1", "0x8d0e76dbd37806259486cd9a31bc8b2306c2b95452dc395546a1042d1d17863ef7a74c636b782e214d3aa0e8d717f94a", "0xa4e15ead76da0214d702c859fb4a8accdcdad75ed08b865842bd203391ec4cba2dcc916455e685f662923b96ee0c023f", "0x8618190972086ebb0c4c1b4a6c94421a13f378bc961cc8267a301de7390c5e73c3333864b3b7696d81148f9d4843fd02", "0x85369d6cc7342e1aa15b59141517d8db8baaaeb7ab9670f3ba3905353948d575923d283b7e5a05b13a30e7baf1208a86", "0x87c51ef42233c24a6da901f28c9a075d9ba3c625687c387ad6757b72ca6b5a8885e6902a3082da7281611728b1e45f26", "0xaa6348a4f71927a3106ad0ea8b02fc8d8c65531e4ab0bd0a17243e66f35afe252e40ab8eef9f13ae55a72566ffdaff5c", "0x96a3bc976e9d03765cc3fee275fa05b4a84c94fed6b767e23ca689394501e96f56f7a97cffddc579a6abff632bf153be", "0x97dbf96c6176379fdb2b888be4e757b2bca54e74124bd068d3fa1dbd82a011bbeb75079da38e0cd22a761fe208ecad9b", "0xb70cf0a1d14089a4129ec4e295313863a59da8c7e26bf74cc0e704ed7f0ee4d7760090d0ddf7728180f1bf2c5ac64955", "0x882d664714cc0ffe53cbc9bef21f23f3649824f423c4dbad1f893d22c4687ab29583688699efc4d5101aa08b0c3e267a", "0x80ecb7cc963e677ccaddbe3320831dd6ee41209acf4ed41b16dc4817121a3d86a1aac9c4db3d8c08a55d28257088af32", "0xa25ba667d832b145f9ce18c3f9b1bd00737aa36db020e1b99752c8ef7d27c6c448982bd8d352e1b6df266b8d8358a8d5", "0x83734841c13dee12759d40bdd209b277e743b0d08cc0dd1e0b7afd2d65bfa640400eefcf6be4a52e463e5b3d885eeac6", "0x848d16505b04804afc773aebabb51b36fd8aacfbb0e09b36c0d5d57df3c0a3b92f33e7d5ad0a7006ec46ebb91df42b8c", "0x909a8d793f599e33bb9f1dc4792a507a97169c87cd5c087310bc05f30afcd247470b4b56dec59894c0fb1d48d39bb54e", "0x8e558a8559df84a1ba8b244ece667f858095c50bb33a5381e60fcc6ba586b69693566d8819b4246a27287f16846c1dfa", "0x84d6b69729f5aaa000cd710c2352087592cfbdf20d5e1166977e195818e593fa1a50d1e04566be23163a2523dc1612f1", "0x9536d262b7a42125d89f4f32b407d737ba8d9242acfc99d965913ab3e043dcac9f7072a43708553562cac4cba841df30", "0x9598548923ca119d6a15fd10861596601dd1dedbcccca97bb208cdc1153cf82991ea8cc17686fbaa867921065265970c", "0xb87f2d4af6d026e4d2836bc3d390a4a18e98a6e386282ce96744603bab74974272e97ac2da281afa21885e2cbb3a8001", "0x991ece62bf07d1a348dd22191868372904b9f8cf065ae7aa4e44fd24a53faf6d851842e35fb472895963aa1992894918", "0xa8c53dea4c665b30e51d22ca6bc1bc78aaf172b0a48e64a1d4b93439b053877ec26cb5221c55efd64fa841bbf7d5aff4", "0x93487ec939ed8e740f15335b58617c3f917f72d07b7a369befd479ae2554d04deb240d4a14394b26192efae4d2f4f35d", "0xa44793ab4035443f8f2968a40e043b4555960193ffa3358d22112093aadfe2c136587e4139ffd46d91ed4107f61ea5e0", "0xb13fe033da5f0d227c75927d3dacb06dbaf3e1322f9d5c7c009de75cdcba5e308232838785ab69a70f0bedea755e003f", "0x970a29b075faccd0700fe60d1f726bdebf82d2cc8252f4a84543ebd3b16f91be42a75c9719a39c4096139f0f31393d58", "0xa4c3eb1f7160f8216fc176fb244df53008ff32f2892363d85254002e66e2de21ccfe1f3b1047589abee50f29b9d507e3", "0x8c552885eab04ba40922a8f0c3c38c96089c95ff1405258d3f1efe8d179e39e1295cbf67677894c607ae986e4e6b1fb0", "0xb3671746fa7f848c4e2ae6946894defadd815230b906b419143523cc0597bc1d6c0a4c1e09d49b66b4a2c11cde3a4de3", "0x937a249a95813a5e2ef428e355efd202e15a37d73e56cfb7e57ea9f943f2ce5ca8026f2f1fd25bf164ba89d07077d858", "0x83646bdf6053a04aa9e2f112499769e5bd5d0d10f2e13db3ca89bd45c0b3b7a2d752b7d137fb3909f9c62b78166c9339", "0xb4eac4b91e763666696811b7ed45e97fd78310377ebea1674b58a2250973f80492ac35110ed1240cd9bb2d17493d708c", "0x82db43a99bc6573e9d92a3fd6635dbbb249ac66ba53099c3c0c8c8080b121dd8243cd5c6e36ba0a4d2525bae57f5c89c", "0xa64d6a264a681b49d134c655d5fc7756127f1ee7c93d328820f32bca68869f53115c0d27fef35fe71f7bc4fdaed97348", "0x8739b7a9e2b4bc1831e7f04517771bc7cde683a5e74e052542517f8375a2f64e53e0d5ac925ef722327e7bb195b4d1d9", "0x8f337cdd29918a2493515ebb5cf702bbe8ecb23b53c6d18920cc22f519e276ca9b991d3313e2d38ae17ae8bdfa4f8b7e", "0xb0edeab9850e193a61f138ef2739fc42ceec98f25e7e8403bfd5fa34a7bc956b9d0898250d18a69fa4625a9b3d6129da", "0xa9920f26fe0a6d51044e623665d998745c9eca5bce12051198b88a77d728c8238f97d4196f26e43b24f8841500b998d0", "0x86e655d61502b979eeeeb6f9a7e1d0074f936451d0a1b0d2fa4fb3225b439a3770767b649256fe481361f481a8dbc276", "0x84d3b32fa62096831cc3bf013488a9f3f481dfe293ae209ed19585a03f7db8d961a7a9dd0db82bd7f62d612707575d9c", "0x81c827826ec9346995ffccf62a241e3b2d32f7357acd1b1f8f7a7dbc97022d3eb51b8a1230e23ce0b401d2e535e8cd78", "0x94a1e40c151191c5b055b21e86f32e69cbc751dcbdf759a48580951834b96a1eed75914c0d19a38aefd21fb6c8d43d0c", "0xab890222b44bc21b71f7c75e15b6c6e16bb03371acce4f8d4353ff3b8fcd42a14026589c5ed19555a3e15e4d18bfc3a3", "0xaccb0be851e93c6c8cc64724cdb86887eea284194b10e7a43c90528ed97e9ec71ca69c6fac13899530593756dd49eab2", "0xb630220aa9e1829c233331413ee28c5efe94ea8ea08d0c6bfd781955078b43a4f92915257187d8526873e6c919c6a1de", "0xadd389a4d358c585f1274b73f6c3c45b58ef8df11f9d11221f620e241bf3579fba07427b288c0c682885a700cc1fa28d", "0xa9fe6ca8bf2961a3386e8b8dcecc29c0567b5c0b3bcf3b0f9169f88e372b80151af883871fc5229815f94f43a6f5b2b0", "0xad839ae003b92b37ea431fa35998b46a0afc3f9c0dd54c3b3bf7a262467b13ff3c323ada1c1ae02ac7716528bdf39e3e", "0x9356d3fd0edcbbb65713c0f2a214394f831b26f792124b08c5f26e7f734b8711a87b7c4623408da6a091c9aef1f6af3c", "0x896b25b083c35ac67f0af3784a6a82435b0e27433d4d74cd6d1eafe11e6827827799490fb1c77c11de25f0d75f14e047", "0x8bfa019391c9627e8e5f05c213db625f0f1e51ec68816455f876c7e55b8f17a4f13e5aae9e3fb9e1cf920b1402ee2b40", "0x8ba3a6faa6a860a8f3ce1e884aa8769ceded86380a86520ab177ab83043d380a4f535fe13884346c5e51bee68da6ab41", "0xa8292d0844084e4e3bb7af92b1989f841a46640288c5b220fecfad063ee94e86e13d3d08038ec2ac82f41c96a3bfe14d", "0x8229bb030b2fc566e11fd33c7eab7a1bb7b49fed872ea1f815004f7398cb03b85ea14e310ec19e1f23e0bdaf60f8f76c", "0x8cfbf869ade3ec551562ff7f63c2745cc3a1f4d4dc853a0cd42dd5f6fe54228f86195ea8fe217643b32e9f513f34a545", "0xac52a3c8d3270ddfe1b5630159da9290a5ccf9ccbdef43b58fc0a191a6c03b8a5974cf6e2bbc7bd98d4a40a3581482d7", "0xab13decb9e2669e33a7049b8eca3ca327c40dea15ad6e0e7fa63ed506db1d258bc36ac88b35f65cae0984e937eb6575d", "0xb5e748eb1a7a1e274ff0cc56311c198f2c076fe4b7e73e5f80396fe85358549df906584e6bb2c8195b3e2be7736850a5", "0xb5cb911325d8f963c41f691a60c37831c7d3bbd92736efa33d1f77a22b3fde7f283127256c2f47e197571e6fe0b46149", "0x8a01dc6ed1b55f26427a014faa347130738b191a06b800e32042a46c13f60b49534520214359d68eb2e170c31e2b8672", "0xa72fa874866e19b2efb8e069328362bf7921ec375e3bcd6b1619384c3f7ee980f6cf686f3544e9374ff54b4d17a1629c", "0x8db21092f7c5f110fba63650b119e82f4b42a997095d65f08f8237b02dd66fdf959f788df2c35124db1dbd330a235671", "0x8c65d50433d9954fe28a09fa7ba91a70a590fe7ba6b3060f5e4be0f6cef860b9897fa935fb4ebc42133524eb071dd169", "0xb4614058e8fa21138fc5e4592623e78b8982ed72aa35ee4391b164f00c68d277fa9f9eba2eeefc890b4e86eba5124591", "0xab2ad3a1bce2fbd55ca6b7c23786171fe1440a97d99d6df4d80d07dd56ac2d7203c294b32fc9e10a6c259381a73f24a1", "0x812ae3315fdc18774a8da3713a4679e8ed10b9405edc548c00cacbe25a587d32040566676f135e4723c5dc25df5a22e9", "0xa464b75f95d01e5655b54730334f443c8ff27c3cb79ec7af4b2f9da3c2039c609908cd128572e1fd0552eb597e8cef8d", "0xa0db3172e93ca5138fe419e1c49a1925140999f6eff7c593e5681951ee0ec1c7e454c851782cbd2b8c9bc90d466e90e0", "0x806db23ba7d00b87d544eed926b3443f5f9c60da6b41b1c489fba8f73593b6e3b46ebfcab671ee009396cd77d5e68aa1", "0x8bfdf2c0044cc80260994e1c0374588b6653947b178e8b312be5c2a05e05767e98ea15077278506aee7df4fee1aaf89e", "0x827f6558c16841b5592ff089c9c31e31eb03097623524394813a2e4093ad2d3f8f845504e2af92195aaa8a1679d8d692", "0x925c4f8eab2531135cd71a4ec88e7035b5eea34ba9d799c5898856080256b4a15ed1a746e002552e2a86c9c157e22e83", "0xa9f9a368f0e0b24d00a35b325964c85b69533013f9c2cfad9708be5fb87ff455210f8cb8d2ce3ba58ca3f27495552899", "0x8ac0d3bebc1cae534024187e7c71f8927ba8fcc6a1926cb61c2b6c8f26bb7831019e635a376146c29872a506784a4aaa", "0x97c577be2cbbfdb37ad754fae9df2ada5fc5889869efc7e18a13f8e502fbf3f4067a509efbd46fd990ab47ce9a70f5a8", "0x935e7d82bca19f16614aa43b4a3474e4d20d064e4bfdf1cea2909e5c9ab72cfe3e54dc50030e41ee84f3588cebc524e9", "0x941aafc08f7c0d94cebfbb1f0aad5202c02e6e37f2c12614f57e727efa275f3926348f567107ee6d8914dd71e6060271", "0xaf0fbc1ba05b4b5b63399686df3619968be5d40073de0313cbf5f913d3d4b518d4c249cdd2176468ccaa36040a484f58", "0xa0c414f23f46ca6d69ce74c6f8a00c036cb0edd098af0c1a7d39c802b52cfb2d5dbdf93fb0295453d4646e2af7954d45", "0x909cf39e11b3875bb63b39687ae1b5d1f5a15445e39bf164a0b14691b4ddb39a8e4363f584ef42213616abc4785b5d66", "0xa92bac085d1194fbd1c88299f07a061d0bdd3f980b663e81e6254dbb288bf11478c0ee880e28e01560f12c5ccb3c0103", "0x841705cd5cd76b943e2b7c5e845b9dd3c8defe8ef67e93078d6d5e67ade33ad4b0fd413bc196f93b0a4073c855cd97d4", "0x8e7eb8364f384a9161e81d3f1d52ceca9b65536ae49cc35b48c3e2236322ba4ae9973e0840802d9fa4f4d82ea833544f", "0xaed3ab927548bc8bec31467ba80689c71a168e34f50dcb6892f19a33a099f5aa6b3f9cb79f5c0699e837b9a8c7f27efe", "0xb8fbf7696210a36e20edabd77839f4dfdf50d6d015cdf81d587f90284a9bcef7d2a1ff520728d7cc69a4843d6c20dedd", "0xa9d533769ce6830211c884ae50a82a7bf259b44ac71f9fb11f0296fdb3981e6b4c1753fe744647b247ebc433a5a61436", "0x8b4bdf90d33360b7f428c71cde0a49fb733badba8c726876945f58c620ce7768ae0e98fc8c31fa59d8955a4823336bb1", "0x808d42238e440e6571c59e52a35ae32547d502dc24fd1759d8ea70a7231a95859baf30b490a4ba55fa2f3aaa11204597", "0x85594701f1d2fee6dc1956bc44c7b31db93bdeec2f3a7d622c1a08b26994760773e3d57521a44cfd7e407ac3fd430429", "0xa66de045ce7173043a6825e9dc440ac957e2efb6df0a337f4f8003eb0c719d873a52e6eba3cb0d69d977ca37d9187674", "0x87a1c6a1fdff993fa51efa5c3ba034c079c0928a7d599b906336af7c2dcab9721ceaf3108c646490af9dff9a754f54b3", "0x926424223e462ceb75aed7c22ade8a7911a903b7e5dd4bc49746ddce8657f4616325cd12667d4393ac52cdd866396d0e", "0xb5dc96106593b42b30f06f0b0a1e0c1aafc70432e31807252d3674f0b1ea5e58eac8424879d655c9488d85a879a3e572", "0x997ca0987735cc716507cb0124b1d266d218b40c9d8e0ecbf26a1d65719c82a637ce7e8be4b4815d307df717bde7c72a", "0x92994d3f57a569b7760324bb5ae4e8e14e1633d175dab06aa57b8e391540e05f662fdc08b8830f489a063f59b689a688", "0xa8087fcc6aa4642cb998bea11facfe87eb33b90a9aa428ab86a4124ad032fc7d2e57795311a54ec9f55cc120ebe42df1", "0xa9bd7d1de6c0706052ca0b362e2e70e8c8f70f1f026ea189b4f87a08ce810297ebfe781cc8004430776c54c1a05ae90c", "0x856d33282e8a8e33a3d237fb0a0cbabaf77ba9edf2fa35a831fdafcadf620561846aa6cbb6bdc5e681118e1245834165", "0x9524a7aa8e97a31a6958439c5f3339b19370f03e86b89b1d02d87e4887309dbbe9a3a8d2befd3b7ed5143c8da7e0a8ad", "0x824fdf433e090f8acbd258ac7429b21f36f9f3b337c6d0b71d1416a5c88a767883e255b2888b7c906dd2e9560c4af24c", "0x88c7fee662ca7844f42ed5527996b35723abffd0d22d4ca203b9452c639a5066031207a5ae763dbc0865b3299d19b1ec", "0x919dca5c5595082c221d5ab3a5bc230f45da7f6dec4eb389371e142c1b9c6a2c919074842479c2844b72c0d806170c0c", "0xb939be8175715e55a684578d8be3ceff3087f60fa875fff48e52a6e6e9979c955efef8ff67cfa2b79499ea23778e33b0", "0x873b6db725e7397d11bc9bed9ac4468e36619135be686790a79bc6ed4249058f1387c9a802ea86499f692cf635851066", "0xaeae06db3ec47e9e5647323fa02fac44e06e59b885ad8506bf71b184ab3895510c82f78b6b22a5d978e8218e7f761e9f", "0xb99c0a8359c72ab88448bae45d4bf98797a26bca48b0d4460cd6cf65a4e8c3dd823970ac3eb774ae5d0cea4e7fadf33e", "0x8f10c8ec41cdfb986a1647463076a533e6b0eec08520c1562401b36bb063ac972aa6b28a0b6ce717254e35940b900e3c", "0xa106d9be199636d7add43b942290269351578500d8245d4aae4c083954e4f27f64740a3138a66230391f2d0e6043a8de", "0xa469997908244578e8909ff57cffc070f1dbd86f0098df3cfeb46b7a085cfecc93dc69ee7cad90ff1dc5a34d50fe580c", "0xa4ef087bea9c20eb0afc0ee4caba7a9d29dfa872137828c721391273e402fb6714afc80c40e98bbd8276d3836bffa080", "0xb07a013f73cd5b98dae0d0f9c1c0f35bff8a9f019975c4e1499e9bee736ca6fcd504f9bc32df1655ff333062382cff04", "0xb0a77188673e87cc83348c4cc5db1eecf6b5184e236220c8eeed7585e4b928db849944a76ec60ef7708ef6dac02d5592", "0xb1284b37e59b529f0084c0dacf0af6c0b91fc0f387bf649a8c74819debf606f7b07fc3e572500016fb145ec2b24e9f17", "0x97b20b5b4d6b9129da185adfbf0d3d0b0faeba5b9715f10299e48ea0521709a8296a9264ce77c275a59c012b50b6519a", "0xb9d37e946fae5e4d65c1fbfacc8a62e445a1c9d0f882e60cca649125af303b3b23af53c81d7bac544fb7fcfc7a314665", "0x8e5acaac379f4bb0127efbef26180f91ff60e4c525bc9b798fc50dfaf4fe8a5aa84f18f3d3cfb8baead7d1e0499af753", "0xb0c0b8ab1235bf1cda43d4152e71efc1a06c548edb964eb4afceb201c8af24240bf8ab5cae30a08604e77432b0a5faf0", "0x8cc28d75d5c8d062d649cbc218e31c4d327e067e6dbd737ec0a35c91db44fbbd0d40ec424f5ed79814add16947417572", "0x95ae6219e9fd47efaa9cb088753df06bc101405ba50a179d7c9f7c85679e182d3033f35b00dbba71fdcd186cd775c52e", "0xb5d28fa09f186ebc5aa37453c9b4d9474a7997b8ae92748ecb940c14868792292ac7d10ade01e2f8069242b308cf97e5", "0x8c922a0faa14cc6b7221f302df3342f38fc8521ec6c653f2587890192732c6da289777a6cd310747ea7b7d104af95995", "0xb9ad5f660b65230de54de535d4c0fcae5bc6b59db21dea5500fdc12eea4470fb8ea003690fdd16d052523418d5e01e8c", "0xa39a9dd41a0ff78c82979483731f1cd68d3921c3e9965869662c22e02dde3877802e180ba93f06e7346f96d9fa9261d2", "0x8b32875977ec372c583b24234c27ed73aef00cdff61eb3c3776e073afbdeade548de9497c32ec6d703ff8ad0a5cb7fe4", "0x9644cbe755a5642fe9d26cfecf170d3164f1848c2c2e271d5b6574a01755f3980b3fc870b98cf8528fef6ecef4210c16", "0x81ea9d1fdd9dd66d60f40ce0712764b99da9448ae0b300f8324e1c52f154e472a086dda840cb2e0b9813dc8ce8afd4b5", "0x906aaa4a7a7cdf01909c5cfbc7ded2abc4b869213cbf7c922d4171a4f2e637e56f17020b852ad339d83b8ac92f111666", "0x939b5f11acbdeff998f2a080393033c9b9d8d5c70912ea651c53815c572d36ee822a98d6dfffb2e339f29201264f2cf4", "0xaba4898bf1ccea9b9e2df1ff19001e05891581659c1cbbde7ee76c349c7fc7857261d9785823c9463a8aea3f40e86b38", "0x83ca1a56b8a0be4820bdb5a9346357c68f9772e43f0b887729a50d2eb2a326bbcede676c8bf2e51d7c89bbd8fdb778a6", "0x94e86e9fe6addfe2c3ee3a547267ed921f4230d877a85bb4442c2d9350c2fa9a9c54e6fe662de82d1a2407e4ab1691c2", "0xa0cc3bdef671a59d77c6984338b023fa2b431b32e9ed2abe80484d73edc6540979d6f10812ecc06d4d0c5d4eaca7183c", "0xb5343413c1b5776b55ea3c7cdd1f3af1f6bd802ea95effe3f2b91a523817719d2ecc3f8d5f3cc2623ace7e35f99ca967", "0x92085d1ed0ed28d8cabe3e7ff1905ed52c7ceb1eac5503760c52fb5ee3a726aba7c90b483c032acc3f166b083d7ec370", "0x8ec679520455275cd957fca8122724d287db5df7d29f1702a322879b127bff215e5b71d9c191901465d19c86c8d8d404", "0xb65eb2c63d8a30332eb24ee8a0c70156fc89325ebbb38bacac7cf3f8636ad8a472d81ccca80423772abc00192d886d8a", "0xa9fe1c060b974bee4d590f2873b28635b61bfcf614e61ff88b1be3eee4320f4874e21e8d666d8ac8c9aba672efc6ecae", "0xb3fe2a9a389c006a831dea7e777062df84b5c2803f9574d7fbe10b7e1c125817986af8b6454d6be9d931a5ac94cfe963", "0x95418ad13b734b6f0d33822d9912c4c49b558f68d08c1b34a0127fcfa666bcae8e6fda8832d2c75bb9170794a20e4d7c", "0xa9a7df761e7f18b79494bf429572140c8c6e9d456c4d4e336184f3f51525a65eb9582bea1e601bdb6ef8150b7ca736a5", "0xa0de03b1e75edf7998c8c1ac69b4a1544a6fa675a1941950297917366682e5644a4bda9cdeedfaf9473d7fccd9080b0c", "0xa61838af8d95c95edf32663a68f007d95167bf6e41b0c784a30b22d8300cfdd5703bd6d16e86396638f6db6ae7e42a85", "0x8866d62084d905c145ff2d41025299d8b702ac1814a7dec4e277412c161bc9a62fed735536789cb43c88693c6b423882", "0x91da22c378c81497fe363e7f695c0268443abee50f8a6625b8a41e865638a643f07b157ee566de09ba09846934b4e2d7", "0x941d21dd57c9496aa68f0c0c05507405fdd413acb59bc668ce7e92e1936c68ec4b065c3c30123319884149e88228f0b2", "0xa77af9b094bc26966ddf2bf9e1520c898194a5ccb694915950dadc204facbe3066d3d89f50972642d76b14884cfbaa21", "0x8e76162932346869f4618bde744647f7ab52ab498ad654bdf2a4feeb986ac6e51370841e5acbb589e38b6e7142bb3049", "0xb60979ace17d6937ece72e4f015da4657a443dd01cebc7143ef11c09e42d4aa8855999a65a79e2ea0067f31c9fc2ab0f", "0xb3e2ffdd5ee6fd110b982fd4fad4b93d0fca65478f986d086eeccb0804960bfaa1919afa743c2239973ea65091fe57d2", "0x8ce0ce05e7d7160d44574011da687454dbd3c8b8290aa671731b066e2c82f8cf2d63cb8e932d78c6122ec610e44660e6", "0xab005dd8d297045c39e2f72fb1c48edb501ccf3575d3d04b9817b3afee3f0bb0f3f53f64bda37d1d9cde545aae999bae", "0x95bd7edb4c4cd60e3cb8a72558845a3cce6bb7032ccdf33d5a49ebb6ddf203bc3c79e7b7e550735d2d75b04c8b2441e8", "0x889953ee256206284094e4735dbbb17975bafc7c3cb94c9fbfee4c3e653857bfd49e818f64a47567f721b98411a3b454", "0xb188423e707640ab0e75a061e0b62830cde8afab8e1ad3dae30db69ffae4e2fc005bababbdcbd7213b918ed4f70e0c14", "0xa97e0fafe011abd70d4f99a0b36638b3d6e7354284588f17a88970ed48f348f88392779e9a038c6cbc9208d998485072", "0x87db11014a91cb9b63e8dfaa82cdebca98272d89eb445ee1e3ff9dbaf2b3fad1a03b888cffc128e4fe208ed0dddece0f", "0xaad2e40364edd905d66ea4ac9d51f9640d6fda9a54957d26ba233809851529b32c85660fa401dbee3679ec54fa6dd966", "0x863e99336ca6edf03a5a259e59a2d0f308206e8a2fb320cfc0be06057366df8e0f94b33a28f574092736b3c5ada84270", "0xb34bcc56a057589f34939a1adc51de4ff6a9f4fee9c7fa9aa131e28d0cf0759a0c871b640162acdfbf91f3f1b59a3703", "0x935dd28f2896092995c5eff1618e5b6efe7a40178888d7826da9b0503c2d6e68a28e7fac1a334e166d0205f0695ef614", "0xb842cd5f8f5de5ca6c68cb4a5c1d7b451984930eb4cc18fd0934d52fdc9c3d2d451b1c395594d73bc3451432bfba653f", "0x9014537885ce2debad736bc1926b25fdab9f69b216bf024f589c49dc7e6478c71d595c3647c9f65ff980b14f4bb2283b", "0x8e827ccca1dd4cd21707140d10703177d722be0bbe5cac578db26f1ef8ad2909103af3c601a53795435b27bf95d0c9ed", "0x8a0b8ad4d466c09d4f1e9167410dbe2edc6e0e6229d4b3036d30f85eb6a333a18b1c968f6ca6d6889bb08fecde017ef4", "0x9241ee66c0191b06266332dc9161dede384c4bb4e116dbd0890f3c3790ec5566da4568243665c4725b718ac0f6b5c179", "0xaeb4d5fad81d2b505d47958a08262b6f1b1de9373c2c9ba6362594194dea3e002ab03b8cbb43f867be83065d3d370f19", "0x8781bc83bb73f7760628629fe19e4714b494dbed444c4e4e4729b7f6a8d12ee347841a199888794c2234f51fa26fc2b9", "0xb58864f0acd1c2afa29367e637cbde1968d18589245d9936c9a489c6c495f54f0113ecdcbe4680ac085dd3c397c4d0c3", "0x94a24284afaeead61e70f3e30f87248d76e9726759445ca18cdb9360586c60cc9f0ec1c397f9675083e0b56459784e2e", "0xaed358853f2b54dcbddf865e1816c2e89be12e940e1abfa661e2ee63ffc24a8c8096be2072fa83556482c0d89e975124", "0xb95374e6b4fc0765708e370bc881e271abf2e35c08b056a03b847e089831ef4fe3124b9c5849d9c276eb2e35b3daf264", "0xb834cdbcfb24c8f84bfa4c552e7fadc0028a140952fd69ed13a516e1314a4cd35d4b954a77d51a1b93e1f5d657d0315d", "0x8fb6d09d23bfa90e7443753d45a918d91d75d8e12ec7d016c0dfe94e5c592ba6aaf483d2f16108d190822d955ad9cdc3", "0xaa315cd3c60247a6ad4b04f26c5404c2713b95972843e4b87b5a36a89f201667d70f0adf20757ebe1de1b29ae27dda50", "0xa116862dca409db8beff5b1ccd6301cdd0c92ca29a3d6d20eb8b87f25965f42699ca66974dd1a355200157476b998f3b", "0xb4c2f5fe173c4dc8311b60d04a65ce1be87f070ac42e13cd19c6559a2931c6ee104859cc2520edebbc66a13dc7d30693", "0x8d4a02bf99b2260c334e7d81775c5cf582b00b0c982ce7745e5a90624919028278f5e9b098573bad5515ce7fa92a80c8", "0x8543493bf564ce6d97bd23be9bff1aba08bd5821ca834f311a26c9139c92a48f0c2d9dfe645afa95fec07d675d1fd53b", "0x9344239d13fde08f98cb48f1f87d34cf6abe8faecd0b682955382a975e6eed64e863fa19043290c0736261622e00045c", "0xaa49d0518f343005ca72b9e6c7dcaa97225ce6bb8b908ebbe7b1a22884ff8bfb090890364e325a0d414ad180b8f161d1", "0x907d7fd3e009355ab326847c4a2431f688627faa698c13c03ffdd476ecf988678407f029b8543a475dcb3dafdf2e7a9c", "0x845f1f10c6c5dad2adc7935f5cd2e2b32f169a99091d4f1b05babe7317b9b1cdce29b5e62f947dc621b9acbfe517a258", "0x8f3be8e3b380ea6cdf9e9c237f5e88fd5a357e5ded80ea1fc2019810814de82501273b4da38916881125b6fa0cfd4459", "0xb9c7f487c089bf1d20c822e579628db91ed9c82d6ca652983aa16d98b4270c4da19757f216a71b9c13ddee3e6e43705f", "0x8ba2d8c88ad2b872db104ea8ddbb006ec2f3749fd0e19298a804bb3a5d94de19285cc7fb19fee58a66f7851d1a66c39f", "0x9375ecd3ed16786fe161af5d5c908f56eeb467a144d3bbddfc767e90065b7c94fc53431adebecba2b6c9b5821184d36e", "0xa49e069bfadb1e2e8bff6a4286872e2a9765d62f0eaa4fcb0e5af4bbbed8be3510fb19849125a40a8a81d1e33e81c3eb", "0x9522cc66757b386aa6b88619525c8ce47a5c346d590bb3647d12f991e6c65c3ab3c0cfc28f0726b6756c892eae1672be", "0xa9a0f1f51ff877406fa83a807aeb17b92a283879f447b8a2159653db577848cc451cbadd01f70441e351e9ed433c18bc", "0x8ff7533dcff6be8714df573e33f82cf8e9f2bcaaa43e939c4759d52b754e502717950de4b4252fb904560fc31dce94a4", "0x959724671e265a28d67c29d95210e97b894b360da55e4cf16e6682e7912491ed8ca14bfaa4dce9c25a25b16af580494f", "0x92566730c3002f4046c737032487d0833c971e775de59fe02d9835c9858e2e3bc37f157424a69764596c625c482a2219", "0xa84b47ceff13ed9c3e5e9cdf6739a66d3e7c2bd8a6ba318fefb1a9aecf653bb2981da6733ddb33c4b0a4523acc429d23", "0xb4ddf571317e44f859386d6140828a42cf94994e2f1dcbcc9777f4eebbfc64fc1e160b49379acc27c4672b8e41835c5d", "0x8ab95c94072b853d1603fdd0a43b30db617d13c1d1255b99075198e1947bfa5f59aed2b1147548a1b5e986cd9173d15c", "0x89511f2eab33894fd4b3753d24249f410ff7263052c1fef6166fc63a79816656b0d24c529e45ccce6be28de6e375d916", "0xa0866160ca63d4f2be1b4ea050dac6b59db554e2ebb4e5b592859d8df339b46fd7cb89aaed0951c3ee540aee982c238a", "0x8fcc5cbba1b94970f5ff2eb1922322f5b0aa7d918d4b380c9e7abfd57afd8b247c346bff7b87af82efbce3052511cd1b", "0x99aeb2a5e846b0a2874cca02c66ed40d5569eb65ab2495bc3f964a092e91e1517941f2688e79f8cca49cd3674c4e06dc", "0xb7a096dc3bad5ca49bee94efd884aa3ff5615cf3825cf95fbe0ce132e35f46581d6482fa82666c7ef5f1643eaee8f1ca", "0x94393b1da6eaac2ffd186b7725eca582f1ddc8cdd916004657f8a564a7c588175cb443fc6943b39029f5bbe0add3fad8", "0x884b85fe012ccbcd849cb68c3ad832d83b3ef1c40c3954ffdc97f103b1ed582c801e1a41d9950f6bddc1d11f19d5ec76", "0xb00061c00131eded8305a7ce76362163deb33596569afb46fe499a7c9d7a0734c084d336b38d168024c2bb42b58e7660", "0xa439153ac8e6ca037381e3240e7ba08d056c83d7090f16ed538df25901835e09e27de2073646e7d7f3c65056af6e4ce7", "0x830fc9ca099097d1f38b90e6843dc86f702be9d20bdacc3e52cae659dc41df5b8d2c970effa6f83a5229b0244a86fe22", "0xb81ea2ffaaff2bb00dd59a9ab825ba5eed4db0d8ac9c8ed1a632ce8f086328a1cddd045fbe1ace289083c1325881b7e7", "0xb51ea03c58daf2db32c99b9c4789b183365168cb5019c72c4cc91ac30b5fb7311d3db76e6fa41b7cd4a8c81e2f6cdc94", "0xa4170b2c6d09ca5beb08318730419b6f19215ce6c631c854116f904be3bc30dd85a80c946a8ab054d3e307afaa3f8fbc", "0x897cc42ff28971ff54d2a55dd6b35cfb8610ac902f3c06e3a5cea0e0a257e870c471236a8e84709211c742a09c5601a6", "0xa18f2e98d389dace36641621488664ecbb422088ab03b74e67009b8b8acacaaa24fdcf42093935f355207d934adc52a8", "0x92adcfb678cc2ba19c866f3f2b988fdcb4610567f3ab436cc0cb9acaf5a88414848d71133ebdbec1983e38e6190f1b5f", "0xa86d43c2ce01b366330d3b36b3ca85f000c3548b8297e48478da1ee7d70d8576d4650cba7852ed125c0d7cb6109aa7f3", "0x8ed31ceed9445437d7732dce78a762d72ff32a7636bfb3fd7974b7ae15db414d8184a1766915244355deb354fbc5803b", "0x9268f70032584f416e92225d65af9ea18c466ebc7ae30952d56a4e36fd9ea811dde0a126da9220ba3c596ec54d8a335e", "0x9433b99ee94f2d3fbdd63b163a2bdf440379334c52308bd24537f7defd807145a062ff255a50d119a7f29f4b85d250e3", "0x90ce664f5e4628a02278f5cf5060d1a34f123854634b1870906e5723ac9afd044d48289be283b267d45fcbf3f4656aaf", "0xaaf21c4d59378bb835d42ae5c5e5ab7a3c8c36a59e75997989313197752b79a472d866a23683b329ea69b048b87fa13e", "0xb83c0589b304cec9ede549fde54f8a7c2a468c6657da8c02169a6351605261202610b2055c639b9ed2d5b8c401fb8f56", "0x9370f326ea0f170c2c05fe2c5a49189f20aec93b6b18a5572a818cd4c2a6adb359e68975557b349fb54f065d572f4c92", "0xac3232fa5ce6f03fca238bef1ce902432a90b8afce1c85457a6bee5571c033d4bceefafc863af04d4e85ac72a4d94d51", "0x80d9ea168ff821b22c30e93e4c7960ce3ad3c1e6deeebedd342a36d01bd942419b187e2f382dbfd8caa34cca08d06a48", "0xa387a3c61676fb3381eefa2a45d82625635a666e999aba30e3b037ec9e040f414f9e1ad9652abd3bcad63f95d85038db", "0xa1b229fe32121e0b391b0f6e0180670b9dc89d79f7337de4c77ea7ad0073e9593846f06797c20e923092a08263204416", "0x92164a9d841a2b828cedf2511213268b698520f8d1285852186644e9a0c97512cafa4bfbe29af892c929ebccd102e998", "0x82ee2fa56308a67c7db4fd7ef539b5a9f26a1c2cc36da8c3206ba4b08258fbb3cec6fe5cdbd111433fb1ba2a1e275927", "0x8c77bfe9e191f190a49d46f05600603fa42345592539b82923388d72392404e0b29a493a15e75e8b068dddcd444c2928", "0x80b927f93ccf79dcf5c5b20bcf5a7d91d7a17bc0401bb7cc9b53a6797feac31026eb114257621f5a64a52876e4474cc1", "0xb6b68b6501c37804d4833d5a063dd108a46310b1400549074e3cac84acc6d88f73948b7ad48d686de89c1ec043ae8c1a", "0xab3da00f9bdc13e3f77624f58a3a18fc3728956f84b5b549d62f1033ae4b300538e53896e2d943f160618e05af265117", "0xb6830e87233b8eace65327fdc764159645b75d2fd4024bf8f313b2dd5f45617d7ecfb4a0b53ccafb5429815a9a1adde6", "0xb9251cfe32a6dc0440615aadcd98b6b1b46e3f4e44324e8f5142912b597ee3526bea2431e2b0282bb58f71be5b63f65e", "0xaf8d70711e81cdddfb39e67a1b76643292652584c1ce7ce4feb1641431ad596e75c9120e85f1a341e7a4da920a9cdd94", "0x98cd4e996594e89495c078bfd52a4586b932c50a449a7c8dfdd16043ca4cda94dafbaa8ad1b44249c99bbcc52152506e", "0xb9fc6d1c24f48404a4a64fbe3e43342738797905db46e4132aee5f086aaa4c704918ad508aaefa455cfe1b36572e6242", "0xa365e871d30ba9291cedaba1be7b04e968905d003e9e1af7e3b55c5eb048818ae5b913514fb08b24fb4fbdccbb35d0b8", "0x93bf99510971ea9af9f1e364f1234c898380677c8e8de9b0dd24432760164e46c787bc9ec42a7ad450500706cf247b2d", "0xb872f825a5b6e7b9c7a9ddfeded3516f0b1449acc9b4fd29fc6eba162051c17416a31e5be6d3563f424d28e65bab8b8f", "0xb06b780e5a5e8eb4f4c9dc040f749cf9709c8a4c9ef15e925f442b696e41e5095db0778a6c73bcd329b265f2c6955c8b", "0x848f1a981f5fc6cd9180cdddb8d032ad32cdfa614fc750d690dbae36cc0cd355cbf1574af9b3ffc8b878f1b2fafb9544", "0xa03f48cbff3e9e8a3a655578051a5ae37567433093ac500ed0021c6250a51b767afac9bdb194ee1e3eac38a08c0eaf45", "0xb5be78ce638ff8c4aa84352b536628231d3f7558c5be3bf010b28feac3022e64691fa672f358c8b663904aebe24a54ed", "0xa9d4da70ff676fa55d1728ba6ab03b471fa38b08854d99e985d88c2d050102d8ccffbe1c90249a5607fa7520b15fe791", "0x8fe9f7092ffb0b69862c8e972fb1ecf54308c96d41354ed0569638bb0364f1749838d6d32051fff1599112978c6e229c", "0xae6083e95f37770ecae0df1e010456f165d96cfe9a7278c85c15cffd61034081ce5723e25e2bede719dc9341ec8ed481", "0xa260891891103089a7afbd9081ea116cfd596fd1015f5b65e10b0961eb37fab7d09c69b7ce4be8bf35e4131848fb3fe4", "0x8d729fa32f6eb9fd2f6a140bef34e8299a2f3111bffd0fe463aa8622c9d98bfd31a1df3f3e87cd5abc52a595f96b970e", "0xa30ec6047ae4bc7da4daa7f4c28c93aedb1112cfe240e681d07e1a183782c9ff6783ac077c155af23c69643b712a533f", "0xac830726544bfe7b5467339e5114c1a75f2a2a8d89453ce86115e6a789387e23551cd64620ead6283dfa4538eb313d86", "0x8445c135b7a48068d8ed3e011c6d818cfe462b445095e2fbf940301e50ded23f272d799eea47683fc027430ce14613ef", "0x95785411715c9ae9d8293ce16a693a2aa83e3cb1b4aa9f76333d0da2bf00c55f65e21e42e50e6c5772ce213dd7b4f7a0", "0xb273b024fa18b7568c0d1c4d2f0c4e79ec509dafac8c5951f14192d63ddbcf2d8a7512c1c1b615cc38fa3e336618e0c5", "0xa78b9d3ea4b6a90572eb27956f411f1d105fdb577ee2ffeec9f221da9b45db84bfe866af1f29597220c75e0c37a628d8", "0xa4be2bf058c36699c41513c4d667681ce161a437c09d81383244fc55e1c44e8b1363439d0cce90a3e44581fb31d49493", "0xb6eef13040f17dd4eba22aaf284d2f988a4a0c4605db44b8d2f4bf9567ac794550b543cc513c5f3e2820242dd704152e", "0x87eb00489071fa95d008c5244b88e317a3454652dcb1c441213aa16b28cd3ecaa9b22fec0bdd483c1df71c37119100b1", "0x92d388acdcb49793afca329cd06e645544d2269234e8b0b27d2818c809c21726bc9cf725651b951e358a63c83dedee24", "0xae27e219277a73030da27ab5603c72c8bd81b6224b7e488d7193806a41343dff2456132274991a4722fdb0ef265d04cd", "0x97583e08ecb82bbc27c0c8476d710389fa9ffbead5c43001bd36c1b018f29faa98de778644883e51870b69c5ffb558b5", "0x90a799a8ce73387599babf6b7da12767c0591cadd36c20a7990e7c05ea1aa2b9645654ec65308ee008816623a2757a6a", "0xa1b47841a0a2b06efd9ab8c111309cc5fc9e1d5896b3e42ed531f6057e5ade8977c29831ce08dbda40348386b1dcc06d", "0xb92b8ef59bbddb50c9457691bc023d63dfcc54e0fd88bd5d27a09e0d98ac290fc90e6a8f6b88492043bf7c87fac8f3e4", "0xa9d6240b07d62e22ec8ab9b1f6007c975a77b7320f02504fc7c468b4ee9cfcfd945456ff0128bc0ef2174d9e09333f8d", "0x8e96534c94693226dc32bca79a595ca6de503af635f802e86442c67e77564829756961d9b701187fe91318da515bf0e6", "0xb6ba290623cd8dd5c2f50931c0045d1cfb0c30877bc8fe58cbc3ff61ee8da100045a39153916efa1936f4aee0892b473", "0xb43baa7717fac02d4294f5b3bb5e58a65b3557747e3188b482410388daac7a9c177f762d943fd5dcf871273921213da8", "0xb9cf00f8fb5e2ef2b836659fece15e735060b2ea39b8e901d3dcbdcf612be8bf82d013833718c04cd46ffaa70b85f42e", "0x8017d0c57419e414cbba504368723e751ef990cc6f05dad7b3c2de6360adc774ad95512875ab8337d110bf39a42026fa", "0xae7401048b838c0dcd4b26bb6c56d79d51964a0daba780970b6c97daee4ea45854ea0ac0e4139b3fe60dac189f84df65", "0x887b237b0cd0f816b749b21db0b40072f9145f7896c36916296973f9e6990ede110f14e5976c906d08987c9836cca57f", "0xa88c3d5770148aee59930561ca1223aceb2c832fb5417e188dca935905301fc4c6c2c9270bc1dff7add490a125eb81c6", "0xb6cf9b02c0cd91895ad209e38c54039523f137b5848b9d3ad33ae43af6c20c98434952db375fe378de7866f2d0e8b18a", "0x84ef3d322ff580c8ad584b1fe4fe346c60866eb6a56e982ba2cf3b021ecb1fdb75ecc6c29747adda86d9264430b3f816", "0xa0561c27224baf0927ad144cb71e31e54a064c598373fcf0d66aebf98ab7af1d8e2f343f77baefff69a6da750a219e11", "0xaa5cc43f5b8162b016f5e1b61214c0c9d15b1078911c650b75e6cdfb49b85ee04c6739f5b1687d15908444f691f732de", "0xad4ac099b935589c7b8fdfdf3db332b7b82bb948e13a5beb121ebd7db81a87d278024a1434bcf0115c54ca5109585c3d", "0x8a00466abf3f109a1dcd19e643b603d3af23d42794ef8ca2514dd507ecea44a031ac6dbc18bd02f99701168b25c1791e", "0xb00b5900dfad79645f8bee4e5adc7b84eb22e5b1e67df77ccb505b7fc044a6c08a8ea5faca662414eb945f874f884cea", "0x950e204e5f17112250b22ea6bb8423baf522fc0af494366f18fe0f949f51d6e6812074a80875cf1ed9c8e7420058d541", "0x91e5cbf8bb1a1d50c81608c9727b414d0dd2fb467ebc92f100882a3772e54f94979cfdf8e373fdef7c7fcdd60fec9e00", "0xa093f6a857b8caaff80599c2e89c962b415ecbaa70d8fd973155fa976a284c6b29a855f5f7a3521134d00d2972755188", "0xb4d55a3551b00da54cc010f80d99ddd2544bde9219a3173dfaadf3848edc7e4056ab532fb75ac26f5f7141e724267663", "0xa03ea050fc9b011d1b04041b5765d6f6453a93a1819cd9bd6328637d0b428f08526466912895dcc2e3008ee58822e9a7", "0x99b12b3665e473d01bc6985844f8994fb65cb15745024fb7af518398c4a37ff215da8f054e8fdf3286984ae36a73ca5e", "0x9972c7e7a7fb12e15f78d55abcaf322c11249cd44a08f62c95288f34f66b51f146302bce750ff4d591707075d9123bd2", "0xa64b4a6d72354e596d87cda213c4fc2814009461570ccb27d455bbe131f8d948421a71925425b546d8cf63d5458cd64b", "0x91c215c73b195795ede2228b7ed1f6e37892e0c6b0f4a0b5a16c57aa1100c84df9239054a173b6110d6c2b7f4bf1ce52", "0x88807198910ec1303480f76a3683870246a995e36adaeadc29c22f0bdba8152fe705bd070b75de657b04934f7d0ccf80", "0xb37c0026c7b32eb02cacac5b55cb5fe784b8e48b2945c64d3037af83ece556a117f0ff053a5968c2f5fa230e291c1238", "0x94c768384ce212bc2387e91ce8b45e4ff120987e42472888a317abc9dcdf3563b62e7a61c8e98d7cdcbe272167d91fc6", "0xa10c2564936e967a390cb14ef6e8f8b04ea9ece5214a38837eda09e79e0c7970b1f83adf017c10efd6faa8b7ffa2c567", "0xa5085eed3a95f9d4b1269182ea1e0d719b7809bf5009096557a0674bde4201b0ddc1f0f16a908fc468846b3721748ce3", "0x87468eb620b79a0a455a259a6b4dfbc297d0d53336537b771254dd956b145dc816b195b7002647ea218552e345818a3f", "0xace2b77ffb87366af0a9cb5d27d6fc4a14323dbbf1643f5f3c4559306330d86461bb008894054394cbfaefeaa0bc2745", "0xb27f56e840a54fbd793f0b7a7631aa4cee64b5947e4382b2dfb5eb1790270288884c2a19afebe5dc0c6ef335d4531c1c", "0x876e438633931f7f895062ee16c4b9d10428875f7bc79a8e156a64d379a77a2c45bf5430c5ab94330f03da352f1e9006", "0xa2512a252587d200d2092b44c914df54e04ff8bcef36bf631f84bde0cf5a732e3dc7f00f662842cfd74b0b0f7f24180e", "0x827f1bc8f54a35b7a4bd8154f79bcc055e45faed2e74adf7cf21cca95df44d96899e847bd70ead6bb27b9c0ed97bbd8b", "0xa0c92cf5a9ed843714f3aea9fe7b880f622d0b4a3bf66de291d1b745279accf6ba35097849691370f41732ba64b5966b", "0xa63f5c1e222775658421c487b1256b52626c6f79cb55a9b7deb2352622cedffb08502042d622eb3b02c97f9c09f9c957", "0x8cc093d52651e65fb390e186db6cc4de559176af4624d1c44cb9b0e836832419dacac7b8db0627b96288977b738d785d", "0xaa7b6a17dfcec146134562d32a12f7bd7fe9522e300859202a02939e69dbd345ed7ff164a184296268f9984f9312e8fc", "0x8ac76721f0d2b679f023d06cbd28c85ae5f4b43c614867ccee88651d4101d4fd352dbdb65bf36bfc3ebc0109e4b0c6f9", "0x8d350f7c05fc0dcd9a1170748846fb1f5d39453e4cb31e6d1457bed287d96fc393b2ecc53793ca729906a33e59c6834a", "0xb9913510dfc5056d7ec5309f0b631d1ec53e3a776412ada9aefdaf033c90da9a49fdde6719e7c76340e86599b1f0eec2", "0x94955626bf4ce87612c5cfffcf73bf1c46a4c11a736602b9ba066328dc52ad6d51e6d4f53453d4ed55a51e0aad810271", "0xb0fcab384fd4016b2f1e53f1aafd160ae3b1a8865cd6c155d7073ecc1664e05b1d8bca1def39c158c7086c4e1103345e", "0x827de3f03edfbde08570b72de6662c8bfa499b066a0a27ebad9b481c273097d17a5a0a67f01553da5392ec3f149b2a78", "0xab7940384c25e9027c55c40df20bd2a0d479a165ced9b1046958353cd69015eeb1e44ed2fd64e407805ba42df10fc7bf", "0x8ad456f6ff8cd58bd57567d931f923d0c99141978511b17e03cab7390a72b9f62498b2893e1b05c7c22dd274e9a31919", "0xac75399e999effe564672db426faa17a839e57c5ef735985c70cd559a377adec23928382767b55ed5a52f7b11b54b756", "0xb17f975a00b817299ac7af5f2024ea820351805df58b43724393bfb3920a8cd747a3bbd4b8286e795521489db3657168", "0xa2bed800a6d95501674d9ee866e7314063407231491d794f8cf57d5be020452729c1c7cefd8c50dc1540181f5caab248", "0x9743f5473171271ffdd3cc59a3ae50545901a7b45cd4bc3570db487865f3b73c0595bebabbfe79268809ee1862e86e4a", "0xb7eab77c2d4687b60d9d7b04e842b3880c7940140012583898d39fcc22d9b9b0a9be2c2e3788b3e6f30319b39c338f09", "0x8e2b8f797a436a1b661140e9569dcf3e1eea0a77c7ff2bc4ff0f3e49af04ed2de95e255df8765f1d0927fb456a9926b1", "0x8aefea201d4a1f4ff98ffce94e540bb313f2d4dfe7e9db484a41f13fc316ed02b282e1acc9bc6f56cad2dc2e393a44c9", "0xb950c17c0e5ca6607d182144aa7556bb0efe24c68f06d79d6413a973b493bfdf04fd147a4f1ab03033a32004cc3ea66f", "0xb7b8dcbb179a07165f2dc6aa829fad09f582a71b05c3e3ea0396bf9e6fe73076f47035c031c2101e8e38e0d597eadd30", "0xa9d77ed89c77ec1bf8335d08d41c3c94dcca9fd1c54f22837b4e54506b212aa38d7440126c80648ab7723ff18e65ed72", "0xa819d6dfd4aef70e52b8402fe5d135f8082d40eb7d3bb5c4d7997395b621e2bb10682a1bad2c9caa33dd818550fc3ec6", "0x8f6ee34128fac8bbf13ce2d68b2bb363eb4fd65b297075f88e1446ddeac242500eeb4ef0735e105882ff5ba8c44c139b", "0xb4440e48255c1644bcecf3a1e9958f1ec4901cb5b1122ee5b56ffd02cad1c29c4266999dbb85aa2605c1b125490074d4", "0xa43304a067bede5f347775d5811cf65a6380a8d552a652a0063580b5c5ef12a0867a39c7912fa219e184f4538eba1251", "0xa891ad67a790089ffc9f6d53e6a3d63d3556f5f693e0cd8a7d0131db06fd4520e719cfcc3934f0a8f62a95f90840f1d4", "0xaea6df8e9bb871081aa0fc5a9bafb00be7d54012c5baf653791907d5042a326aeee966fd9012a582cc16695f5baf7042", "0x8ffa2660dc52ed1cd4eff67d6a84a8404f358a5f713d04328922269bee1e75e9d49afeec0c8ad751620f22352a438e25", "0x87ec6108e2d63b06abed350f8b363b7489d642486f879a6c3aa90e5b0f335efc2ff2834eef9353951a42136f8e6a1b32", "0x865619436076c2760d9e87ddc905023c6de0a8d56eef12c98a98c87837f2ca3f27fd26a2ad752252dbcbe2b9f1d5a032", "0x980437dce55964293cb315c650c5586ffd97e7a944a83f6618af31c9d92c37b53ca7a21bb5bc557c151b9a9e217e7098", "0x95d128fc369df4ad8316b72aea0ca363cbc7b0620d6d7bb18f7076a8717a6a46956ff140948b0cc4f6d2ce33b5c10054", "0x8c7212d4a67b9ec70ebbca04358ad2d36494618d2859609163526d7b3acc2fc935ca98519380f55e6550f70a9bc76862", "0x893a2968819401bf355e85eee0f0ed0406a6d4a7d7f172d0017420f71e00bb0ba984f6020999a3cdf874d3cd8ebcd371", "0x9103c1af82dece25d87274e89ea0acd7e68c2921c4af3d8d7c82ab0ed9990a5811231b5b06113e7fa43a6bd492b4564f", "0x99cfd87a94eab7d35466caa4ed7d7bb45e5c932b2ec094258fb14bf205659f83c209b83b2f2c9ccb175974b2a33e7746", "0x874b6b93e4ee61be3f00c32dd84c897ccd6855c4b6251eb0953b4023634490ed17753cd3223472873cbc6095b2945075", "0x84a32c0dc4ea60d33aac3e03e70d6d639cc9c4cc435c539eff915017be3b7bdaba33349562a87746291ebe9bc5671f24", "0xa7057b24208928ad67914e653f5ac1792c417f413d9176ba635502c3f9c688f7e2ee81800d7e3dc0a340c464da2fd9c5", "0xa03fb9ed8286aacfa69fbd5d953bec591c2ae4153400983d5dbb6cd9ea37fff46ca9e5cceb9d117f73e9992a6c055ad2", "0x863b2de04e89936c9a4a2b40380f42f20aefbae18d03750fd816c658aee9c4a03df7b12121f795c85d01f415baaeaa59", "0x8526eb9bd31790fe8292360d7a4c3eed23be23dd6b8b8f01d2309dbfdc0cfd33ad1568ddd7f8a610f3f85a9dfafc6a92", "0xb46ab8c5091a493d6d4d60490c40aa27950574a338ea5bbc045be3a114af87bdcb160a8c80435a9b7ad815f3cb56a3f3", "0xaeadc47b41a8d8b4176629557646202f868b1d728b2dda58a347d937e7ffc8303f20d26d6c00b34c851b8aeec547885d", "0xaebb19fc424d72c1f1822aa7adc744cd0ef7e55727186f8df8771c784925058c248406ebeeaf3c1a9ee005a26e9a10c6", "0x8ff96e81c1a4a2ab1b4476c21018fae0a67e92129ee36120cae8699f2d7e57e891f5c624902cb1b845b944926a605cc3", "0x8251b8d2c43fadcaa049a9e7aff838dae4fb32884018d58d46403ac5f3beb5c518bfd45f03b8abb710369186075eb71c", "0xa8b2a64f865f51a5e5e86a66455c093407933d9d255d6b61e1fd81ffafc9538d73caaf342338a66ba8ee166372a3d105", "0xaad915f31c6ba7fdc04e2aaac62e84ef434b7ee76a325f07dc430d12c84081999720181067b87d792efd0117d7ee1eab", "0xa13db3bb60389883fd41d565c54fb5180d9c47ce2fe7a169ae96e01d17495f7f4fa928d7e556e7c74319c4c25d653eb2", "0xa4491b0198459b3f552855d680a59214eb74e6a4d6c5fa3b309887dc50ebea2ecf6d26c040550f7dc478b452481466fb", "0x8f017f13d4b1e3f0c087843582b52d5f8d13240912254d826dd11f8703a99a2f3166dfbdfdffd9a3492979d77524276b", "0x96c3d5dcd032660d50d7cd9db2914f117240a63439966162b10c8f1f3cf74bc83b0f15451a43b31dbd85e4a7ce0e4bb1", "0xb479ec4bb79573d32e0ec93b92bdd7ec8c26ddb5a2d3865e7d4209d119fd3499eaac527615ffac78c440e60ef3867ae0", "0xb2c49c4a33aa94b52b6410b599e81ff15490aafa7e43c8031c865a84e4676354a9c81eb4e7b8be6825fdcefd1e317d44", "0x906dc51d6a90c089b6704b47592805578a6eed106608eeb276832f127e1b8e858b72e448edcbefb497d152447e0e68ff", "0xb0e81c63b764d7dfbe3f3fddc9905aef50f3633e5d6a4af6b340495124abedcff5700dfd1577bbbed7b6bf97d02719cb", "0x9304c64701e3b4ed6d146e48a881f7d83a17f58357cca0c073b2bb593afd2d94f6e2a7a1ec511d0a67ad6ff4c3be5937", "0xb6fdbd12ba05aa598d80b83f70a15ef90e5cba7e6e75fa038540ee741b644cd1f408a6cecfd2a891ef8d902de586c6b5", "0xb80557871a6521b1b3c74a1ba083ae055b575df607f1f7b04c867ba8c8c181ea68f8d90be6031f4d25002cca27c44da2", "0xaa7285b8e9712e06b091f64163f1266926a36607f9d624af9996856ed2aaf03a580cb22ce407d1ade436c28b44ca173f", "0x8148d72b975238b51e6ea389e5486940d22641b48637d7dfadfa603a605bfc6d74a016480023945d0b85935e396aea5d", "0x8a014933a6aea2684b5762af43dcf4bdbb633cd0428d42d71167a2b6fc563ece5e618bff22f1db2ddb69b845b9a2db19", "0x990d91740041db770d0e0eb9d9d97d826f09fd354b91c41e0716c29f8420e0e8aac0d575231efba12fe831091ec38d5a", "0x9454d0d32e7e308ddec57cf2522fb1b67a2706e33fb3895e9e1f18284129ab4f4c0b7e51af25681d248d7832c05eb698", "0xa5bd434e75bac105cb3e329665a35bce6a12f71dd90c15165777d64d4c13a82bceedb9b48e762bd24034e0fc9fbe45f4", "0xb09e3b95e41800d4dc29c6ffdaab2cd611a0050347f6414f154a47ee20ee59bf8cf7181454169d479ebce1eb5c777c46", "0xb193e341d6a047d15eea33766d656d807b89393665a783a316e9ba10518e5515c8e0ade3d6e15641d917a8a172a5a635", "0xade435ec0671b3621dde69e07ead596014f6e1daa1152707a8c18877a8b067bde2895dd47444ffa69db2bbef1f1d8816", "0xa7fd3d6d87522dfc56fb47aef9ce781a1597c56a8bbfd796baba907afdc872f753d732bfda1d3402aee6c4e0c189f52d", "0xa298cb4f4218d0464b2fab393e512bbc477c3225aa449743299b2c3572f065bc3a42d07e29546167ed9e1b6b3b3a3af3", "0xa9ee57540e1fd9c27f4f0430d194b91401d0c642456c18527127d1f95e2dba41c2c86d1990432eb38a692fda058fafde", "0x81d6c1a5f93c04e6d8e5a7e0678c1fc89a1c47a5c920bcd36180125c49fcf7c114866b90e90a165823560b19898a7c16", "0xa4b7a1ec9e93c899b9fd9aaf264c50e42c36c0788d68296a471f7a3447af4dbc81e4fa96070139941564083ec5b5b5a1", "0xb3364e327d381f46940c0e11e29f9d994efc6978bf37a32586636c0070b03e4e23d00650c1440f448809e1018ef9f6d8", "0x8056e0913a60155348300e3a62e28b5e30629a90f7dd4fe11289097076708110a1d70f7855601782a3cdc5bdb1ca9626", "0xb4980fd3ea17bac0ba9ee1c470b17e575bb52e83ebdd7d40c93f4f87bebeaff1c8a679f9d3d09d635f068d37d5bd28bd", "0x905a9299e7e1853648e398901dfcd437aa575c826551f83520df62984f5679cb5f0ea86aa45ed3e18b67ddc0dfafe809", "0xab99553bf31a84f2e0264eb34a08e13d8d15e2484aa9352354becf9a15999c76cc568d68274b70a65e49703fc23540d0", "0xa43681597bc574d2dae8964c9a8dc1a07613d7a1272bdcb818d98c85d44e16d744250c33f3b5e4d552d97396b55e601f", "0xa54e5a31716fccb50245898c99865644405b8dc920ded7a11f3d19bdc255996054b268e16f2e40273f11480e7145f41e", "0x8134f3ad5ef2ad4ba12a8a4e4d8508d91394d2bcdc38b7c8c8c0b0a820357ac9f79d286c65220f471eb1adca1d98fc68", "0x94e2f755e60471578ab2c1adb9e9cea28d4eec9b0e92e0140770bca7002c365fcabfe1e5fb4fe6cfe79a0413712aa3ef", "0xad48f8d0ce7eb3cc6e2a3086ad96f562e5bed98a360721492ae2e74dc158586e77ec8c35d5fd5927376301b7741bad2b", "0x8614f0630bdd7fbad3a31f55afd9789f1c605dc85e7dc67e2edfd77f5105f878bb79beded6e9f0b109e38ea7da67e8d5", "0x9804c284c4c5e77dabb73f655b12181534ca877c3e1e134aa3f47c23b7ec92277db34d2b0a5d38d2b69e5d1c3008a3e3", "0xa51b99c3088e473afdaa9e0a9f7e75a373530d3b04e44e1148da0726b95e9f5f0c7e571b2da000310817c36f84b19f7f", "0xac4ff909933b3b76c726b0a382157cdc74ab851a1ac6cef76953c6444441804cc43abb883363f416592e8f6cfbc4550b", "0xae7d915eb9fc928b65a29d6edbc75682d08584d0014f7bcf17d59118421ae07d26a02137d1e4de6938bcd1ab8ef48fad", "0x852f7e453b1af89b754df6d11a40d5d41ea057376e8ecacd705aacd2f917457f4a093d6b9a8801837fa0f62986ad7149", "0x92c6bf5ada5d0c3d4dd8058483de36c215fa98edab9d75242f3eff9db07c734ad67337da6f0eefe23a487bf75a600dee", "0xa2b42c09d0db615853763552a48d2e704542bbd786aae016eb58acbf6c0226c844f5fb31e428cb6450b9db855f8f2a6f", "0x880cc07968266dbfdcfbc21815cd69e0eddfee239167ac693fb0413912d816f2578a74f7716eecd6deefa68c6eccd394", "0xb885b3ace736cd373e8098bf75ba66fa1c6943ca1bc4408cd98ac7074775c4478594f91154b8a743d9c697e1b29f5840", "0xa51ce78de512bd87bfa0835de819941dffbf18bec23221b61d8096fc9436af64e0693c335b54e7bfc763f287bdca2db6", "0xa3c76166a3bdb9b06ef696e57603b58871bc72883ee9d45171a30fe6e1d50e30bc9c51b4a0f5a7270e19a77b89733850", "0xacefc5c6f8a1e7c24d7b41e0fc7f6f3dc0ede6cf3115ffb9a6e54b1d954cbca9bda8ad7a084be9be245a1b8e9770d141", "0xb420ed079941842510e31cfad117fa11fb6b4f97dfbc6298cb840f27ebaceba23eeaf3f513bcffbf5e4aae946310182d", "0x95c3bb5ef26c5ed2f035aa5d389c6b3c15a6705b9818a3fefaed28922158b35642b2e8e5a1a620fdad07e75ad4b43af4", "0x825149f9081ecf07a2a4e3e8b5d21bade86c1a882475d51c55ee909330b70c5a2ac63771c8600c6f38df716af61a3ea1", "0x873b935aae16d9f08adbc25353cee18af2f1b8d5f26dec6538d6bbddc515f2217ed7d235dcfea59ae61b428798b28637", "0x9294150843a2bedcedb3bb74c43eb28e759cf9499582c5430bccefb574a8ddd4f11f9929257ff4c153990f9970a2558f", "0xb619563a811cc531da07f4f04e5c4c6423010ff9f8ed7e6ec9449162e3d501b269fb1c564c09c0429431879b0f45df02", "0x91b509b87eb09f007d839627514658c7341bc76d468920fe8a740a8cb96a7e7e631e0ea584a7e3dc1172266f641d0f5c", "0x8b8aceace9a7b9b4317f1f01308c3904d7663856946afbcea141a1c615e21ccad06b71217413e832166e9dd915fbe098", "0x87b3b36e725833ea0b0f54753c3728c0dbc87c52d44d705ffc709f2d2394414c652d3283bab28dcce09799504996cee0", "0xb2670aad5691cbf308e4a6a77a075c4422e6cbe86fdba24e9f84a313e90b0696afb6a067eebb42ba2d10340d6a2f6e51", "0x876784a9aff3d54faa89b2bacd3ff5862f70195d0b2edc58e8d1068b3c9074c0da1cfa23671fe12f35e33b8a329c0ccd", "0x8b48b9e758e8a8eae182f5cbec96f67d20cca6d3eee80a2d09208eb1d5d872e09ef23d0df8ebbb9b01c7449d0e3e3650", "0xb79303453100654c04a487bdcadc9e3578bc80930c489a7069a52e8ca1dba36c492c8c899ce025f8364599899baa287d", "0x961b35a6111da54ece6494f24dacd5ea46181f55775b5f03df0e370c34a5046ac2b4082925855325bb42bc2a2c98381d", "0xa31feb1be3f5a0247a1f7d487987eb622e34fca817832904c6ee3ee60277e5847945a6f6ea1ac24542c72e47bdf647df", "0xa12a2aa3e7327e457e1aae30e9612715dd2cfed32892c1cd6dcda4e9a18203af8a44afb46d03b2eed89f6b9c5a2c0c23", "0xa08265a838e69a2ca2f80fead6ccf16f6366415b920c0b22ee359bcd8d4464ecf156f400a16a7918d52e6d733dd64211", "0xb723d6344e938d801cca1a00032af200e541d4471fd6cbd38fb9130daa83f6a1dffbbe7e67fc20f9577f884acd7594b2", "0xa6733d83ec78ba98e72ddd1e7ff79b7adb0e559e256760d0c590a986e742445e8cdf560d44b29439c26d87edd0b07c8c", "0xa61c2c27d3f7b9ff4695a17afedf63818d4bfba390507e1f4d0d806ce8778d9418784430ce3d4199fd3bdbc2504d2af3", "0x8332f3b63a6dc985376e8b1b25eeae68be6160fbe40053ba7bcf6f073204f682da72321786e422d3482fd60c9e5aa034", "0xa280f44877583fbb6b860d500b1a3f572e3ee833ec8f06476b3d8002058e25964062feaa1e5bec1536d734a5cfa09145", "0xa4026a52d277fcea512440d2204f53047718ebfcae7b48ac57ea7f6bfbc5de9d7304db9a9a6cbb273612281049ddaec5", "0x95cdf69c831ab2fad6c2535ede9c07e663d2ddccc936b64e0843d2df2a7b1c31f1759c3c20f1e7a57b1c8f0dbb21b540", "0x95c96cec88806469c277ab567863c5209027cecc06c7012358e5f555689c0d9a5ffb219a464f086b45817e8536b86d2f", "0xafe38d4684132a0f03d806a4c8df556bf589b25271fbc6fe2e1ed16de7962b341c5003755da758d0959d2e6499b06c68", "0xa9b77784fda64987f97c3a23c5e8f61b918be0f7c59ba285084116d60465c4a2aaafc8857eb16823282cc83143eb9126", "0xa830f05881ad3ce532a55685877f529d32a5dbe56cea57ffad52c4128ee0fad0eeaf0da4362b55075e77eda7babe70e5", "0x992b3ad190d6578033c13ed5abfee4ef49cbc492babb90061e3c51ee4b5790cdd4c8fc1abff1fa2c00183b6b64f0bbbe", "0xb1015424d9364aeff75de191652dc66484fdbec3e98199a9eb9671ec57bec6a13ff4b38446e28e4d8aedb58dd619cd90", "0xa745304604075d60c9db36cada4063ac7558e7ec2835d7da8485e58d8422e817457b8da069f56511b02601289fbb8981", "0xa5ba4330bc5cb3dbe0486ddf995632a7260a46180a08f42ae51a2e47778142132463cc9f10021a9ad36986108fefa1a9", "0xb419e9fd4babcaf8180d5479db188bb3da232ae77a1c4ed65687c306e6262f8083070a9ac32220cddb3af2ec73114092", "0xa49e23dc5f3468f3bf3a0bb7e4a114a788b951ff6f23a3396ae9e12cbff0abd1240878a3d1892105413dbc38818e807c", "0xb7ecc7b4831f650202987e85b86bc0053f40d983f252e9832ef503aea81c51221ce93279da4aa7466c026b2d2070e55d", "0x96a8c35cb87f84fa84dcd6399cc2a0fd79cc9158ef4bdde4bae31a129616c8a9f2576cd19baa3f497ca34060979aed7d", "0x8681b2c00aa62c2b519f664a95dcb8faef601a3b961bb4ce5d85a75030f40965e2983871d41ea394aee934e859581548", "0x85c229a07efa54a713d0790963a392400f55fbb1a43995a535dc6c929f20d6a65cf4efb434e0ad1cb61f689b8011a3bc", "0x90856f7f3444e5ad44651c28e24cc085a5db4d2ffe79aa53228c26718cf53a6e44615f3c5cda5aa752d5f762c4623c66", "0x978999b7d8aa3f28a04076f74d11c41ef9c89fdfe514936c4238e0f13c38ec97e51a5c078ebc6409e517bfe7ccb42630", "0xa099914dd7ed934d8e0d363a648e9038eb7c1ec03fa04dbcaa40f7721c618c3ef947afef7a16b4d7ac8c12aa46637f03", "0xab2a104fed3c83d16f2cda06878fa5f30c8c9411de71bfb67fd2fc9aa454dcbcf3d299d72f8cc12e919466a50fcf7426", "0xa4471d111db4418f56915689482f6144efc4664cfb0311727f36c864648d35734351becc48875df96f4abd3cfcf820f9", "0x83be11727cd30ea94ccc8fa31b09b81c9d6a9a5d3a4686af9da99587332fe78c1f94282f9755854bafd6033549afec91", "0x88020ff971dc1a01a9e993cd50a5d2131ffdcbb990c1a6aaa54b20d8f23f9546a70918ea57a21530dcc440c1509c24ad", "0xae24547623465e87905eaffa1fa5d52bb7c453a8dbd89614fa8819a2abcedaf455c2345099b7324ae36eb0ad7c8ef977", "0xb59b0c60997de1ee00b7c388bc7101d136c9803bf5437b1d589ba57c213f4f835a3e4125b54738e78abbc21b000f2016", "0xa584c434dfe194546526691b68fa968c831c31da42303a1d735d960901c74011d522246f37f299555416b8cf25c5a548", "0x80408ce3724f4837d4d52376d255e10f69eb8558399ae5ca6c11b78b98fe67d4b93157d2b9b639f1b5b64198bfe87713", "0xabb941e8d406c2606e0ddc35c113604fdd9d249eacc51cb64e2991e551b8639ce44d288cc92afa7a1e7fc599cfc84b22", "0xb223173f560cacb1c21dba0f1713839e348ad02cbfdef0626748604c86f89e0f4c919ed40b583343795bdd519ba952c8", "0xaf1c70512ec3a19d98b8a1fc3ff7f7f5048a27d17d438d43f561974bbdd116fcd5d5c21040f3447af3f0266848d47a15", "0x8a44809568ebe50405bede19b4d2607199159b26a1b33e03d180e6840c5cf59d991a4fb150d111443235d75ecad085b7", "0xb06207cdca46b125a27b3221b5b50cf27af4c527dd7c80e2dbcebbb09778a96df3af67e50f07725239ce3583dad60660", "0x993352d9278814ec89b26a11c4a7c4941bf8f0e6781ae79559d14749ee5def672259792db4587f85f0100c7bb812f933", "0x9180b8a718b971fd27bc82c8582d19c4b4f012453e8c0ffeeeffe745581fc6c07875ab28be3af3fa3896d19f0c89ac5b", "0x8b8e1263eb48d0fe304032dd5ea1f30e73f0121265f7458ba9054d3626894e8a5fef665340abd2ede9653045c2665938", "0x99a2beee4a10b7941c24b2092192faf52b819afd033e4a2de050fd6c7f56d364d0cf5f99764c3357cf32399e60fc5d74", "0x946a4aad7f8647ea60bee2c5fcdeb6f9a58fb2cfca70c4d10e458027a04846e13798c66506151be3df9454b1e417893f", "0xa672a88847652d260b5472d6908d1d57e200f1e492d30dd1cecc441cdfc9b76e016d9bab560efd4d7f3c30801de884a9", "0x9414e1959c156cde1eb24e628395744db75fc24b9df4595350aaad0bc38e0246c9b4148f6443ef68b8e253a4a6bcf11c", "0x9316e9e4ec5fab4f80d6540df0e3a4774db52f1d759d2e5b5bcd3d7b53597bb007eb1887cb7dc61f62497d51ffc8d996", "0x902d6d77bb49492c7a00bc4b70277bc28c8bf9888f4307bb017ac75a962decdedf3a4e2cf6c1ea9f9ba551f4610cbbd7", "0xb07025a18b0e32dd5e12ec6a85781aa3554329ea12c4cd0d3b2c22e43d777ef6f89876dd90a9c8fb097ddf61cf18adc5", "0xb355a849ad3227caa4476759137e813505ec523cbc2d4105bc7148a4630f9e81918d110479a2d5f5e4cd9ccec9d9d3e3", "0xb49532cfdf02ee760109881ad030b89c48ee3bb7f219ccafc13c93aead754d29bdafe345be54c482e9d5672bd4505080", "0x9477802410e263e4f938d57fa8f2a6cac7754c5d38505b73ee35ea3f057aad958cb9722ba6b7b3cfc4524e9ca93f9cdc", "0x9148ea83b4436339580f3dbc9ba51509e9ab13c03063587a57e125432dd0915f5d2a8f456a68f8fff57d5f08c8f34d6e", "0xb00b6b5392b1930b54352c02b1b3b4f6186d20bf21698689bbfc7d13e86538a4397b90e9d5c93fd2054640c4dbe52a4f", "0x926a9702500441243cd446e7cbf15dde16400259726794694b1d9a40263a9fc9e12f7bcbf12a27cb9aaba9e2d5848ddc", "0xa0c6155f42686cbe7684a1dc327100962e13bafcf3db97971fc116d9f5c0c8355377e3d70979cdbd58fd3ea52440901c", "0xa277f899f99edb8791889d0817ea6a96c24a61acfda3ad8c3379e7c62b9d4facc4b965020b588651672fd261a77f1bfc", "0x8f528cebb866b501f91afa50e995234bef5bf20bff13005de99cb51eaac7b4f0bf38580cfd0470de40f577ead5d9ba0f", "0x963fc03a44e9d502cc1d23250efef44d299befd03b898d07ce63ca607bb474b5cf7c965a7b9b0f32198b04a8393821f7", "0xab087438d0a51078c378bf4a93bd48ef933ff0f1fa68d02d4460820df564e6642a663b5e50a5fe509527d55cb510ae04", "0xb0592e1f2c54746bb076be0fa480e1c4bebc4225e1236bcda3b299aa3853e3afb401233bdbcfc4a007b0523a720fbf62", "0x851613517966de76c1c55a94dc4595f299398a9808f2d2f0a84330ba657ab1f357701d0895f658c18a44cb00547f6f57", "0xa2fe9a1dd251e72b0fe4db27be508bb55208f8f1616b13d8be288363ec722826b1a1fd729fc561c3369bf13950bf1fd6", "0xb896cb2bc2d0c77739853bc59b0f89b2e008ba1f701c9cbe3bef035f499e1baee8f0ff1e794854a48c320586a2dfc81a", "0xa1b60f98e5e5106785a9b81a85423452ee9ef980fa7fa8464f4366e73f89c50435a0c37b2906052b8e58e212ebd366cf", "0xa853b0ebd9609656636df2e6acd5d8839c0fda56f7bf9288a943b06f0b67901a32b95e016ca8bc99bd7b5eab31347e72", "0xb290fa4c1346963bd5225235e6bdf7c542174dab4c908ab483d1745b9b3a6015525e398e1761c90e4b49968d05e30eea", "0xb0f65a33ad18f154f1351f07879a183ad62e5144ad9f3241c2d06533dad09cbb2253949daff1bb02d24d16a3569f7ef0", "0xa00db59b8d4218faf5aeafcd39231027324408f208ec1f54d55a1c41228b463b88304d909d16b718cfc784213917b71e", "0xb8d695dd33dc2c3bc73d98248c535b2770ad7fa31aa726f0aa4b3299efb0295ba9b4a51c71d314a4a1bd5872307534d1", "0xb848057cca2ca837ee49c42b88422303e58ea7d2fc76535260eb5bd609255e430514e927cc188324faa8e657396d63ec", "0x92677836061364685c2aaf0313fa32322746074ed5666fd5f142a7e8f87135f45cd10e78a17557a4067a51dfde890371", "0xa854b22c9056a3a24ab164a53e5c5cf388616c33e67d8ebb4590cb16b2e7d88b54b1393c93760d154208b5ca822dc68f", "0x86fff174920388bfab841118fb076b2b0cdec3fdb6c3d9a476262f82689fb0ed3f1897f7be9dbf0932bb14d346815c63", "0x99661cf4c94a74e182752bcc4b98a8c2218a8f2765642025048e12e88ba776f14f7be73a2d79bd21a61def757f47f904", "0x8a8893144d771dca28760cba0f950a5d634195fd401ec8cf1145146286caffb0b1a6ba0c4c1828d0a5480ce49073c64c", "0x938a59ae761359ee2688571e7b7d54692848eb5dde57ffc572b473001ea199786886f8c6346a226209484afb61d2e526", "0x923f68a6aa6616714cf077cf548aeb845bfdd78f2f6851d8148cba9e33a374017f2f3da186c39b82d14785a093313222", "0xac923a93d7da7013e73ce8b4a2b14b8fd0cc93dc29d5de941a70285bdd19be4740fedfe0c56b046689252a3696e9c5bc", "0xb49b32c76d4ec1a2c68d4989285a920a805993bc6fcce6dacd3d2ddae73373050a5c44ba8422a3781050682fa0ef6ba2", "0x8a367941c07c3bdca5712524a1411bad7945c7c48ffc7103b1d4dff2c25751b0624219d1ccde8c3f70c465f954be5445", "0xb838f029df455efb6c530d0e370bbbf7d87d61a9aea3d2fe5474c5fe0a39cf235ceecf9693c5c6c5820b1ba8f820bd31", "0xa8983b7c715eaac7f13a001d2abc462dfc1559dab4a6b554119c271aa8fe00ffcf6b6949a1121f324d6d26cb877bcbae", "0xa2afb24ad95a6f14a6796315fbe0d8d7700d08f0cfaf7a2abe841f5f18d4fecf094406cbd54da7232a159f9c5b6e805e", "0x87e8e95ad2d62f947b2766ff405a23f7a8afba14e7f718a691d95369c79955cdebe24c54662553c60a3f55e6322c0f6f", "0x87c2cbcecb754e0cc96128e707e5c5005c9de07ffd899efa3437cadc23362f5a1d3fcdd30a1f5bdc72af3fb594398c2a", "0x91afd6ee04f0496dc633db88b9370d41c428b04fd991002502da2e9a0ef051bcd7b760e860829a44fbe5539fa65f8525", "0x8c50e5d1a24515a9dd624fe08b12223a75ca55196f769f24748686315329b337efadca1c63f88bee0ac292dd0a587440", "0x8a07e8f912a38d94309f317c32068e87f68f51bdfa082d96026f5f5f8a2211621f8a3856dda8069386bf15fb2d28c18f", "0x94ad1dbe341c44eeaf4dc133eed47d8dbfe752575e836c075745770a6679ff1f0e7883b6aa917462993a7f469d74cab5", "0x8745f8bd86c2bb30efa7efb7725489f2654f3e1ac4ea95bd7ad0f3cfa223055d06c187a16192d9d7bdaea7b050c6a324", "0x900d149c8d79418cda5955974c450a70845e02e5a4ecbcc584a3ca64d237df73987c303e3eeb79da1af83bf62d9e579f", "0x8f652ab565f677fb1a7ba03b08004e3cda06b86c6f1b0b9ab932e0834acf1370abb2914c15b0d08327b5504e5990681c", "0x9103097d088be1f75ab9d3da879106c2f597e2cc91ec31e73430647bdd5c33bcfd771530d5521e7e14df6acda44f38a6", "0xb0fec7791cfb0f96e60601e1aeced9a92446b61fedab832539d1d1037558612d78419efa87ff5f6b7aab8fd697d4d9de", "0xb9d2945bdb188b98958854ba287eb0480ef614199c4235ce5f15fc670b8c5ffe8eeb120c09c53ea8a543a022e6a321ac", "0xa9461bb7d5490973ebaa51afc0bb4a5e42acdccb80e2f939e88b77ac28a98870e103e1042899750f8667a8cc9123bae9", "0xa37fdf11d4bcb2aed74b9f460a30aa34afea93386fa4cdb690f0a71bc58f0b8df60bec56e7a24f225978b862626fa00e", "0xa214420e183e03d531cf91661466ea2187d84b6e814b8b20b3730a9400a7d25cf23181bb85589ebc982cec414f5c2923", "0xad09a45a698a6beb3e0915f540ef16e9af7087f53328972532d6b5dfe98ce4020555ece65c6cbad8bd6be8a4dfefe6fd", "0xab6742800b02728c92d806976764cb027413d6f86edd08ad8bb5922a2969ee9836878cd39db70db0bd9a2646862acc4f", "0x974ca9305bd5ea1dc1755dff3b63e8bfe9f744321046c1395659bcea2a987b528e64d5aa96ac7b015650b2253b37888d", "0x84eee9d6bce039c52c2ebc4fccc0ad70e20c82f47c558098da4be2f386a493cbc76adc795b5488c8d11b6518c2c4fab8", "0x875d7bda46efcb63944e1ccf760a20144df3b00d53282b781e95f12bfc8f8316dfe6492c2efbf796f1150e36e436e9df", "0xb68a2208e0c587b5c31b5f6cb32d3e6058a9642e2d9855da4f85566e1412db528475892060bb932c55b3a80877ad7b4a", "0xba006368ecab5febb6ab348644d9b63de202293085ed468df8bc24d992ae8ce468470aa37f36a73630c789fb9c819b30", "0x90a196035150846cd2b482c7b17027471372a8ce7d914c4d82b6ea7fa705d8ed5817bd42d63886242585baf7d1397a1c", "0xa223b4c85e0daa8434b015fd9170b5561fe676664b67064974a1e9325066ecf88fc81f97ab5011c59fad28cedd04b240", "0x82e8ec43139cf15c6bbeed484b62e06cded8a39b5ce0389e4cbe9c9e9c02f2f0275d8d8d4e8dfec8f69a191bef220408", "0x81a3fc07a7b68d92c6ee4b6d28f5653ee9ec85f7e2ee1c51c075c1b130a8c5097dc661cf10c5aff1c7114b1a6a19f11a", "0x8ed2ef8331546d98819a5dd0e6c9f8cb2630d0847671314a28f277faf68da080b53891dd75c82cbcf7788b255490785d", "0xacecabf84a6f9bbed6b2fc2e7e4b48f02ef2f15e597538a73aea8f98addc6badda15e4695a67ecdb505c1554e8f345ec", "0xb8f51019b2aa575f8476e03dcadf86cc8391f007e5f922c2a36b2daa63f5a503646a468990cd5c65148d323942193051", "0xaaa595a84b403ec65729bc1c8055a94f874bf9adddc6c507b3e1f24f79d3ad359595a672b93aab3394db4e2d4a7d8970", "0x895144c55fcbd0f64d7dd69e6855cfb956e02b5658eadf0f026a70703f3643037268fdd673b0d21b288578a83c6338dd", "0xa2e92ae6d0d237d1274259a8f99d4ea4912a299816350b876fba5ebc60b714490e198a916e1c38c6e020a792496fa23c", "0xa45795fda3b5bb0ad1d3c628f6add5b2a4473a1414c1a232e80e70d1cfffd7f8a8d9861f8df2946999d7dbb56bf60113", "0xb6659bf7f6f2fef61c39923e8c23b8c70e9c903028d8f62516d16755cd3fba2fe41c285aa9432dc75ab08f8a1d8a81fc", "0xa735609a6bc5bfd85e58234fc439ff1f58f1ff1dd966c5921d8b649e21f006bf2b8642ad8a75063c159aaf6935789293", "0xa3c622eb387c9d15e7bda2e3e84d007cb13a6d50d655c3f2f289758e49d3b37b9a35e4535d3cc53d8efd51f407281f19", "0x8afe147b53ad99220f5ef9d763bfc91f9c20caecbcf823564236fb0e6ede49414c57d71eec4772c8715cc65a81af0047", "0xb5f0203233cf71913951e9c9c4e10d9243e3e4a1f2cb235bf3f42009120ba96e04aa414c9938ea8873b63148478927e8", "0x93c52493361b458d196172d7ba982a90a4f79f03aa8008edc322950de3ce6acf4c3977807a2ffa9e924047e02072b229", "0xb9e72b805c8ac56503f4a86c82720afbd5c73654408a22a2ac0b2e5caccdfb0e20b59807433a6233bc97ae58cf14c70a", "0xaf0475779b5cee278cca14c82da2a9f9c8ef222eb885e8c50cca2315fea420de6e04146590ed0dd5a29c0e0812964df5", "0xb430ccab85690db02c2d0eb610f3197884ca12bc5f23c51e282bf3a6aa7e4a79222c3d8761454caf55d6c01a327595f9", "0x830032937418b26ee6da9b5206f3e24dc76acd98589e37937e963a8333e5430abd6ce3dd93ef4b8997bd41440eed75d6", "0x8820a6d73180f3fe255199f3f175c5eb770461ad5cfdde2fb11508041ed19b8c4ce66ad6ecebf7d7e836cc2318df47ca", "0xaef1393e7d97278e77bbf52ef6e1c1d5db721ccf75fe753cf47a881fa034ca61eaa5098ee5a344c156d2b14ff9e284ad", "0x8a4a26c07218948c1196c45d927ef4d2c42ade5e29fe7a91eaebe34a29900072ce5194cf28d51f746f4c4c649daf4396", "0x84011dc150b7177abdcb715efbd8c201f9cb39c36e6069af5c50a096021768ba40cef45b659c70915af209f904ede3b6", "0xb1bd90675411389bb66910b21a4bbb50edce5330850c5ab0b682393950124252766fc81f5ecfc72fb7184387238c402e", "0x8dfdcd30583b696d2c7744655f79809f451a60c9ad5bf1226dc078b19f4585d7b3ef7fa9d54e1ac09520d95cbfd20928", "0xb351b4dc6d98f75b8e5a48eb7c6f6e4b78451991c9ba630e5a1b9874c15ac450cd409c1a024713bf2cf82dc400e025ef", "0xa462b8bc97ac668b97b28b3ae24b9f5de60e098d7b23ecb600d2194cd35827fb79f77c3e50d358f5bd72ee83fef18fa0", "0xa183753265c5f7890270821880cce5f9b2965b115ba783c6dba9769536f57a04465d7da5049c7cf8b3fcf48146173c18", "0xa8a771b81ed0d09e0da4d79f990e58eabcd2be3a2680419502dd592783fe52f657fe55125b385c41d0ba3b9b9cf54a83", "0xa71ec577db46011689d073245e3b1c3222a9b1fe6aa5b83629adec5733dd48617ebea91346f0dd0e6cdaa86e4931b168", "0xa334b8b244f0d598a02da6ae0f918a7857a54dce928376c4c85df15f3b0f2ba3ac321296b8b7c9dd47d770daf16c8f8c", "0xa29037f8ef925c417c90c4df4f9fb27fb977d04e2b3dd5e8547d33e92ab72e7a00f5461de21e28835319eae5db145eb7", "0xb91054108ae78b00e3298d667b913ebc44d8f26e531eae78a8fe26fdfb60271c97efb2dee5f47ef5a3c15c8228138927", "0x926c13efbe90604f6244be9315a34f72a1f8d1aab7572df431998949c378cddbf2fe393502c930fff614ff06ae98a0ce", "0x995c758fd5600e6537089b1baa4fbe0376ab274ff3e82a17768b40df6f91c2e443411de9cafa1e65ea88fb8b87d504f4", "0x9245ba307a7a90847da75fca8d77ec03fdfc812c871e7a2529c56a0a79a6de16084258e7a9ac4ae8a3756f394336e21c", "0x99e0cfa2bb57a7e624231317044c15e52196ecce020db567c8e8cb960354a0be9862ee0c128c60b44777e65ac315e59f", "0xad4f6b3d27bbbb744126601053c3dc98c07ff0eb0b38a898bd80dce778372846d67e5ab8fb34fb3ad0ef3f235d77ba7f", "0xa0f12cae3722bbbca2e539eb9cc7614632a2aefe51410430070a12b5bc5314ecec5857b7ff8f41e9980cac23064f7c56", "0xb487f1bc59485848c98222fd3bc36c8c9bb3d2912e2911f4ceca32c840a7921477f9b1fe00877e05c96c75d3eecae061", "0xa6033db53925654e18ecb3ce715715c36165d7035db9397087ac3a0585e587998a53973d011ac6d48af439493029cee6", "0xa6b4d09cd01c70a3311fd131d3710ccf97bde3e7b80efd5a8c0eaeffeb48cca0f951ced905290267b115b06d46f2693b", "0xa9dff1df0a8f4f218a98b6f818a693fb0d611fed0fc3143537cbd6578d479af13a653a8155e535548a2a0628ae24fa58", "0xa58e469f65d366b519f9a394cacb7edaddac214463b7b6d62c2dbc1316e11c6c5184ce45c16de2d77f990dcdd8b55430", "0x989e71734f8119103586dc9a3c5f5033ddc815a21018b34c1f876cdfc112efa868d5751bf6419323e4e59fa6a03ece1c", "0xa2da00e05036c884369e04cf55f3de7d659cd5fa3f849092b2519dd263694efe0f051953d9d94b7e121f0aee8b6174d7", "0x968f3c029f57ee31c4e1adea89a7f92e28483af9a74f30fbdb995dc2d40e8e657dff8f8d340d4a92bf65f54440f2859f", "0x932778df6f60ac1639c1453ef0cbd2bf67592759dcccb3e96dcc743ff01679e4c7dd0ef2b0833dda548d32cb4eba49e2", "0xa805a31139f8e0d6dae1ac87d454b23a3dc9fc653d4ca18d4f8ebab30fc189c16e73981c2cb7dd6f8c30454a5208109d", "0xa9ba0991296caa2aaa4a1ceacfb205544c2a2ec97088eace1d84ee5e2767656a172f75d2f0c4e16a3640a0e0dec316e0", "0xb1e49055c968dced47ec95ae934cf45023836d180702e20e2df57e0f62fb85d7ac60d657ba3ae13b8560b67210449459", "0xa94e1da570a38809c71e37571066acabff7bf5632737c9ab6e4a32856924bf6211139ab3cedbf083850ff2d0e0c0fcfc", "0x88ef1bb322000c5a5515b310c838c9af4c1cdbb32eab1c83ac3b2283191cd40e9573747d663763a28dad0d64adc13840", "0xa987ce205f923100df0fbd5a85f22c9b99b9b9cbe6ddfa8dfda1b8fe95b4f71ff01d6c5b64ca02eb24edb2b255a14ef0", "0x84fe8221a9e95d9178359918a108de4763ebfa7a6487facb9c963406882a08a9a93f492f8e77cf9e7ea41ae079c45993", "0xaa1cf3dc7c5dcfa15bbbc811a4bb6dbac4fba4f97fb1ed344ab60264d7051f6eef19ea9773441d89929ee942ed089319", "0x8f6a7d610d59d9f54689bbe6a41f92d9f6096cde919c1ab94c3c7fcecf0851423bc191e5612349e10f855121c0570f56", "0xb5af1fa7894428a53ea520f260f3dc3726da245026b6d5d240625380bfb9c7c186df0204bb604efac5e613a70af5106e", "0xa5bce6055ff812e72ce105f147147c7d48d7a2313884dd1f488b1240ee320f13e8a33f5441953a8e7a3209f65b673ce1", "0xb9b55b4a1422677d95821e1d042ab81bbf0bf087496504021ec2e17e238c2ca6b44fb3b635a5c9eac0871a724b8d47c3", "0x941c38e533ce4a673a3830845b56786585e5fe49c427f2e5c279fc6db08530c8f91db3e6c7822ec6bb4f956940052d18", "0xa38e191d66c625f975313c7007bbe7431b5a06ed2da1290a7d5d0f2ec73770d476efd07b8e632de64597d47df175cbb0", "0x94ba76b667abf055621db4c4145d18743a368d951565632ed4e743dd50dd3333507c0c34f286a5c5fdbf38191a2255cd", "0xa5ca38c60be5602f2bfa6e00c687ac96ac36d517145018ddbee6f12eb0faa63dd57909b9eeed26085fe5ac44e55d10ab", "0xb00fea3b825e60c1ed1c5deb4b551aa65a340e5af36b17d5262c9cd2c508711e4dc50dc2521a2c16c7c901902266e64a", "0x971b86fc4033485e235ccb0997a236206ba25c6859075edbcdf3c943116a5030b7f75ebca9753d863a522ba21a215a90", "0xb3b31f52370de246ee215400975b674f6da39b2f32514fe6bd54e747752eedca22bb840493b44a67df42a3639c5f901f", "0xaffbbfac9c1ba7cbfa1839d2ae271dd6149869b75790bf103230637da41857fc326ef3552ff31c15bda0694080198143", "0xa95d42aa7ef1962520845aa3688f2752d291926f7b0d73ea2ee24f0612c03b43f2b0fe3c9a9a99620ffc8d487b981bc2", "0x914a266065caf64985e8c5b1cb2e3f4e3fe94d7d085a1881b1fefa435afef4e1b39a98551d096a62e4f5cc1a7f0fdc2e", "0x81a0b4a96e2b75bc1bf2dbd165d58d55cfd259000a35504d1ffb18bc346a3e6f07602c683723864ffb980f840836fd8d", "0x91c1556631cddd4c00b65b67962b39e4a33429029d311c8acf73a18600e362304fb68bccb56fde40f49e95b7829e0b87", "0x8befbacc19e57f7c885d1b7a6028359eb3d80792fe13b92a8400df21ce48deb0bb60f2ddb50e3d74f39f85d7eab23adc", "0x92f9458d674df6e990789690ec9ca73dacb67fc9255b58c417c555a8cc1208ace56e8e538f86ba0f3615573a0fbac00d", "0xb4b1b3062512d6ae7417850c08c13f707d5838e43d48eb98dd4621baf62eee9e82348f80fe9b888a12874bfa538771f8", "0xa13c4a3ac642ede37d9c883f5319e748d2b938f708c9d779714108a449b343f7b71a6e3ef4080fee125b416762920273", "0xaf44983d5fc8cceee0551ef934e6e653f2d3efa385e5c8a27a272463a6f333e290378cc307c2b664eb923c78994e706e", "0xa389fd6c59fe2b4031cc244e22d3991e541bd203dd5b5e73a6159e72df1ab41d49994961500dcde7989e945213184778", "0x8d2141e4a17836c548de9598d7b298b03f0e6c73b7364979a411c464e0628e21cff6ac3d6decdba5d1c4909eff479761", "0x980b22ef53b7bdf188a3f14bc51b0dbfdf9c758826daa3cbc1e3986022406a8aa9a6a79e400567120b88c67faa35ce5f", "0xa28882f0a055f96df3711de5d0aa69473e71245f4f3e9aa944e9d1fb166e02caa50832e46da6d3a03b4801735fd01b29", "0x8db106a37d7b88f5d995c126abb563934dd8de516af48e85695d02b1aea07f79217e3cdd03c6f5ca57421830186c772b", "0xb5a7e50da0559a675c472f7dfaee456caab6695ab7870541b2be8c2b118c63752427184aad81f0e1afc61aef1f28c46f", "0x9962118780e20fe291d10b64f28d09442a8e1b5cffd0f3dd68d980d0614050a626c616b44e9807fbee7accecae00686a", "0xb38ddf33745e8d2ad6a991aefaf656a33c5f8cbe5d5b6b6fd03bd962153d8fd0e01b5f8f96d80ae53ab28d593ab1d4e7", "0x857dc12c0544ff2c0c703761d901aba636415dee45618aba2e3454ff9cbc634a85c8b05565e88520ff9be2d097c8b2b1", "0xa80d465c3f8cc63af6d74a6a5086b626c1cb4a8c0fee425964c3bd203d9d7094e299f81ce96d58afc20c8c9a029d9dae", "0x89e1c8fbde8563763be483123a3ed702efac189c6d8ab4d16c85e74bbaf856048cc42d5d6e138633a38572ba5ec3f594", "0x893a594cf495535f6d216508f8d03c317dcf03446668cba688da90f52d0111ac83d76ad09bf5ea47056846585ee5c791", "0xaadbd8be0ae452f7f9450c7d2957598a20cbf10139a4023a78b4438172d62b18b0de39754dd2f8862dbd50a3a0815e53", "0xae7d39670ecca3eb6db2095da2517a581b0e8853bdfef619b1fad9aacd443e7e6a40f18209fadd44038a55085c5fe8b2", "0x866ef241520eacb6331593cfcb206f7409d2f33d04542e6e52cba5447934e02d44c471f6c9a45963f9307e9809ab91d9", "0xb1a09911ad3864678f7be79a9c3c3eb5c84a0a45f8dcb52c67148f43439aeaaa9fd3ed3471276b7e588b49d6ebe3033a", "0xadd07b7f0dbb34049cd8feeb3c18da5944bf706871cfd9f14ff72f6c59ad217ebb1f0258b13b167851929387e4e34cfe", "0xae048892d5c328eefbdd4fba67d95901e3c14d974bfc0a1fc68155ca9f0d59e61d7ba17c6c9948b120cf35fd26e6fee9", "0x9185b4f3b7da0ddb4e0d0f09b8a9e0d6943a4611e43f13c3e2a767ed8592d31e0ba3ebe1914026a3627680274291f6e5", "0xa9c022d4e37b0802284ce3b7ee9258628ab4044f0db4de53d1c3efba9de19d15d65cc5e608dbe149c21c2af47d0b07b5", "0xb24dbd5852f8f24921a4e27013b6c3fa8885b973266cb839b9c388efad95821d5d746348179dcc07542bd0d0aefad1ce", "0xb5fb4f279300876a539a27a441348764908bc0051ebd66dc51739807305e73db3d2f6f0f294ffb91b508ab150eaf8527", "0xace50841e718265b290c3483ed4b0fdd1175338c5f1f7530ae9a0e75d5f80216f4de37536adcbc8d8c95982e88808cd0", "0xb19cadcde0f63bd1a9c24bd9c2806f53c14c0b9735bf351601498408ba503ddbd2037c891041cbba47f58b8c483f3b21", "0xb6061e63558d312eb891b97b39aa552fa218568d79ee26fe6dd5b864aea9e3216d8f2e2f3b093503be274766dac41426", "0x89730fdb2876ab6f0fe780d695f6e12090259027e789b819956d786e977518057e5d1d7f5ab24a3ae3d5d4c97773bd2b", "0xb6fa841e81f9f2cad0163a02a63ae96dc341f7ae803b616efc6e1da2fbea551c1b96b11ad02c4afbdf6d0cc9f23da172", "0x8fb66187182629c861ddb6896d7ed3caf2ad050c3dba8ab8eb0d7a2c924c3d44c48d1a148f9e33fb1f061b86972f8d21", "0x86022ac339c1f84a7fa9e05358c1a5b316b4fc0b83dbe9c8c7225dc514f709d66490b539359b084ce776e301024345fa", "0xb50b9c321468da950f01480bb62b6edafd42f83c0001d6e97f2bd523a1c49a0e8574fb66380ea28d23a7c4d54784f9f0", "0xa31c05f7032f30d1dac06678be64d0250a071fd655e557400e4a7f4c152be4d5c7aa32529baf3e5be7c4bd49820054f6", "0xb95ac0848cd322684772119f5b682d90a66bbf9dac411d9d86d2c34844bbd944dbaf8e47aa41380455abd51687931a78", "0xae4a6a5ce9553b65a05f7935e61e496a4a0f6fd8203367a2c627394c9ce1e280750297b74cdc48fd1d9a31e93f97bef4", "0xa22daf35f6e9b05e52e0b07f7bd1dbbebd2c263033fb0e1b2c804e2d964e2f11bc0ece6aca6af079dd3a9939c9c80674", "0x902150e0cb1f16b9b59690db35281e28998ce275acb313900da8b2d8dfd29fa1795f8ca3ff820c31d0697de29df347c1", "0xb17b5104a5dc665cdd7d47e476153d715eb78c6e5199303e4b5445c21a7fa7cf85fe7cfd08d7570f4e84e579b005428c", "0xa03f49b81c15433f121680aa02d734bb9e363af2156654a62bcb5b2ba2218398ccb0ff61104ea5d7df5b16ea18623b1e", "0x802101abd5d3c88876e75a27ffc2f9ddcce75e6b24f23dba03e5201281a7bd5cc7530b6a003be92d225093ca17d3c3bb", "0xa4d183f63c1b4521a6b52226fc19106158fc8ea402461a5cccdaa35fee93669df6a8661f45c1750cd01308149b7bf08e", "0x8d17c22e0c8403b69736364d460b3014775c591032604413d20a5096a94d4030d7c50b9fe3240e31d0311efcf9816a47", "0x947225acfcce5992eab96276f668c3cbe5f298b90a59f2bb213be9997d8850919e8f496f182689b5cbd54084a7332482", "0x8df6f4ed216fc8d1905e06163ba1c90d336ab991a18564b0169623eb39b84e627fa267397da15d3ed754d1f3423bff07", "0x83480007a88f1a36dea464c32b849a3a999316044f12281e2e1c25f07d495f9b1710b4ba0d88e9560e72433addd50bc2", "0xb3019d6e591cf5b33eb972e49e06c6d0a82a73a75d78d383dd6f6a4269838289e6e07c245f54fed67f5c9bb0fd5e1c5f", "0x92e8ce05e94927a9fb02debadb99cf30a26172b2705003a2c0c47b3d8002bf1060edb0f6a5750aad827c98a656b19199", "0xac2aff801448dbbfc13cca7d603fd9c69e82100d997faf11f465323b97255504f10c0c77401e4d1890339d8b224f5803", "0xb0453d9903d08f508ee27e577445dc098baed6cde0ac984b42e0f0efed62760bd58d5816cf1e109d204607b7b175e30c", "0xae68dc4ba5067e825d46d2c7c67f1009ceb49d68e8d3e4c57f4bcd299eb2de3575d42ea45e8722f8f28497a6e14a1cfe", "0xb22486c2f5b51d72335ce819bbafb7fa25eb1c28a378a658f13f9fc79cd20083a7e573248d911231b45a5cf23b561ca7", "0x89d1201d1dbd6921867341471488b4d2fd0fc773ae1d4d074c78ae2eb779a59b64c00452c2a0255826fca6b3d03be2b1", "0xa2998977c91c7a53dc6104f5bc0a5b675e5350f835e2f0af69825db8af4aeb68435bdbcc795f3dd1f55e1dd50bc0507f", "0xb0be4937a925b3c05056ed621910d535ccabf5ab99fd3b9335080b0e51d9607d0fd36cb5781ff340018f6acfca4a9736", "0xaea145a0f6e0ba9df8e52e84bb9c9de2c2dc822f70d2724029b153eb68ee9c17de7d35063dcd6a39c37c59fdd12138f7", "0x91cb4545d7165ee8ffbc74c874baceca11fdebbc7387908d1a25877ca3c57f2c5def424dab24148826832f1e880bede0", "0xb3b579cb77573f19c571ad5eeeb21f65548d7dff9d298b8d7418c11f3e8cd3727c5b467f013cb87d6861cfaceee0d2e3", "0xb98a1eeec2b19fecc8378c876d73645aa52fb99e4819903735b2c7a885b242787a30d1269a04bfb8573d72d9bbc5f0f0", "0x940c1f01ed362bd588b950c27f8cc1d52276c71bb153d47f07ec85b038c11d9a8424b7904f424423e714454d5e80d1cd", "0xaa343a8ecf09ce11599b8cf22f7279cf80f06dbf9f6d62cb05308dbbb39c46fd0a4a1240b032665fbb488a767379b91b", "0x87c3ac72084aca5974599d3232e11d416348719e08443acaba2b328923af945031f86432e170dcdd103774ec92e988c9", "0x91d6486eb5e61d2b9a9e742c20ec974a47627c6096b3da56209c2b4e4757f007e793ebb63b2b246857c9839b64dc0233", "0xaebcd3257d295747dd6fc4ff910d839dd80c51c173ae59b8b2ec937747c2072fa85e3017f9060aa509af88dfc7529481", "0xb3075ba6668ca04eff19efbfa3356b92f0ab12632dcda99cf8c655f35b7928c304218e0f9799d68ef9f809a1492ff7db", "0x93ba7468bb325639ec2abd4d55179c69fd04eaaf39fc5340709227bbaa4ad0a54ea8b480a1a3c8d44684e3be0f8d1980", "0xa6aef86c8c0d92839f38544d91b767c582568b391071228ff5a5a6b859c87bf4f81a7d926094a4ada1993ddbd677a920", "0x91dcd6d14207aa569194aa224d1e5037b999b69ade52843315ca61ba26abe9a76412c9e88259bc5cf5d7b95b97d9c3bc", "0xb3b483d31c88f78d49bd065893bc1e3d2aa637e27dedb46d9a7d60be7660ce7a10aaaa7deead362284a52e6d14021178", "0x8e5730070acf8371461ef301cc4523e8e672aa0e3d945d438a0e0aa6bdf8cb9c685dcf38df429037b0c8aff3955c6f5b", "0xb8c6d769890a8ee18dc4f9e917993315877c97549549b34785a92543cbeec96a08ae3a28d6e809c4aacd69de356c0012", "0x95ca86cd384eaceaa7c077c5615736ca31f36824bd6451a16142a1edc129fa42b50724aeed7c738f08d7b157f78b569e", "0x94df609c6d71e8eee7ab74226e371ccc77e01738fe0ef1a6424435b4570fe1e5d15797b66ed0f64eb88d4a3a37631f0e", "0x89057b9783212add6a0690d6bb99097b182738deff2bd9e147d7fd7d6c8eacb4c219923633e6309ad993c24572289901", "0x83a0f9f5f265c5a0e54defa87128240235e24498f20965009fef664f505a360b6fb4020f2742565dfc7746eb185bcec0", "0x91170da5306128931349bc3ed50d7df0e48a68b8cc8420975170723ac79d8773e4fa13c5f14dc6e3fafcad78379050b1", "0xb7178484d1b55f7e56a4cc250b6b2ec6040437d96bdfddfa7b35ed27435860f3855c2eb86c636f2911b012eb83b00db8", "0xac0b00c4322d1e4208e09cd977b4e54d221133ff09551f75b32b0b55d0e2be80941dda26257b0e288c162e63c7e9cf68", "0x9690ed9e7e53ed37ff362930e4096b878b12234c332fd19d5d064824084245952eda9f979e0098110d6963e468cf513e", "0xb6fa547bb0bb83e5c5be0ed462a8783fba119041c136a250045c09d0d2af330c604331e7de960df976ff76d67f8000cd", "0x814603907c21463bcf4e59cfb43066dfe1a50344ae04ef03c87c0f61b30836c3f4dea0851d6fa358c620045b7f9214c8", "0x9495639e3939fad2a3df00a88603a5a180f3c3a0fe4d424c35060e2043e0921788003689887b1ed5be424d9a89bb18bb", "0xaba4c02d8d57f2c92d5bc765885849e9ff8393d6554f5e5f3e907e5bfac041193a0d8716d7861104a4295d5a03c36b03", "0x8ead0b56c1ca49723f94a998ba113b9058059321da72d9e395a667e6a63d5a9dac0f5717cec343f021695e8ced1f72af", "0xb43037f7e3852c34ed918c5854cd74e9d5799eeddfe457d4f93bb494801a064735e326a76e1f5e50a339844a2f4a8ec9", "0x99db8422bb7302199eb0ff3c3d08821f8c32f53a600c5b6fb43e41205d96adae72be5b460773d1280ad1acb806af9be8", "0x8a9be08eae0086c0f020838925984df345c5512ff32e37120b644512b1d9d4fecf0fd30639ca90fc6cf334a86770d536", "0x81b43614f1c28aa3713a309a88a782fb2bdfc4261dd52ddc204687791a40cf5fd6a263a8179388596582cccf0162efc2", "0xa9f3a8b76912deb61d966c75daf5ddb868702ebec91bd4033471c8e533183df548742a81a2671de5be63a502d827437d", "0x902e2415077f063e638207dc7e14109652e42ab47caccd6204e2870115791c9defac5425fd360b37ac0f7bd8fe7011f8", "0xaa18e4fdc1381b59c18503ae6f6f2d6943445bd00dd7d4a2ad7e5adad7027f2263832690be30d456e6d772ad76f22350", "0xa348b40ba3ba7d81c5d4631f038186ebd5e5f314f1ea737259151b07c3cc8cf0c6ed4201e71bcc1c22fefda81a20cde6", "0xaa1306f7ac1acbfc47dc6f7a0cb6d03786cec8c8dc8060388ccda777bca24bdc634d03e53512c23dba79709ff64f8620", "0x818ccfe46e700567b7f3eb400e5a35f6a5e39b3db3aa8bc07f58ace35d9ae5a242faf8dbccd08d9a9175bbce15612155", "0xb7e3da2282b65dc8333592bb345a473f03bd6df69170055fec60222de9897184536bf22b9388b08160321144d0940279", "0xa4d976be0f0568f4e57de1460a1729129252b44c552a69fceec44e5b97c96c711763360d11f9e5bf6d86b4976bf40d69", "0x85d185f0397c24c2b875b09b6328a23b87982b84ee880f2677a22ff4c9a1ba9f0fea000bb3f7f66375a00d98ebafce17", "0xb4ccbb8c3a2606bd9b87ce022704663af71d418351575f3b350d294f4efc68c26f9a2ce49ff81e6ff29c3b63d746294e", "0x93ffd3265fddb63724dfde261d1f9e22f15ecf39df28e4d89e9fea03221e8e88b5dd9b77628bacaa783c6f91802d47cc", "0xb1fd0f8d7a01378e693da98d03a2d2fda6b099d03454b6f2b1fa6472ff6bb092751ce6290059826b74ac0361eab00e1e", "0xa89f440c71c561641589796994dd2769616b9088766e983c873fae0716b95c386c8483ab8a4f367b6a68b72b7456dd32", "0xaf4fe92b01d42d03dd5d1e7fa55e96d4bbcb7bf7d4c8c197acd16b3e0f3455807199f683dcd263d74547ef9c244b35cc", "0xa8227f6e0a344dfe76bfbe7a1861be32c4f4bed587ccce09f9ce2cf481b2dda8ae4f566154bc663d15f962f2d41761bd", "0xa7b361663f7495939ed7f518ba45ea9ff576c4e628995b7aea026480c17a71d63fc2c922319f0502eb7ef8f14a406882", "0x8ddcf382a9f39f75777160967c07012cfa89e67b19714a7191f0c68eaf263935e5504e1104aaabd0899348c972a8d3c6", "0x98c95b9f6f5c91f805fb185eedd06c6fc4457d37dd248d0be45a6a168a70031715165ea20606245cbdf8815dc0ac697f", "0x805b44f96e001e5909834f70c09be3efcd3b43632bcac5b6b66b6d227a03a758e4b1768ce2a723045681a1d34562aaeb", "0xb0e81b07cdc45b3dca60882676d9badb99f25c461b7efe56e3043b80100bb62d29e1873ae25eb83087273160ece72a55", "0xb0c53f0abe78ee86c7b78c82ae1f7c070bb0b9c45c563a8b3baa2c515d482d7507bb80771e60b38ac13f78b8af92b4a9", "0xa7838ef6696a9e4d2e5dfd581f6c8d6a700467e8fd4e85adabb5f7a56f514785dd4ab64f6f1b48366f7d94728359441b", "0x88c76f7700a1d23c30366a1d8612a796da57b2500f97f88fdf2d76b045a9d24e7426a8ffa2f4e86d3046937a841dad58", "0xad8964baf98c1f02e088d1d9fcb3af6b1dfa44cdfe0ed2eae684e7187c33d3a3c28c38e8f4e015f9c04d451ed6f85ff6", "0x90e9d00a098317ececaa9574da91fc149eda5b772dedb3e5a39636da6603aa007804fa86358550cfeff9be5a2cb7845e", "0xa56ff4ddd73d9a6f5ab23bb77efa25977917df63571b269f6a999e1ad6681a88387fcc4ca3b26d57badf91b236503a29", "0x97ad839a6302c410a47e245df84c01fb9c4dfef86751af3f9340e86ff8fc3cd52fa5ff0b9a0bd1d9f453e02ca80658a6", "0xa4c8c44cbffa804129e123474854645107d1f0f463c45c30fd168848ebea94880f7c0c5a45183e9eb837f346270bdb35", "0xa72e53d0a1586d736e86427a93569f52edd2f42b01e78aee7e1961c2b63522423877ae3ac1227a2cf1e69f8e1ff15bc3", "0x8559f88a7ef13b4f09ac82ae458bbae6ab25671cfbf52dae7eac7280d6565dd3f0c3286aec1a56a8a16dc3b61d78ce47", "0x8221503f4cdbed550876c5dc118a3f2f17800c04e8be000266633c83777b039a432d576f3a36c8a01e8fd18289ebc10b", "0x99bfbe5f3e46d4d898a578ba86ed26de7ed23914bd3bcdf3c791c0bcd49398a52419077354a5ab75cea63b6c871c6e96", "0xaa134416d8ff46f2acd866c1074af67566cfcf4e8be8d97329dfa0f603e1ff208488831ce5948ac8d75bfcba058ddcaa", "0xb02609d65ebfe1fe8e52f21224a022ea4b5ea8c1bd6e7b9792eed8975fc387cdf9e3b419b8dd5bcce80703ab3a12a45f", "0xa4f14798508698fa3852e5cac42a9db9797ecee7672a54988aa74037d334819aa7b2ac7b14efea6b81c509134a6b7ad2", "0x884f01afecbcb987cb3e7c489c43155c416ed41340f61ecb651d8cba884fb9274f6d9e7e4a46dd220253ae561614e44c", "0xa05523c9e71dce1fe5307cc71bd721feb3e1a0f57a7d17c7d1c9fb080d44527b7dbaa1f817b1af1c0b4322e37bc4bb1e", "0x8560aec176a4242b39f39433dd5a02d554248c9e49d3179530815f5031fee78ba9c71a35ceeb2b9d1f04c3617c13d8f0", "0x996aefd402748d8472477cae76d5a2b92e3f092fc834d5222ae50194dd884c9fb8b6ed8e5ccf8f6ed483ddbb4e80c747", "0x8fd09900320000cbabc40e16893e2fcf08815d288ec19345ad7b6bb22f7d78a52b6575a3ca1ca2f8bc252d2eafc928ec", "0x939e51f73022bc5dc6862a0adf8fb8a3246b7bfb9943cbb4b27c73743926cc20f615a036c7e5b90c80840e7f1bfee0e7", "0xa0a6258700cadbb9e241f50766573bf9bdb7ad380b1079dc3afb4054363d838e177b869cad000314186936e40359b1f2", "0x972699a4131c8ed27a2d0e2104d54a65a7ff1c450ad9da3a325c662ab26869c21b0a84d0700b98c8b5f6ce3b746873d7", "0xa454c7fe870cb8aa6491eafbfb5f7872d6e696033f92e4991d057b59d70671f2acdabef533e229878b60c7fff8f748b1", "0xa167969477214201f09c79027b10221e4707662e0c0fde81a0f628249f2f8a859ce3d30a7dcc03b8ecca8f7828ad85c7", "0x8ff6b7265175beb8a63e1dbf18c9153fb2578c207c781282374f51b40d57a84fd2ef2ea2b9c6df4a54646788a62fd17f", "0xa3d7ebeccde69d73d8b3e76af0da1a30884bb59729503ff0fb0c3bccf9221651b974a6e72ea33b7956fc3ae758226495", "0xb71ef144c9a98ce5935620cb86c1590bd4f48e5a2815d25c0cdb008fde628cf628c31450d3d4f67abbfeb16178a74cfd", "0xb5e0a16d115134f4e2503990e3f2035ed66b9ccf767063fe6747870d97d73b10bc76ed668550cb82eedc9a2ca6f75524", "0xb30ffaaf94ee8cbc42aa2c413175b68afdb207dbf351fb20be3852cb7961b635c22838da97eaf43b103aff37e9e725cc", "0x98aa7d52284f6c1f22e272fbddd8c8698cf8f5fbb702d5de96452141fafb559622815981e50b87a72c2b1190f59a7deb", "0x81fbacda3905cfaf7780bb4850730c44166ed26a7c8d07197a5d4dcd969c09e94a0461638431476c16397dd7bdc449f9", "0x95e47021c1726eac2e5853f570d6225332c6e48e04c9738690d53e07c6b979283ebae31e2af1fc9c9b3e59f87e5195b1", "0xac024a661ba568426bb8fce21780406537f518075c066276197300841e811860696f7588188bc01d90bace7bc73d56e3", "0xa4ebcaf668a888dd404988ab978594dee193dad2d0aec5cdc0ccaf4ec9a7a8228aa663db1da8ddc52ec8472178e40c32", "0xa20421b8eaf2199d93b083f2aff37fb662670bd18689d046ae976d1db1fedd2c2ff897985ecc6277b396db7da68bcb27", "0x8bc33d4b40197fd4d49d1de47489d10b90d9b346828f53a82256f3e9212b0cbc6930b895e879da9cec9fedf026aadb3e", "0xaaafdd1bec8b757f55a0433eddc0a39f818591954fd4e982003437fcceb317423ad7ee74dbf17a2960380e7067a6b4e2", "0xaad34277ebaed81a6ec154d16736866f95832803af28aa5625bf0461a71d02b1faba02d9d9e002be51c8356425a56867", "0x976e9c8b150d08706079945bd0e84ab09a648ecc6f64ded9eb5329e57213149ae409ae93e8fbd8eda5b5c69f5212b883", "0x8097fae1653247d2aed4111533bc378171d6b2c6d09cbc7baa9b52f188d150d645941f46d19f7f5e27b7f073c1ebd079", "0x83905f93b250d3184eaba8ea7d727c4464b6bdb027e5cbe4f597d8b9dc741dcbea709630bd4fd59ce24023bec32fc0f3", "0x8095030b7045cff28f34271386e4752f9a9a0312f8df75de4f424366d78534be2b8e1720a19cb1f9a2d21105d790a225", "0xa7b7b73a6ae2ed1009c49960374b0790f93c74ee03b917642f33420498c188a169724945a975e5adec0a1e83e07fb1b2", "0x856a41c54df393b6660b7f6354572a4e71c8bfca9cabaffb3d4ef2632c015e7ee2bc10056f3eccb3dbed1ad17d939178", "0xa8f7a55cf04b38cd4e330394ee6589da3a07dc9673f74804fdf67b364e0b233f14aec42e783200a2e4666f7c5ff62490", "0x82c529f4e543c6bca60016dc93232c115b359eaee2798a9cf669a654b800aafe6ab4ba58ea8b9cdda2b371c8d62fa845", "0x8caab020c1baddce77a6794113ef1dfeafc5f5000f48e97f4351b588bf02f1f208101745463c480d37f588d5887e6d8c", "0x8fa91b3cc400f48b77b6fd77f3b3fbfb3f10cdff408e1fd22d38f77e087b7683adad258804409ba099f1235b4b4d6fea", "0x8aa02787663d6be9a35677d9d8188b725d5fcd770e61b11b64e3def8808ea5c71c0a9afd7f6630c48634546088fcd8e2", "0xb5635b7b972e195cab878b97dea62237c7f77eb57298538582a330b1082f6207a359f2923864630136d8b1f27c41b9aa", "0x8257bb14583551a65975946980c714ecd6e5b629672bb950b9caacd886fbd22704bc9e3ba7d30778adab65dc74f0203a", "0xab5fe1cd12634bfa4e5c60d946e2005cbd38f1063ec9a5668994a2463c02449a0a185ef331bd86b68b6e23a8780cb3ba", "0xa7d3487da56cda93570cc70215d438204f6a2709bfb5fda6c5df1e77e2efc80f4235c787e57fbf2c74aaff8cbb510a14", "0xb61cff7b4c49d010e133319fb828eb900f8a7e55114fc86b39c261a339c74f630e1a7d7e1350244ada566a0ff3d46c4b", "0x8d4d1d55d321d278db7a85522ccceca09510374ca81d4d73e3bb5249ace7674b73900c35a531ec4fa6448fabf7ad00dc", "0x966492248aee24f0f56c8cfca3c8ec6ba3b19abb69ae642041d4c3be8523d22c65c4dafcab4c58989ccc4e0bd2f77919", "0xb20c320a90cb220b86e1af651cdc1e21315cd215da69f6787e28157172f93fc8285dcd59b039c626ed8ca4633cba1a47", "0xaae9e6b22f018ceb5c0950210bb8182cb8cb61014b7e14581a09d36ebd1bbfebdb2b82afb7fdb0cf75e58a293d9c456d", "0x875547fb67951ad37b02466b79f0c9b985ccbc500cfb431b17823457dc79fb9597ec42cd9f198e15523fcd88652e63a4", "0x92afce49773cb2e20fb21e4f86f18e0959ebb9c33361547ddb30454ee8e36b1e234019cbdca0e964cb292f7f77df6b90", "0x8af85343dfe1821464c76ba11c216cbef697b5afc69c4d821342e55afdac047081ec2e3f7b09fc14b518d9a23b78c003", "0xb7de4a1648fd63f3a918096ea669502af5357438e69dac77cb8102b6e6c15c76e033cfaa80dafc806e535ede5c1a20aa", "0xac80e9b545e8bd762951d96c9ce87f629d01ffcde07efc2ef7879ca011f1d0d8a745abf26c9d452541008871304fac00", "0xa4cf0f7ed724e481368016c38ea5816698a5f68eb21af4d3c422d2ba55f96a33e427c2aa40de1b56a7cfac7f7cf43ab0", "0x899b0a678bb2db2cae1b44e75a661284844ebcdd87abf308fedeb2e4dbe5c5920c07db4db7284a7af806a2382e8b111a", "0xaf0588a2a4afce2b1b13c1230816f59e8264177e774e4a341b289a101dcf6af813638fed14fb4d09cb45f35d5d032609", "0xa4b8df79e2be76e9f5fc5845f06fe745a724cf37c82fcdb72719b77bdebea3c0e763f37909373e3a94480cc5e875cba0", "0x83e42c46d88930c8f386b19fd999288f142d325e2ebc86a74907d6d77112cb0d449bc511c95422cc810574031a8cbba9", "0xb5e39534070de1e5f6e27efbdd3dc917d966c2a9b8cf2d893f964256e95e954330f2442027dc148c776d63a95bcde955", "0x958607569dc28c075e658cd4ae3927055c6bc456eef6212a6fea8205e48ed8777a8064f584cda38fe5639c371e2e7fba", "0x812adf409fa63575113662966f5078a903212ffb65c9b0bbe62da0f13a133443a7062cb8fd70f5e5dd5559a32c26d2c8", "0xa679f673e5ce6a3cce7fa31f22ee3785e96bcb55e5a776e2dd3467bef7440e3555d1a9b87cb215e86ee9ed13a090344b", "0xafedbb34508b159eb25eb2248d7fe328f86ef8c7d84c62d5b5607d74aae27cc2cc45ee148eb22153b09898a835c58df4", "0xb75505d4f6b67d31e665cfaf5e4acdb5838ae069166b7fbcd48937c0608a59e40a25302fcc1873d2e81c1782808c70f0", "0xb62515d539ec21a155d94fc00ea3c6b7e5f6636937bce18ed5b618c12257fb82571886287fd5d1da495296c663ebc512", "0xab8e1a9446bbdd588d1690243b1549d230e6149c28f59662b66a8391a138d37ab594df38e7720fae53217e5c3573b5be", "0xb31e8abf4212e03c3287bb2c0a153065a7290a16764a0bac8f112a72e632185a654bb4e88fdd6053e6c7515d9719fadb", "0xb55165477fe15b6abd2d0f4fddaa9c411710dcc4dd712daba3d30e303c9a3ee5415c256f9dc917ecf18c725b4dbab059", "0xa0939d4f57cacaae549b78e87cc234de4ff6a35dc0d9cd5d7410abc30ebcd34c135e008651c756e5a9d2ca79c40ef42b", "0x8cf10e50769f3443340844aad4d56ec790850fed5a41fcbd739abac4c3015f0a085a038fbe7fae9f5ad899cce5069f6b", "0x924055e804d82a99ea4bb160041ea4dc14b568abf379010bc1922fde5d664718c31d103b8b807e3a1ae809390e708c73", "0x8ec0f9d26f71b0f2e60a179e4fd1778452e2ffb129d50815e5d7c7cb9415fa69ae5890578086e8ef6bfde35ad2a74661", "0x98c7f12b15ec4426b59f737f73bf5faea4572340f4550b7590dfb7f7ffedb2372e3e555977c63946d579544c53210ad0", "0x8a935f7a955c78f69d66f18eee0092e5e833fa621781c9581058e219af4d7ceee48b84e472e159dda6199715fb2f9acf", "0xb78d4219f95a2dbfaa7d0c8a610c57c358754f4f43c2af312ab0fe8f10a5f0177e475332fb8fd23604e474fc2abeb051", "0x8d086a14803392b7318c28f1039a17e3cfdcece8abcaca3657ec3d0ac330842098a85c0212f889fabb296dfb133ce9aa", "0xa53249f417aac82f2c2a50c244ce21d3e08a5e5a8bd33bec2a5ab0d6cd17793e34a17edfa3690899244ce201e2fb9986", "0x8619b0264f9182867a1425be514dc4f1ababc1093138a728a28bd7e4ecc99b9faaff68c23792264bc6e4dce5f52a5c52", "0x8c171edbbbde551ec19e31b2091eb6956107dd9b1f853e1df23bff3c10a3469ac77a58335eee2b79112502e8e163f3de", "0xa9d19ec40f0ca07c238e9337c6d6a319190bdba2db76fb63902f3fb459aeeb50a1ac30db5b25ee1b4201f3ca7164a7f4", "0xb9c6ec14b1581a03520b8d2c1fbbc31fb8ceaef2c0f1a0d0080b6b96e18442f1734bea7ef7b635d787c691de4765d469", "0x8cb437beb4cfa013096f40ccc169a713dc17afee6daa229a398e45fd5c0645a9ad2795c3f0cd439531a7151945d7064d", "0xa6e8740cc509126e146775157c2eb278003e5bb6c48465c160ed27888ca803fa12eee1f6a8dd7f444f571664ed87fdc1", "0xb75c1fecc85b2732e96b3f23aefb491dbd0206a21d682aee0225838dc057d7ed3b576176353e8e90ae55663f79e986e4", "0xad8d249b0aea9597b08358bce6c77c1fd552ef3fbc197d6a1cfe44e5e6f89b628b12a6fb04d5dcfcbacc51f46e4ae7bb", "0xb998b2269932cbd58d04b8e898d373ac4bb1a62e8567484f4f83e224061bc0f212459f1daae95abdbc63816ae6486a55", "0x827988ef6c1101cddc96b98f4a30365ff08eea2471dd949d2c0a9b35c3bbfa8c07054ad1f4c88c8fbf829b20bb5a9a4f", "0x8692e638dd60babf7d9f2f2d2ce58e0ac689e1326d88311416357298c6a2bffbfebf55d5253563e7b3fbbf5072264146", "0xa685d75b91aea04dbc14ab3c1b1588e6de96dae414c8e37b8388766029631b28dd860688079b12d09cd27f2c5af11adf", "0xb57eced93eec3371c56679c259b34ac0992286be4f4ff9489d81cf9712403509932e47404ddd86f89d7c1c3b6391b28c", "0xa1c8b4e42ebcbd8927669a97f1b72e236fb19249325659e72be7ddaaa1d9e81ca2abb643295d41a8c04a2c01f9c0efd7", "0x877c33de20d4ed31674a671ba3e8f01a316581e32503136a70c9c15bf0b7cb7b1cba6cd4eb641fad165fb3c3c6c235fd", "0xa2a469d84ec478da40838f775d11ad38f6596eb41caa139cc190d6a10b5108c09febae34ffdafac92271d2e73c143693", "0x972f817caedb254055d52e963ed28c206848b6c4cfdb69dbc961c891f8458eaf582a6d4403ce1177d87bc2ea410ef60a", "0xaccbd739e138007422f28536381decc54bb6bd71d93edf3890e54f9ef339f83d2821697d1a4ac1f5a98175f9a9ecb9b5", "0x8940f8772e05389f823b62b3adc3ed541f91647f0318d7a0d3f293aeeb421013de0d0a3664ea53dd24e5fbe02d7efef6", "0x8ecce20f3ef6212edef07ec4d6183fda8e0e8cad2c6ccd0b325e75c425ee1faba00b5c26b4d95204238931598d78f49d", "0x97cc72c36335bd008afbed34a3b0c7225933faba87f7916d0a6d2161e6f82e0cdcda7959573a366f638ca75d30e9dab1", "0x9105f5de8699b5bdb6bd3bb6cc1992d1eac23929c29837985f83b22efdda92af64d9c574aa9640475087201bbbe5fd73", "0x8ffb33c4f6d05c413b9647eb6933526a350ed2e4278ca2ecc06b0e8026d8dbe829c476a40e45a6df63a633090a3f82ef", "0x8bfc6421fdc9c2d2aaa68d2a69b1a2728c25b84944cc3e6a57ff0c94bfd210d1cbf4ff3f06702d2a8257024d8be7de63", "0xa80e1dc1dddfb41a70220939b96dc6935e00b32fb8be5dff4eed1f1c650002ff95e4af481c43292e3827363b7ec4768a", "0x96f714ebd54617198bd636ba7f7a7f8995a61db20962f2165078d9ed8ee764d5946ef3cbdc7ebf8435bb8d5dd4c1deac", "0x8cdb0890e33144d66391d2ae73f5c71f5a861f72bc93bff6cc399fc25dd1f9e17d8772592b44593429718784802ac377", "0x8ccf9a7f80800ee770b92add734ed45a73ecc31e2af0e04364eefc6056a8223834c7c0dc9dfc52495bdec6e74ce69994", "0xaa0875f423bd68b5f10ba978ddb79d3b96ec093bfbac9ff366323193e339ed7c4578760fb60f60e93598bdf1e5cc4995", "0xa9214f523957b59c7a4cb61a40251ad72aba0b57573163b0dc0f33e41d2df483fb9a1b85a5e7c080e9376c866790f8cb", "0xb6224b605028c6673a536cc8ff9aeb94e7a22e686fda82cf16068d326469172f511219b68b2b3affb7933af0c1f80d07", "0xb6d58968d8a017c6a34e24c2c09852f736515a2c50f37232ac6b43a38f8faa7572cc31dade543b594b61b5761c4781d0", "0x8a97cefe5120020c38deeb861d394404e6c993c6cbd5989b6c9ebffe24f46ad11b4ba6348e2991cbf3949c28cfc3c99d", "0x95bf046f8c3a9c0ce2634be4de3713024daec3fc4083e808903b25ce3ac971145af90686b451efcc72f6b22df0216667", "0xa6a4e2f71b8fa28801f553231eff2794c0f10d12e7e414276995e21195abc9c2983a8997e41af41e78d19ff6fbb2680b", "0x8e5e62a7ca9c2f58ebaab63db2ff1fb1ff0877ae94b7f5e2897f273f684ae639dff44cc65718f78a9c894787602ab26a", "0x8542784383eec4f565fcb8b9fc2ad8d7a644267d8d7612a0f476fc8df3aff458897a38003d506d24142ad18f93554f2b", "0xb7db68ba4616ea072b37925ec4fb39096358c2832cc6d35169e032326b2d6614479f765ae98913c267105b84afcb9bf2", "0x8b31dbb9457d23d416c47542c786e07a489af35c4a87dadb8ee91bea5ac4a5315e65625d78dad2cf8f9561af31b45390", "0xa8545a1d91ac17257732033d89e6b7111db8242e9c6ebb0213a88906d5ef407a2c6fdb444e29504b06368b6efb4f4839", "0xb1bd85d29ebb28ccfb05779aad8674906b267c2bf8cdb1f9a0591dd621b53a4ee9f2942687ee3476740c0b4a7621a3ae", "0xa2b54534e152e46c50d91fff03ae9cd019ff7cd9f4168b2fe7ac08ef8c3bbc134cadd3f9d6bd33d20ae476c2a8596c8a", "0xb19b571ff4ae3e9f5d95acda133c455e72c9ea9973cae360732859836c0341c4c29ab039224dc5bc3deb824e031675d8", "0x940b5f80478648bac025a30f3efeb47023ce20ee98be833948a248bca6979f206bb28fc0f17b90acf3bb4abd3d14d731", "0x8f106b40588586ac11629b96d57808ad2808915d89539409c97414aded90b4ff23286a692608230a52bff696055ba5d6", "0xae6bda03aa10da3d2abbc66d764ca6c8d0993e7304a1bdd413eb9622f3ca1913baa6da1e9f4f9e6cf847f14f44d6924d", "0xa18e7796054a340ef826c4d6b5a117b80927afaf2ebd547794c400204ae2caf277692e2eabb55bc2f620763c9e9da66d", "0x8d2d25180dc2c65a4844d3e66819ccfcf48858f0cc89e1c77553b463ec0f7feb9a4002ce26bc618d1142549b9850f232", "0x863f413a394de42cc8166c1c75d513b91d545fff1de6b359037a742c70b008d34bf8e587afa2d62c844d0c6f0ea753e7", "0x83cd0cf62d63475e7fcad18a2e74108499cdbf28af2113cfe005e3b5887794422da450b1944d0a986eb7e1f4c3b18f25", "0xb4f8b350a6d88fea5ab2e44715a292efb12eb52df738c9b2393da3f1ddee68d0a75b476733ccf93642154bceb208f2b8", "0xb3f52aaa4cd4221cb9fc45936cc67fd3864bf6d26bf3dd86aa85aa55ecfc05f5e392ecce5e7cf9406b4b1c4fce0398c8", "0xb33137084422fb643123f40a6df2b498065e65230fc65dc31791c330e898c51c3a65ff738930f32c63d78f3c9315f85b", "0x91452bfa75019363976bb7337fe3a73f1c10f01637428c135536b0cdc7da5ce558dae3dfc792aa55022292600814a8ef", "0xad6ba94c787cd4361ca642c20793ea44f1f127d4de0bb4a77c7fbfebae0fcadbf28e2cb6f0c12c12a07324ec8c19761d", "0x890aa6248b17f1501b0f869c556be7bf2b1d31a176f9978bb97ab7a6bd4138eed32467951c5ef1871944b7f620542f43", "0x82111db2052194ee7dd22ff1eafffac0443cf969d3762cceae046c9a11561c0fdce9c0711f88ac01d1bed165f8a7cee3", "0xb1527b71df2b42b55832f72e772a466e0fa05743aacc7814f4414e4bcc8d42a4010c9e0fd940e6f254cafedff3cd6543", "0x922370fa49903679fc565f09c16a5917f8125e72acfeb060fcdbadbd1644eb9f4016229756019c93c6d609cda5d5d174", "0xaa4c7d98a96cab138d2a53d4aee8ebff6ef903e3b629a92519608d88b3bbd94de5522291a1097e6acf830270e64c8ee1", "0xb3dc21608a389a72d3a752883a382baaafc61ecc44083b832610a237f6a2363f24195acce529eb4aed4ef0e27a12b66e", "0x94619f5de05e07b32291e1d7ab1d8b7337a2235e49d4fb5f3055f090a65e932e829efa95db886b32b153bdd05a53ec8c", "0xade1e92722c2ffa85865d2426fb3d1654a16477d3abf580cfc45ea4b92d5668afc9d09275d3b79283e13e6b39e47424d", "0xb7201589de7bed094911dd62fcd25c459a8e327ac447b69f541cdba30233063e5ddffad0b67e9c3e34adcffedfd0e13d", "0x809d325310f862d6549e7cb40f7e5fc9b7544bd751dd28c4f363c724a0378c0e2adcb5e42ec8f912f5f49f18f3365c07", "0xa79c20aa533de7a5d671c99eb9eb454803ba54dd4f2efa3c8fec1a38f8308e9905c71e9282955225f686146388506ff6", "0xa85eeacb5e8fc9f3ed06a3fe2dc3108ab9f8c5877b148c73cf26e4e979bf5795edbe2e63a8d452565fd1176ed40402b2", "0x97ef55662f8a1ec0842b22ee21391227540adf7708f491436044f3a2eb18c471525e78e1e14fa292507c99d74d7437c6", "0x93110d64ed5886f3d16ce83b11425576a3a7a9bb831cd0de3f9a0b0f2270a730d68136b4ef7ff035ede004358f419b5c", "0xac9ed0a071517f0ae4f61ce95916a90ba9a77a3f84b0ec50ef7298acdcd44d1b94525d191c39d6bd1bb68f4471428760", "0x98abd6a02c7690f5a339adf292b8c9368dfc12e0f8069cf26a5e0ce54b4441638f5c66ea735142f3c28e00a0024267e6", "0xb51efb73ba6d44146f047d69b19c0722227a7748b0e8f644d0fc9551324cf034c041a2378c56ce8b58d06038fb8a78de", "0x8f115af274ef75c1662b588b0896b97d71f8d67986ae846792702c4742ab855952865ce236b27e2321967ce36ff93357", "0xb3c4548f14d58b3ab03c222da09e4381a0afe47a72d18d50a94e0008797f78e39e99990e5b4757be62310d400746e35a", "0xa9b1883bd5f31f909b8b1b6dcb48c1c60ed20aa7374b3ffa7f5b2ed036599b5bef33289d23c80a5e6420d191723b92f7", "0x85d38dffd99487ae5bb41ab4a44d80a46157bbbe8ef9497e68f061721f74e4da513ccc3422936b059575975f6787c936", "0xadf870fcb96e972c033ab7a35d28ae79ee795f82bc49c3bd69138f0e338103118d5529c53f2d72a9c0d947bf7d312af2", "0xab4c7a44e2d9446c6ff303eb49aef0e367a58b22cc3bb27b4e69b55d1d9ee639c9234148d2ee95f9ca8079b1457d5a75", "0xa386420b738aba2d7145eb4cba6d643d96bda3f2ca55bb11980b318d43b289d55a108f4bc23a9606fb0bccdeb3b3bb30", "0x847020e0a440d9c4109773ecca5d8268b44d523389993b1f5e60e541187f7c597d79ebd6e318871815e26c96b4a4dbb1", "0xa530aa7e5ca86fcd1bec4b072b55cc793781f38a666c2033b510a69e110eeabb54c7d8cbcb9c61fee531a6f635ffa972", "0x87364a5ea1d270632a44269d686b2402da737948dac27f51b7a97af80b66728b0256547a5103d2227005541ca4b7ed04", "0x8816fc6e16ea277de93a6d793d0eb5c15e9e93eb958c5ef30adaf8241805adeb4da8ce19c3c2167f971f61e0b361077d", "0x8836a72d301c42510367181bb091e4be377777aed57b73c29ef2ce1d475feedd7e0f31676284d9a94f6db01cc4de81a2", "0xb0d9d8b7116156d9dde138d28aa05a33e61f8a85839c1e9071ccd517b46a5b4b53acb32c2edd7150c15bc1b4bd8db9e3", "0xae931b6eaeda790ba7f1cd674e53dc87f6306ff44951fa0df88d506316a5da240df9794ccbd7215a6470e6b31c5ea193", "0x8c6d5bdf87bd7f645419d7c6444e244fe054d437ed1ba0c122fde7800603a5fadc061e5b836cb22a6cfb2b466f20f013", "0x90d530c6d0cb654999fa771b8d11d723f54b8a8233d1052dc1e839ea6e314fbed3697084601f3e9bbb71d2b4eaa596df", "0xb0d341a1422588c983f767b1ed36c18b141774f67ef6a43cff8e18b73a009da10fc12120938b8bba27f225bdfd3138f9", "0xa131b56f9537f460d304e9a1dd75702ace8abd68cb45419695cb8dee76998139058336c87b7afd6239dc20d7f8f940cc", "0xaa6c51fa28975f709329adee1bbd35d49c6b878041841a94465e8218338e4371f5cb6c17f44a63ac93644bf28f15d20f", "0x88440fb584a99ebd7f9ea04aaf622f6e44e2b43bbb49fb5de548d24a238dc8f26c8da2ccf03dd43102bda9f16623f609", "0x9777b8695b790e702159a4a750d5e7ff865425b95fa0a3c15495af385b91c90c00a6bd01d1b77bffe8c47d01baae846f", "0x8b9d764ece7799079e63c7f01690c8eff00896a26a0d095773dea7a35967a8c40db7a6a74692f0118bf0460c26739af4", "0x85808c65c485520609c9e61fa1bb67b28f4611d3608a9f7a5030ee61c3aa3c7e7dc17fff48af76b4aecee2cb0dbd22ac", "0xad2783a76f5b3db008ef5f7e67391fda4e7e36abde6b3b089fc4835b5c339370287935af6bd53998bed4e399eda1136d", "0x96f18ec03ae47c205cc4242ca58e2eff185c9dca86d5158817e2e5dc2207ab84aadda78725f8dc080a231efdc093b940", "0x97de1ab6c6cc646ae60cf7b86df73b9cf56cc0cd1f31b966951ebf79fc153531af55ca643b20b773daa7cab784b832f7", "0x870ba266a9bfa86ef644b1ef025a0f1b7609a60de170fe9508de8fd53170c0b48adb37f19397ee8019b041ce29a16576", "0xad990e888d279ac4e8db90619d663d5ae027f994a3992c2fbc7d262b5990ae8a243e19157f3565671d1cb0de17fe6e55", "0x8d9d5adcdd94c5ba3be4d9a7428133b42e485f040a28d16ee2384758e87d35528f7f9868de9bd23d1a42a594ce50a567", "0x85a33ed75d514ece6ad78440e42f7fcdb59b6f4cff821188236d20edae9050b3a042ce9bc7d2054296e133d033e45022", "0x92afd2f49a124aaba90de59be85ff269457f982b54c91b06650c1b8055f9b4b0640fd378df02a00e4fc91f7d226ab980", "0x8c0ee09ec64bd831e544785e3d65418fe83ed9c920d9bb4d0bf6dd162c1264eb9d6652d2def0722e223915615931581c", "0x8369bedfa17b24e9ad48ebd9c5afea4b66b3296d5770e09b00446c5b0a8a373d39d300780c01dcc1c6752792bccf5fd0", "0x8b9e960782576a59b2eb2250d346030daa50bbbec114e95cdb9e4b1ba18c3d34525ae388f859708131984976ca439d94", "0xb682bface862008fea2b5a07812ca6a28a58fd151a1d54c708fc2f8572916e0d678a9cb8dc1c10c0470025c8a605249e", "0xa38d5e189bea540a824b36815fc41e3750760a52be0862c4cac68214febdc1a754fb194a7415a8fb7f96f6836196d82a", "0xb9e7fbda650f18c7eb8b40e42cc42273a7298e65e8be524292369581861075c55299ce69309710e5b843cb884de171bd", "0xb6657e5e31b3193874a1bace08f42faccbd3c502fb73ad87d15d18a1b6c2a146f1baa929e6f517db390a5a47b66c0acf", "0xae15487312f84ed6265e4c28327d24a8a0f4d2d17d4a5b7c29b974139cf93223435aaebe3af918f5b4bb20911799715f", "0x8bb4608beb06bc394e1a70739b872ce5a2a3ffc98c7547bf2698c893ca399d6c13686f6663f483894bccaabc3b9c56ad", "0xb58ac36bc6847077584308d952c5f3663e3001af5ecf2e19cb162e1c58bd6c49510205d453cffc876ca1dc6b8e04a578", "0x924f65ced61266a79a671ffb49b300f0ea44c50a0b4e3b02064faa99fcc3e4f6061ea8f38168ab118c5d47bd7804590e", "0x8d67d43b8a06b0ff4fafd7f0483fa9ed1a9e3e658a03fb49d9d9b74e2e24858dc1bed065c12392037b467f255d4e5643", "0xb4d4f87813125a6b355e4519a81657fa97c43a6115817b819a6caf4823f1d6a1169683fd68f8d025cdfa40ebf3069acb", "0xa7fd4d2c8e7b59b8eed3d4332ae94b77a89a2616347402f880bc81bde072220131e6dbec8a605be3a1c760b775375879", "0x8d4a7d8fa6f55a30df37bcf74952e2fa4fd6676a2e4606185cf154bdd84643fd01619f8fb8813a564f72e3f574f8ce30", "0x8086fb88e6260e9a9c42e9560fde76315ff5e5680ec7140f2a18438f15bc2cc7d7d43bfb5880b180b738c20a834e6134", "0x916c4c54721de03934fee6f43de50bb04c81f6f8dd4f6781e159e71c40c60408aa54251d457369d133d4ba3ed7c12cb4", "0x902e5bf468f11ed9954e2a4a595c27e34abe512f1d6dc08bbca1c2441063f9af3dc5a8075ab910a10ff6c05c1c644a35", "0xa1302953015e164bf4c15f7d4d35e3633425a78294406b861675667eec77765ff88472306531e5d3a4ec0a2ff0dd6a9e", "0x87874461df3c9aa6c0fa91325576c0590f367075f2f0ecfeb34afe162c04c14f8ce9d608c37ac1adc8b9985bc036e366", "0x84b50a8a61d3cc609bfb0417348133e698fe09a6d37357ce3358de189efcf35773d78c57635c2d26c3542b13cc371752", "0xacaed2cff8633d12c1d12bb7270c54d65b0b0733ab084fd47f81d0a6e1e9b6f300e615e79538239e6160c566d8bb8d29", "0x889e6a0e136372ca4bac90d1ab220d4e1cad425a710e8cdd48b400b73bb8137291ceb36a39440fa84305783b1d42c72f", "0x90952e5becec45b2b73719c228429a2c364991cf1d5a9d6845ae5b38018c2626f4308daa322cab1c72e0f6c621bb2b35", "0x8f5a97a801b6e9dcd66ccb80d337562c96f7914e7169e8ff0fda71534054c64bf2a9493bb830623d612cfe998789be65", "0x84f3df8b9847dcf1d63ca470dc623154898f83c25a6983e9b78c6d2d90a97bf5e622445be835f32c1e55e6a0a562ea78", "0x91d12095cd7a88e7f57f254f02fdb1a1ab18984871dead2f107404bcf8069fe68258c4e6f6ebd2477bddf738135400bb", "0xb771a28bc04baef68604d4723791d3712f82b5e4fe316d7adc2fc01b935d8e644c06d59b83bcb542afc40ebafbee0683", "0x872f6341476e387604a7e93ae6d6117e72d164e38ebc2b825bc6df4fcce815004d7516423c190c1575946b5de438c08d", "0x90d6b4aa7d40a020cdcd04e8b016d041795961a8e532a0e1f4041252131089114a251791bf57794cadb7d636342f5d1c", "0x899023ba6096a181448d927fed7a0fe858be4eac4082a42e30b3050ee065278d72fa9b9d5ce3bc1372d4cbd30a2f2976", "0xa28f176571e1a9124f95973f414d5bdbf5794d41c3839d8b917100902ac4e2171eb940431236cec93928a60a77ede793", "0x838dbe5bcd29c4e465d02350270fa0036cd46f8730b13d91e77afb7f5ed16525d0021d3b2ae173a76c378516a903e0cb", "0x8e105d012dd3f5d20f0f1c4a7e7f09f0fdd74ce554c3032e48da8cce0a77260d7d47a454851387770f5c256fa29bcb88", "0x8f4df0f9feeb7a487e1d138d13ea961459a6402fd8f8cabb226a92249a0d04ded5971f3242b9f90d08da5ff66da28af6", "0xad1cfda4f2122a20935aa32fb17c536a3653a18617a65c6836700b5537122af5a8206befe9eaea781c1244c43778e7f1", "0x832c6f01d6571964ea383292efc8c8fa11e61c0634a25fa180737cc7ab57bc77f25e614aac9a2a03d98f27b3c1c29de2", "0x903f89cc13ec6685ac7728521898781fecb300e9094ef913d530bf875c18bcc3ceed7ed51e7b482d45619ab4b025c2e9", "0xa03c474bb915aad94f171e8d96f46abb2a19c9470601f4c915512ec8b9e743c3938450a2a5b077b4618b9df8809e1dc1", "0x83536c8456f306045a5f38ae4be2e350878fa7e164ea408d467f8c3bc4c2ee396bd5868008c089183868e4dfad7aa50b", "0x88f26b4ea1b236cb326cd7ad7e2517ec8c4919598691474fe15d09cabcfc37a8d8b1b818f4d112432ee3a716b0f37871", "0xa44324e3fe96e9c12b40ded4f0f3397c8c7ee8ff5e96441118d8a6bfad712d3ac990b2a6a23231a8f691491ac1fd480f", "0xb0de4693b4b9f932191a21ee88629964878680152a82996c0019ffc39f8d9369bbe2fe5844b68d6d9589ace54af947e4", "0x8e5d8ba948aea5fd26035351a960e87f0d23efddd8e13236cc8e4545a3dda2e9a85e6521efb8577e03772d3637d213d9", "0x93efc82d2017e9c57834a1246463e64774e56183bb247c8fc9dd98c56817e878d97b05f5c8d900acf1fbbbca6f146556", "0x8731176363ad7658a2862426ee47a5dce9434216cef60e6045fa57c40bb3ce1e78dac4510ae40f1f31db5967022ced32", "0xb10c9a96745722c85bdb1a693100104d560433d45b9ac4add54c7646a7310d8e9b3ca9abd1039d473ae768a18e489845", "0xa2ac374dfbb464bf850b4a2caf15b112634a6428e8395f9c9243baefd2452b4b4c61b0cb2836d8eae2d57d4900bf407e", "0xb69fe3ded0c4f5d44a09a0e0f398221b6d1bf5dbb8bc4e338b93c64f1a3cac1e4b5f73c2b8117158030ec03787f4b452", "0x8852cdbaf7d0447a8c6f211b4830711b3b5c105c0f316e3a6a18dcfbb9be08bd6f4e5c8ae0c3692da08a2dfa532f9d5c", "0x93bbf6d7432a7d98ade3f94b57bf9f4da9bc221a180a370b113066dd42601bb9e09edd79e2e6e04e00423399339eebda", "0xa80941c391f1eeafc1451c59e4775d6a383946ff22997aeaadf806542ba451d3b0f0c6864eeba954174a296efe2c1550", "0xa045fe2bb011c2a2f71a0181a8f457a3078470fb74c628eab8b59aef69ffd0d649723bf74d6885af3f028bc5a104fb39", "0xb9d8c35911009c4c8cad64692139bf3fc16b78f5a19980790cb6a7aea650a25df4231a4437ae0c351676a7e42c16134f", "0x94c79501ded0cfcbab99e1841abe4a00a0252b3870e20774c3da16c982d74c501916ec28304e71194845be6e3113c7ab", "0x900a66418b082a24c6348d8644ddb1817df5b25cb33044a519ef47cc8e1f7f1e38d2465b7b96d32ed472d2d17f8414c6", "0xb26f45d393b8b2fcb29bdbb16323dc7f4b81c09618519ab3a39f8ee5bd148d0d9f3c0b5dfab55b5ce14a1cb9206d777b", "0xaa1a87735fc493a80a96a9a57ca40a6d9c32702bfcaa9869ce1a116ae65d69cefe2f3e79a12454b4590353e96f8912b4", "0xa922b188d3d0b69b4e4ea2a2aa076566962844637da12c0832105d7b31dea4a309eee15d12b7a336be3ea36fcbd3e3b7", "0x8f3841fcf4105131d8c4d9885e6e11a46c448226401cf99356c291fadb864da9fa9d30f3a73c327f23f9fd99a11d633e", "0x9791d1183fae270e226379af6c497e7da803ea854bb20afa74b253239b744c15f670ee808f708ede873e78d79a626c9a", "0xa4cad52e3369491ada61bf28ada9e85de4516d21c882e5f1cd845bea9c06e0b2887b0c5527fcff6fc28acd3c04f0a796", "0xb9ac86a900899603452bd11a7892a9bfed8054970bfcbeaa8c9d1930db891169e38d6977f5258c25734f96c8462eee3b", "0xa3a154c28e5580656a859f4efc2f5ebfa7eaa84ca40e3f134fa7865e8581586db74992dbfa4036aa252fba103773ddde", "0x95cc2a0c1885a029e094f5d737e3ecf4d26b99036453a8773c77e360101f9f98676ee246f6f732a377a996702d55691f", "0x842651bbe99720438d8d4b0218feb60481280c05beb17750e9ca0d8c0599a60f873b7fbdcc7d8835ba9a6d57b16eec03", "0x81ee54699da98f5620307893dcea8f64670609fa20e5622265d66283adeac122d458b3308c5898e6c57c298db2c8b24f", "0xb97868b0b2bc98032d68352a535a1b341b9ff3c7af4e3a7f3ebc82d3419daa1b5859d6aedc39994939623c7cd878bd9b", "0xb60325cd5d36461d07ef253d826f37f9ee6474a760f2fff80f9873d01fd2b57711543cdc8d7afa1c350aa753c2e33dea", "0x8c205326c11d25a46717b780c639d89714c7736c974ae71287e3f4b02e6605ac2d9b4928967b1684f12be040b7bf2dd3", "0x95a392d82db51e26ade6c2ccd3396d7e40aff68fa570b5951466580d6e56dda51775dce5cf3a74a7f28c3cb2eb551c4d", "0x8f2cc8071eb56dffb70bda6dd433b556221dc8bba21c53353c865f00e7d4d86c9e39f119ea9a8a12ef583e9a55d9a6b6", "0x9449a71af9672aaf8856896d7e3d788b22991a7103f75b08c0abbcc2bfe60fda4ed8ce502cea4511ff0ea52a93e81222", "0x857090ab9fdb7d59632d068f3cc8cf27e61f0d8322d30e6b38e780a1f05227199b4cd746aac1311c36c659ef20931f28", "0x98a891f4973e7d9aaf9ac70854608d4f7493dffc7e0987d7be9dd6029f6ea5636d24ef3a83205615ca1ff403750058e1", "0xa486e1365bbc278dd66a2a25d258dc82f46b911103cb16aab3945b9c95ae87b386313a12b566df5b22322ede0afe25ad", "0xa9a1eb399ed95d396dccd8d1ac718043446f8b979ec62bdce51c617c97a312f01376ab7fb87d27034e5f5570797b3c33", "0xb7abc3858d7a74bb446218d2f5a037e0fae11871ed9caf44b29b69c500c1fa1dcfad64c9cdccc9d80d5e584f06213deb", "0x8cfb09fe2e202faa4cebad932b1d35f5ca204e1c2a0c740a57812ac9a6792130d1312aabd9e9d4c58ca168bfebd4c177", "0xa90a305c2cd0f184787c6be596fa67f436afd1f9b93f30e875f817ac2aae8bdd2e6e656f6be809467e6b3ad84adb86b1", "0x80a9ef993c2b009ae172cc8f7ec036f5734cf4f4dfa06a7db4d54725e7fbfae5e3bc6f22687bdbb6961939d6f0c87537", "0x848ade1901931e72b955d7db1893f07003e1708ff5d93174bac5930b9a732640f0578839203e9b77eb27965c700032d3", "0x93fdf4697609c5ae9c33b9ca2f5f1af44abeb2b98dc4fdf732cf7388de086f410730dc384d9b7a7f447bb009653c8381", "0x89ce3fb805aea618b5715c0d22a9f46da696b6fa86794f56fdf1d44155a33d42daf1920bcbe36cbacf3cf4c92df9cbc7", "0x829ce2c342cf82aa469c65f724f308f7a750bd1494adc264609cd790c8718b8b25b5cab5858cf4ee2f8f651d569eea67", "0xaf2f0cee7bf413204be8b9df59b9e4991bc9009e0d6dbe6815181df0ec2ca93ab8f4f3135b1c14d8f53d74bff0bd6f27", "0xb87998cecf7b88cde93d1779f10a521edd5574a2fbd240102978639ec57433ba08cdb53849038a329cebbe74657268d2", "0xa64542a1261a6ed3d720c2c3a802303aad8c4c110c95d0f12e05c1065e66f42da494792b6bfc5b9272363f3b1d457f58", "0x86a6fd042e4f282fadf07a4bfee03fc96a3aea49f7a00f52bf249a20f1ec892326855410e61f37fbb27d9305eb2fc713", "0x967ea5bc403b6db269682f7fd0df90659350d7e1aa66bc4fab4c9dfcd75ed0bba4b52f1cebc5f34dc8ba810793727629", "0xa52990f9f3b8616ce3cdc2c74cd195029e6a969753dcf2d1630438700e7d6ebde36538532b3525ac516f5f2ce9dd27a3", "0xa64f7ff870bab4a8bf0d4ef6f5c744e9bf1021ed08b4c80903c7ad318e80ba1817c3180cc45cb5a1cae1170f0241655f", "0xb00f706fa4de1f663f021e8ad3d155e84ce6084a409374b6e6cd0f924a0a0b51bebaaaf1d228c77233a73b0a5a0df0e9", "0x8b882cc3bff3e42babdb96df95fb780faded84887a0a9bab896bef371cdcf169d909f5658649e93006aa3c6e1146d62e", "0x9332663ef1d1dcf805c3d0e4ce7a07d9863fb1731172e766b3cde030bf81682cc011e26b773fb9c68e0477b4ae2cfb79", "0xa8aa8151348dbd4ef40aaeb699b71b4c4bfd3218560c120d85036d14f678f6736f0ec68e80ce1459d3d35feccc575164", "0xa16cd8b729768f51881c213434aa28301fa78fcb554ddd5f9012ee1e4eae7b5cb3dd88d269d53146dea92d10790faf0b", "0x86844f0ef9d37142faf3b1e196e44fbe280a3ba4189aa05c356778cb9e3b388a2bff95eed305ada8769935c9974e4c57", "0xae2eec6b328fccf3b47bcdac32901ac2744a51beb410b04c81dea34dee4912b619466a4f5e2780d87ecefaebbe77b46d", "0x915df4c38d301c8a4eb2dc5b1ba0ffaad67cbb177e0a80095614e9c711f4ef24a4cef133f9d982a63d2a943ba6c8669d", "0xae6a2a4dedfc2d1811711a8946991fede972fdf2a389b282471280737536ffc0ac3a6d885b1f8bda0366eb0b229b9979", "0xa9b628c63d08b8aba6b1317f6e91c34b2382a6c85376e8ef2410a463c6796740ae936fc4e9e0737cb9455d1daa287bd8", "0x848e30bf7edf2546670b390d5cf9ab71f98fcb6add3c0b582cb34996c26a446dee5d1bde4fdcde4fc80c10936e117b29", "0x907d6096c7c8c087d1808dd995d5d2b9169b3768c3f433475b50c2e2bd4b082f4d543afd8b0b0ddffa9c66222a72d51d", "0xa59970a2493b07339124d763ac9d793c60a03354539ecbcf6035bc43d1ea6e35718202ae6d7060b7d388f483d971573c", "0xb9cfef2af9681b2318f119d8611ff6d9485a68d8044581b1959ab1840cbca576dbb53eec17863d2149966e9feb21122f", "0xad47271806161f61d3afa45cdfe2babceef5e90031a21779f83dc8562e6076680525b4970b2f11fe9b2b23c382768323", "0x8e425a99b71677b04fe044625d338811fbb8ee32368a424f6ab2381c52e86ee7a6cecedf777dc97181519d41c351bc22", "0x86b55b54d7adefc12954a9252ee23ae83efe8b5b4b9a7dc307904413e5d69868c7087a818b2833f9b004213d629be8ad", "0xa14fda6b93923dd11e564ae4457a66f397741527166e0b16a8eb91c6701c244fd1c4b63f9dd3515193ec88fa6c266b35", "0xa9b17c36ae6cd85a0ed7f6cabc5b47dc8f80ced605db327c47826476dc1fb8f8669aa7a7dc679fbd4ee3d8e8b4bd6a6f", "0x82a0829469c1458d959c821148f15dacae9ea94bf56c59a6ab2d4dd8b3d16d73e313b5a3912a6c1f131d73a8f06730c4", "0xb22d56d549a53eaef549595924bdb621ff807aa4513feedf3fdcbf7ba8b6b9cfa4481c2f67fc642db397a6b794a8b63a", "0x974c59c24392e2cb9294006cbe3c52163e255f3bd0c2b457bdc68a6338e6d5b6f87f716854492f8d880a6b896ccf757c", "0xb70d247ba7cad97c50b57f526c2ba915786e926a94e8f8c3eebc2e1be6f4255411b9670e382060049c8f4184302c40b2", "0xad80201fe75ef21c3ddbd98cf23591e0d7a3ba1036dfe77785c32f44755a212c31f0ceb0a0b6f5ee9b6dc81f358d30c3", "0x8c656e841f9bb90b9a42d425251f3fdbc022a604d75f5845f479ed4be23e02aaf9e6e56cde351dd7449c50574818a199", "0x8b88dd3fa209d3063b7c5b058f7249ee9900fbc2287d16da61a0704a0a1d71e45d9c96e1cda7fdf9654534ec44558b22", "0x961da00cc8750bd84d253c08f011970ae1b1158ad6778e8ed943d547bceaf52d6d5a212a7de3bf2706688c4389b827d2", "0xa5dd379922549a956033e3d51a986a4b1508e575042b8eaa1df007aa77cf0b8c2ab23212f9c075702788fa9c53696133", "0xac8fcfde3a349d1e93fc8cf450814e842005c545c4844c0401bc80e6b96cdb77f29285a14455e167c191d4f312e866cd", "0xac63d79c799783a8466617030c59dd5a8f92ee6c5204676fd8d881ce5f7f8663bdbeb0379e480ea9b6340ab0dc88e574", "0x805874fde19ce359041ae2bd52a39e2841acabfd31f965792f2737d7137f36d4e4722ede8340d8c95afa6af278af8acb", "0x8d2f323a228aa8ba7b7dc1399138f9e6b41df1a16a7069003ab8104b8b68506a45141bc5fe66acf430e23e13a545190b", "0xa1610c721a2d9af882bb6b39bea97cff1527a3aea041d25934de080214ae77c959e79957164440686d15ab301e897d4d", "0xaba16d29a47fc36f12b654fde513896723e2c700c4190f11b26aa4011da57737ad717daa02794aa3246e4ae5f0b0cc3a", "0xa406db2f15fdd135f346cc4846623c47edd195e80ba8c7cb447332095314d565e4040694ca924696bb5ee7f8996ea0ba", "0x8b30e2cd9b47d75ba57b83630e40f832249af6c058d4f490416562af451993eec46f3e1f90bc4d389e4c06abd1b32a46", "0xaacf9eb7036e248e209adbfc3dd7ce386569ea9b312caa4b240726549db3c68c4f1c8cbf8ed5ea9ea60c7e57c9df3b8e", "0xb20fcac63bf6f5ee638a42d7f89be847f348c085ddcbec3fa318f4323592d136c230495f188ef2022aa355cc2b0da6f9", "0x811eff750456a79ec1b1249d76d7c1547065b839d8d4aaad860f6d4528eb5b669473dcceeeea676cddbc3980b68461b7", "0xb52d14ae33f4ab422f953392ae76a19c618cc31afc96290bd3fe2fb44c954b5c92c4789f3f16e8793f2c0c1691ade444", "0xa7826dafeeba0db5b66c4dfcf2b17fd7b40507a5a53ac2e42942633a2cb30b95ba1739a6e9f3b7a0e0f1ec729bf274e2", "0x8acfd83ddf7c60dd7c8b20c706a3b972c65d336b8f9b3d907bdd8926ced271430479448100050b1ef17578a49c8fa616", "0xaf0c69f65184bb06868029ad46f8465d75c36814c621ac20a5c0b06a900d59305584f5a6709683d9c0e4b6cd08d650a6", "0xb6cc8588191e00680ee6c3339bd0f0a17ad8fd7f4be57d5d7075bede0ea593a19e67f3d7c1a20114894ee5bfcab71063", "0xa82fd4f58635129dbb6cc3eb9391cf2d28400018b105fc41500fbbd12bd890b918f97d3d359c29dd3b4c4e34391dfab0", "0x92fc544ed65b4a3625cf03c41ddff7c039bc22d22c0d59dcc00efd5438401f2606adb125a1d5de294cca216ec8ac35a3", "0x906f67e4a32582b71f15940523c0c7ce370336935e2646bdaea16a06995256d25e99df57297e39d6c39535e180456407", "0x97510337ea5bbd5977287339197db55c60533b2ec35c94d0a460a416ae9f60e85cee39be82abeeacd5813cf54df05862", "0x87e6894643815c0ea48cb96c607266c5ee4f1f82ba5fe352fb77f9b6ed14bfc2b8e09e80a99ac9047dfcf62b2ae26795", "0xb6fd55dd156622ad7d5d51b7dde75e47bd052d4e542dd6449e72411f68275775c846dde301e84613312be8c7bce58b07", "0xb98461ac71f554b2f03a94e429b255af89eec917e208a8e60edf5fc43b65f1d17a20de3f31d2ce9f0cb573c25f2f4d98", "0x96f0dea40ca61cefbee41c4e1fe9a7d81fbe1f49bb153d083ab70f5d0488a1f717fd28cedcf6aa18d07cce2c62801898", "0x8d7c3ab310184f7dc34b6ce4684e4d29a31e77b09940448ea4daac730b7eb308063125d4dd229046cf11bfd521b771e0", "0x96f0564898fe96687918bbf0a6adead99cf72e3a35ea3347e124af9d006221f8e82e5a9d2fe80094d5e8d48e610f415e", "0xad50fcb92c2675a398cf07d4c40a579e44bf8d35f27cc330b57e54d5ea59f7d898af0f75dccfe3726e5471133d70f92b", "0x828beed62020361689ae7481dd8f116902b522fb0c6c122678e7f949fdef70ead011e0e6bffd25678e388744e17cdb69", "0x8349decac1ca16599eee2efc95bcaabf67631107da1d34a2f917884bd70dfec9b4b08ab7bc4379d6c73b19c0b6e54fb8", "0xb2a6a2e50230c05613ace9e58bb2e98d94127f196f02d9dddc53c43fc68c184549ca12d713cb1b025d8260a41e947155", "0x94ff52181aadae832aed52fc3b7794536e2a31a21fc8be3ea312ca5c695750d37f08002f286b33f4023dba1e3253ecfa", "0xa21d56153c7e5972ee9a319501be4faff199fdf09bb821ea9ce64aa815289676c00f105e6f00311b3a5b627091b0d0fc", "0xa27a60d219f1f0c971db73a7f563b371b5c9fc3ed1f72883b2eac8a0df6698400c9954f4ca17d7e94e44bd4f95532afb", "0xa2fc56fae99b1f18ba5e4fe838402164ce82f8a7f3193d0bbd360c2bac07c46f9330c4c7681ffb47074c6f81ee6e7ac6", "0xb748e530cd3afb96d879b83e89c9f1a444f54e55372ab1dcd46a0872f95ce8f49cf2363fc61be82259e04f555937ed16", "0x8bf8993e81080c7cbba1e14a798504af1e4950b2f186ab3335b771d6acaee4ffe92131ae9c53d74379d957cb6344d9cd", "0x96774d0ef730d22d7ab6d9fb7f90b9ead44285219d076584a901960542756700a2a1603cdf72be4708b267200f6c36a9", "0xb47703c2ab17be1e823cc7bf3460db1d6760c0e33862c90ca058845b2ff234b0f9834ddba2efb2ee1770eb261e7d8ffd", "0x84319e67c37a9581f8b09b5e4d4ae88d0a7fb4cbb6908971ab5be28070c3830f040b1de83ee663c573e0f2f6198640e4", "0x96811875fa83133e0b3c0e0290f9e0e28bca6178b77fdf5350eb19344d453dbd0d71e55a0ef749025a5a2ca0ad251e81", "0x81a423423e9438343879f2bfd7ee9f1c74ebebe7ce3cfffc8a11da6f040cc4145c3b527bd3cf63f9137e714dbcb474ef", "0xb8c3535701ddbeec2db08e17a4fa99ba6752d32ece5331a0b8743676f421fcb14798afc7c783815484f14693d2f70db8", "0x81aee980c876949bf40782835eec8817d535f6f3f7e00bf402ddd61101fdcd60173961ae90a1cf7c5d060339a18c959d", "0x87e67b928d97b62c49dac321ce6cb680233f3a394d4c9a899ac2e8db8ccd8e00418e66cdfd68691aa3cb8559723b580c", "0x8eac204208d99a2b738648df96353bbb1b1065e33ee4f6bba174b540bbbd37d205855e1f1e69a6b7ff043ca377651126", "0x848e6e7a54ad64d18009300b93ea6f459ce855971dddb419b101f5ac4c159215626fadc20cc3b9ab1701d8f6dfaddd8b", "0x88aa123d9e0cf309d46dddb6acf634b1ade3b090a2826d6e5e78669fa1220d6df9a6697d7778cd9b627db17eea846126", "0x9200c2a629b9144d88a61151b661b6c4256cc5dadfd1e59a8ce17a013c2d8f7e754aabe61663c3b30f1bc47784c1f8cf", "0xb6e1a2827c3bdda91715b0e1b1f10dd363cef337e7c80cac1f34165fc0dea7c8b69747e310563db5818390146ce3e231", "0x92c333e694f89f0d306d54105b2a5dcc912dbe7654d9e733edab12e8537350815be472b063e56cfde5286df8922fdecb", "0xa6fac04b6d86091158ebb286586ccfec2a95c9786e14d91a9c743f5f05546073e5e3cc717635a0c602cad8334e922346", "0xa581b4af77feebc1fb897d49b5b507c6ad513d8f09b273328efbb24ef0d91eb740d01b4d398f2738125dacfe550330cd", "0x81c4860cccf76a34f8a2bc3f464b7bfd3e909e975cce0d28979f457738a56e60a4af8e68a3992cf273b5946e8d7f76e2", "0x8d1eaa09a3180d8af1cbaee673db5223363cc7229a69565f592fa38ba0f9d582cedf91e15dabd06ebbf2862fc0feba54", "0x9832f49b0147f4552402e54593cfa51f99540bffada12759b71fcb86734be8e500eea2d8b3d036710bdf04c901432de9", "0x8bdb0e8ec93b11e5718e8c13cb4f5de545d24829fd76161216340108098dfe5148ed25e3b57a89a516f09fa79043734d", "0xab96f06c4b9b0b2c0571740b24fca758e6976315053a7ecb20119150a9fa416db2d3a2e0f8168b390bb063f0c1caf785", "0xab777f5c52acd62ecf4d1f168b9cc8e1a9b45d4ec6a8ff52c583e867c2239aba98d7d3af977289b367edce03d9c2dfb1", "0xa09d3ce5e748da84802436951acc3d3ea5d8ec1d6933505ed724d6b4b0d69973ab0930daec9c6606960f6e541e4a3ce2", "0x8ef94f7be4d85d5ad3d779a5cf4d7b2fc3e65c52fb8e1c3c112509a4af77a0b5be994f251e5e40fabeeb1f7d5615c22b", "0xa7406a5bf5708d9e10922d3c5c45c03ef891b8d0d74ec9f28328a72be4cdc05b4f2703fa99366426659dfca25d007535", "0xb7f52709669bf92a2e070bfe740f422f0b7127392c5589c7f0af71bb5a8428697c762d3c0d74532899da24ea7d8695c2", "0xb9dfb0c8df84104dbf9239ccefa4672ef95ddabb8801b74997935d1b81a78a6a5669a3c553767ec19a1281f6e570f4ff", "0xae4d5c872156061ce9195ac640190d8d71dd406055ee43ffa6f9893eb24b870075b74c94d65bc1d5a07a6573282b5520", "0xafe6bd3eb72266d333f1807164900dcfa02a7eb5b1744bb3c86b34b3ee91e3f05e38fa52a50dc64eeb4bdb1dd62874b8", "0x948043cf1bc2ef3c01105f6a78dc06487f57548a3e6ef30e6ebc51c94b71e4bf3ff6d0058c72b6f3ecc37efd7c7fa8c0", "0xa22fd17c2f7ffe552bb0f23fa135584e8d2d8d75e3f742d94d04aded2a79e22a00dfe7acbb57d44e1cdb962fb22ae170", "0x8cd0f4e9e4fb4a37c02c1bde0f69359c43ab012eb662d346487be0c3758293f1ca560122b059b091fddce626383c3a8f", "0x90499e45f5b9c81426f3d735a52a564cafbed72711d9279fdd88de8038e953bc48c57b58cba85c3b2e4ce56f1ddb0e11", "0x8c30e4c034c02958384564cac4f85022ef36ab5697a3d2feaf6bf105049675bbf23d01b4b6814711d3d9271abff04cac", "0x81f7999e7eeea30f3e1075e6780bbf054f2fb6f27628a2afa4d41872a385b4216dd5f549da7ce6cf39049b2251f27fb7", "0xb36a7191f82fc39c283ffe53fc1f5a9a00b4c64eee7792a8443475da9a4d226cf257f226ea9d66e329af15d8f04984ec", "0xaad4da528fdbb4db504f3041c747455baff5fcd459a2efd78f15bdf3aea0bdb808343e49df88fe7a7c8620009b7964a3", "0x99ebd8c6dd5dd299517fb6381cfc2a7f443e6e04a351440260dd7c2aee3f1d8ef06eb6c18820b394366ecdfd2a3ce264", "0x8873725b81871db72e4ec3643084b1cdce3cbf80b40b834b092767728605825c19b6847ad3dcf328438607e8f88b4410", "0xb008ee2f895daa6abd35bd39b6f7901ae4611a11a3271194e19da1cdcc7f1e1ea008fe5c5440e50d2c273784541ad9c5", "0x9036feafb4218d1f576ef89d0e99124e45dacaa6d816988e34d80f454d10e96809791d5b78f7fd65f569e90d4d7238c5", "0x92073c1d11b168e4fa50988b0288638b4868e48bbc668c5a6dddf5499875d53be23a285acb5e4bad60114f6cf6c556e9", "0x88c87dfcb8ba6cbfe7e1be081ccfadbd589301db2cb7c99f9ee5d7db90aa297ed1538d5a867678a763f2deede5fd219a", "0xb42a562805c661a50f5dea63108002c0f27c0da113da6a9864c9feb5552225417c0356c4209e8e012d9bcc9d182c7611", "0x8e6317d00a504e3b79cd47feb4c60f9df186467fe9ca0f35b55c0364db30528f5ff071109dabb2fc80bb9cd4949f0c24", "0xb7b1ea6a88694f8d2f539e52a47466695e39e43a5eb9c6f23bca15305fe52939d8755cc3ac9d6725e60f82f994a3772f", "0xa3cd55161befe795af93a38d33290fb642b8d80da8b786c6e6fb02d393ea308fbe87f486994039cbd7c7b390414594b6", "0xb416d2d45b44ead3b1424e92c73c2cf510801897b05d1724ff31cbd741920cd858282fb5d6040fe1f0aa97a65bc49424", "0x950ee01291754feace97c2e933e4681e7ddfbc4fcd079eb6ff830b0e481d929c93d0c7fb479c9939c28ca1945c40da09", "0x869bd916aee8d86efe362a49010382674825d49195b413b4b4018e88ce43fe091b475d0b863ff0ba2259400f280c2b23", "0x9782f38cd9c9d3385ec286ebbc7cba5b718d2e65a5890b0a5906b10a89dc8ed80d417d71d7c213bf52f2af1a1f513ea7", "0x91cd33bc2628d096269b23faf47ee15e14cb7fdc6a8e3a98b55e1031ea0b68d10ba30d97e660f7e967d24436d40fad73", "0x8becc978129cc96737034c577ae7225372dd855da8811ae4e46328e020c803833b5bdbc4a20a93270e2b8bd1a2feae52", "0xa36b1d8076783a9522476ce17f799d78008967728ce920531fdaf88303321bcaf97ecaa08e0c01f77bc32e53c5f09525", "0xb4720e744943f70467983aa34499e76de6d59aa6fadf86f6b787fdce32a2f5b535b55db38fe2da95825c51002cfe142d", "0x91ad21fc502eda3945f6de874d1b6bf9a9a7711f4d61354f9e5634fc73f9c06ada848de15ab0a75811d3250be862827d", "0x84f78e2ebf5fc077d78635f981712daf17e2475e14c2a96d187913006ad69e234746184a51a06ef510c9455b38acb0d7", "0x960aa7906e9a2f11db64a26b5892ac45f20d2ccb5480f4888d89973beb6fa0dfdc06d68d241ff5ffc7f1b82b1aac242d", "0xa99365dcd1a00c66c9db6924b97c920f5c723380e823b250db85c07631b320ec4e92e586f7319e67a522a0578f7b6d6c", "0xa25d92d7f70cf6a88ff317cfec071e13774516da664f5fac0d4ecaa65b8bf4eb87a64a4d5ef2bd97dfae98d388dbf5cc", "0xa7af47cd0041295798f9779020a44653007444e8b4ef0712982b06d0dcdd434ec4e1f7c5f7a049326602cb605c9105b7", "0xaefe172eac5568369a05980931cc476bebd9dea573ba276d59b9d8c4420784299df5a910033b7e324a6c2dfc62e3ef05", "0xb69bc9d22ffa645baa55e3e02522e9892bb2daa7fff7c15846f13517d0799766883ee09ae0869df4139150c5b843ca8a", "0x95a10856140e493354fdd12722c7fdded21b6a2ffbc78aa2697104af8ad0c8e2206f44b0bfee077ef3949d46bbf7c16b", "0x891f2fcd2c47cbea36b7fa715968540c233313f05333f09d29aba23c193f462ed490dd4d00969656e89c53155fdfe710", "0xa6c33e18115e64e385c843dde34e8a228222795c7ca90bc2cc085705d609025f3351d9be61822c69035a49fb3e48f2d5", "0xb87fb12f12c0533b005adad0487f03393ff682e13575e3cb57280c3873b2c38ba96a63c49eef7a442753d26b7005230b", "0xb905c02ba451bfd411c135036d92c27af3b0b1c9c2f1309d6948544a264b125f39dd41afeff4666b12146c545adc168a", "0x8b29c513f43a78951cf742231cf5457a6d9d55edf45df5481a0f299a418d94effef561b15d2c1a01d1b8067e7153fda9", "0xb9941cccd51dc645920d2781c81a317e5a33cb7cf76427b60396735912cb6d2ca9292bb4d36b6392467d390d2c58d9f3", "0xa8546b627c76b6ef5c93c6a98538d8593dbe21cb7673fd383d5401b0c935eea0bdeeefeb1af6ad41bad8464fb87bbc48", "0xaa286b27de2812de63108a1aec29d171775b69538dc6198640ac1e96767c2b83a50391f49259195957d457b493b667c9", "0xa932fb229f641e9abbd8eb2bd874015d97b6658ab6d29769fc23b7db9e41dd4f850382d4c1f08af8f156c5937d524473", "0xa1412840fcc86e2aeec175526f2fb36e8b3b8d21a78412b7266daf81e51b3f68584ed8bd42a66a43afdd8c297b320520", "0x89c78be9efb624c97ebca4fe04c7704fa52311d183ffd87737f76b7dadc187c12c982bd8e9ed7cd8beb48cdaafd2fd01", "0xa3f5ddec412a5bec0ce15e3bcb41c6214c2b05d4e9135a0d33c8e50a78eaba71e0a5a6ea8b45854dec5c2ed300971fc2", "0x9721f9cec7a68b7758e3887548790de49fa6a442d0396739efa20c2f50352a7f91d300867556d11a703866def2d5f7b5", "0xa23764e140a87e5991573521af039630dd28128bf56eed2edbed130fd4278e090b60cf5a1dca9de2910603d44b9f6d45", "0xa1a6494a994215e48ab55c70efa8ffdddce6e92403c38ae7e8dd2f8288cad460c6c7db526bbdf578e96ca04d9fe12797", "0xb1705ea4cb7e074efe0405fc7b8ee2ec789af0426142f3ec81241cacd4f7edcd88e39435e4e4d8e7b1df64f3880d6613", "0x85595d061d677116089a6064418b93eb44ff79e68d12bd9625078d3bbc440a60d0b02944eff6054433ee34710ae6fbb4", "0x9978d5e30bedb7526734f9a1febd973a70bfa20890490e7cc6f2f9328feab1e24f991285dbc3711d892514e2d7d005ad", "0xaf30243c66ea43b9f87a061f947f7bce745f09194f6e95f379c7582b9fead920e5d6957eaf05c12ae1282ada4670652f", "0xa1930efb473f88001e47aa0b2b2a7566848cccf295792e4544096ecd14ee5d7927c173a8576b405bfa2eec551cd67eb5", "0xb0446d1c590ee5a45f7e22d269c044f3848c97aec1d226b44bfd0e94d9729c28a38bccddc3a1006cc5fe4e3c24f001f2", "0xb8a8380172df3d84b06176df916cf557966d4f2f716d3e9437e415d75b646810f79f2b2b71d857181b7fc944018883a3", "0xa563afec25b7817bfa26e19dc9908bc00aa8fc3d19be7d6de23648701659009d10e3e4486c28e9c6b13d48231ae29ac5", "0xa5a8e80579de886fb7d6408f542791876885947b27ad6fa99a8a26e381f052598d7b4e647b0115d4b5c64297e00ce28e", "0x8f87afcc7ad33c51ac719bade3cd92da671a37a82c14446b0a2073f4a0a23085e2c8d31913ed2d0be928f053297de8f6", "0xa43c455ce377e0bc434386c53c752880687e017b2f5ae7f8a15c044895b242dffde4c92fb8f8bb50b18470b17351b156", "0x8368f8b12a5bceb1dba25adb3a2e9c7dc9b1a77a1f328e5a693f5aec195cd1e06b0fe9476b554c1c25dac6c4a5b640a3", "0x919878b27f3671fc78396f11531c032f3e2bd132d04cc234fa4858676b15fb1db3051c0b1db9b4fc49038216f11321ce", "0xb48cd67fb7f1242696c1f877da4bdf188eac676cd0e561fbac1a537f7b8229aff5a043922441d603a26aae56a15faee4", "0xa3e0fdfd4d29ea996517a16f0370b54787fefe543c2fe73bfc6f9e560c1fd30dad8409859e2d7fa2d44316f24746c712", "0x8bb156ade8faf149df7bea02c140c7e392a4742ae6d0394d880a849127943e6f26312033336d3b9fdc0092d71b5efe87", "0x8845e5d5cc555ca3e0523244300f2c8d7e4d02aaebcb5bd749d791208856c209a6f84dd99fd55968c9f0ab5f82916707", "0xa3e90bb5c97b07789c2f32dff1aec61d0a2220928202f5ad5355ae71f8249237799d6c8a22602e32e572cb12eabe0c17", "0xb150bcc391884c996149dc3779ce71f15dda63a759ee9cc05871f5a8379dcb62b047098922c0f26c7bd04deb394c33f9", "0x95cd4ad88d51f0f2efcfd0c2df802fe252bb9704d1afbf9c26a248df22d55da87bdfaf41d7bc6e5df38bd848f0b13f42", "0xa05a49a31e91dff6a52ac8b9c2cfdd646a43f0d488253f9e3cfbce52f26667166bbb9b608fc358763a65cbf066cd6d05", "0xa59c3c1227fdd7c2e81f5e11ef5c406da44662987bac33caed72314081e2eed66055d38137e01b2268e58ec85dd986c0", "0xb7020ec3bd73a99861f0f1d88cf5a19abab1cbe14b7de77c9868398c84bb8e18dbbe9831838a96b6d6ca06e82451c67b", "0x98d1ff2525e9718ee59a21d8900621636fcd873d9a564b8dceb4be80a194a0148daf1232742730b3341514b2e5a5436c", "0x886d97b635975fc638c1b6afc493e5998ca139edba131b75b65cfe5a8e814f11bb678e0eeee5e6e5cd913ad3f2fefdfc", "0x8fb9fd928d38d5d813b671c924edd56601dd7163b686c13f158645c2f869d9250f3859aa5463a39258c90fef0f41190a", "0xaac35e1cd655c94dec3580bb3800bd9c2946c4a9856f7d725af15fbea6a2d8ca51c8ad2772abed60ee0e3fb9cb24046b", "0xb8d71fa0fa05ac9e443c9b4929df9e7f09a919be679692682e614d24227e04894bfc14a5c73a62fb927fedff4a0e4aa7", "0xa45a19f11fbbb531a704badbb813ed8088ab827c884ee4e4ebf363fa1132ff7cfa9d28be9c85b143e4f7cdbc94e7cf1a", "0x82b54703a4f295f5471b255ab59dce00f0fe90c9fb6e06b9ee48b15c91d43f4e2ef4a96c3118aeb03b08767be58181bb", "0x8283264c8e6d2a36558f0d145c18576b6600ff45ff99cc93eca54b6c6422993cf392668633e5df396b9331e873d457e5", "0x8c549c03131ead601bc30eb6b9537b5d3beb7472f5bb1bcbbfd1e9f3704477f7840ab3ab7f7dc13bbbbcdff886a462d4", "0xafbb0c520ac1b5486513587700ad53e314cb74bfbc12e0b5fbdcfdaac36d342e8b59856196a0d84a25cff6e6e1d17e76", "0x89e4c22ffb51f2829061b3c7c1983c5c750cad158e3a825d46f7cf875677da5d63f653d8a297022b5db5845c9271b32b", "0xafb27a86c4c2373088c96b9adf4433f2ebfc78ac5c526e9f0510670b6e4e5e0057c0a4f75b185e1a30331b9e805c1c15", "0xa18e16b57445f88730fc5d3567bf5a176861dc14c7a08ed2996fe80eed27a0e7628501bcb78a1727c5e9ac55f29c12c4", "0x93d61bf88b192d6825cf4e1120af1c17aa0f994d158b405e25437eaeefae049f7b721a206e7cc8a04fdc29d3c42580a1", "0xa99f2995a2e3ed2fd1228d64166112038de2f516410aa439f4c507044e2017ea388604e2d0f7121256fadf7fbe7023d1", "0x914fd91cffc23c32f1c6d0e98bf660925090d873367d543034654389916f65f552e445b0300b71b61b721a72e9a5983c", "0xb42a578a7787b71f924e7def425d849c1c777156b1d4170a8ee7709a4a914e816935131afd9a0412c4cb952957b20828", "0x82fb30590e84b9e45db1ec475a39971cf554dc01bcc7050bc89265740725c02e2be5a972168c5170c86ae83e5b0ad2c0", "0xb14f8d8e1e93a84976289e0cf0dfa6f3a1809e98da16ee5c4932d0e1ed6bf8a07697fdd4dd86a3df84fb0003353cdcc0", "0x85d7a2f4bda31aa2cb208b771fe03291a4ebdaf6f1dc944c27775af5caec412584c1f45bc741fca2a6a85acb3f26ad7d", "0xaf02e56ce886ff2253bc0a68faad76f25ead84b2144e5364f3fb9b648f03a50ee9dc0b2c33ebacf7c61e9e43201ef9ef", "0x87e025558c8a0b0abd06dfc350016847ea5ced7af2d135a5c9eec9324a4858c4b21510fb0992ec52a73447f24945058e", "0x80fff0bafcd058118f5e7a4d4f1ae0912efeb281d2cbe4d34ba8945cc3dbe5d8baf47fb077343b90b8d895c90b297aca", "0xb6edcf3a40e7b1c3c0148f47a263cd819e585a51ef31c2e35a29ce6f04c53e413f743034c0d998d9c00a08ba00166f31", "0xabb87ed86098c0c70a76e557262a494ff51a30fb193f1c1a32f8e35eafa34a43fcc07aa93a3b7a077d9e35afa07b1a3d", "0xa280214cd3bb0fb7ecd2d8bcf518cbd9078417f2b91d2533ec2717563f090fb84f2a5fcfdbbeb2a2a1f8a71cc5aa5941", "0xa63083ca7238ea2b57d15a475963cf1d4f550d8cd76db290014a0461b90351f1f26a67d674c837b0b773b330c7c3d534", "0xa8fa39064cb585ece5263e2f42f430206476bf261bd50f18d2b694889bd79d04d56410664cecad62690e5c5a20b3f6ff", "0x85ba52ce9d700a5dcf6c5b00559acbe599d671ce5512467ff4b6179d7fad550567ce2a9c126a50964e3096458ea87920", "0xb913501e1008f076e5eac6d883105174f88b248e1c9801e568fefaffa1558e4909364fc6d9512aa4d125cbd7cc895f05", "0x8eb33b5266c8f2ed4725a6ad147a322e44c9264cf261c933cbbe230a43d47fca0f29ec39756b20561dabafadd5796494", "0x850ebc8b661a04318c9db5a0515066e6454fa73865aa4908767a837857ecd717387f614acb614a88e075d4edc53a2f5a", "0xa08d6b92d866270f29f4ce23a3f5d99b36b1e241a01271ede02817c8ec3f552a5c562db400766c07b104a331835c0c64", "0x8131804c89bb3e74e9718bfc4afa547c1005ff676bd4db9604335032b203390cfa54478d45c6c78d1fe31a436ed4be9f", "0x9106d94f23cc1eacec8316f16d6f0a1cc160967c886f51981fdb9f3f12ee1182407d2bb24e5b873de58cb1a3ee915a6b", "0xa13806bfc3eae7a7000c9d9f1bd25e10218d4e67f59ae798b145b098bca3edad2b1040e3fc1e6310e612fb8818f459ac", "0x8c69fbca502046cb5f6db99900a47b34117aef3f4b241690cdb3b84ca2a2fc7833e149361995dc41fa78892525bce746", "0x852c473150c91912d58ecb05769222fa18312800c3f56605ad29eec9e2d8667b0b81c379048d3d29100ed2773bb1f3c5", "0xb1767f6074426a00e01095dbb1795beb4e4050c6411792cbad6537bc444c3165d1058bafd1487451f9c5ddd209e0ae7e", "0x80c600a5fe99354ce59ff0f84c760923dc8ff66a30bf47dc0a086181785ceb01f9b951c4e66df800ea6d705e8bc47055", "0xb5cf19002fbc88a0764865b82afcb4d64a50196ea361e5c71dff7de084f4dcbbc34ec94a45cc9e0247bd51da565981aa", "0x93e67a254ea8ce25e112d93cc927fadaa814152a2c4ec7d9a56eaa1ed47aec99b7e9916b02e64452cc724a6641729bbb", "0xace70b32491bda18eee4a4d041c3bc9effae9340fe7e6c2f5ad975ee0874c17f1a7da7c96bd85fccff9312c518fac6e9", "0xab4cfa02065017dd7f1aadc66f2c92f78f0f11b8597c03a5d69d82cb2eaf95a4476a836ac102908f137662472c8d914b", "0xa40b8cd8deb8ae503d20364d64cab7c2801b7728a9646ed19c65edea6a842756a2f636283494299584ad57f4bb12cd0b", "0x8594e11d5fc2396bcd9dbf5509ce4816dbb2b7305168021c426171fb444d111da5a152d6835ad8034542277011c26c0e", "0x8024de98c26b4c994a66628dc304bb737f4b6859c86ded552c5abb81fd4c6c2e19d5a30beed398a694b9b2fdea1dd06a", "0x8843f5872f33f54df8d0e06166c1857d733995f67bc54abb8dfa94ad92407cf0179bc91b0a50bbb56cdc2b350d950329", "0xb8bab44c7dd53ef9edf497dcb228e2a41282c90f00ba052fc52d57e87b5c8ab132d227af1fcdff9a12713d1f980bcaae", "0x982b4d7b29aff22d527fd82d2a52601d95549bfb000429bb20789ed45e5abf1f4b7416c7b7c4b79431eb3574b29be658", "0x8eb1f571b6a1878e11e8c1c757e0bc084bab5e82e897ca9be9b7f4b47b91679a8190bf0fc8f799d9b487da5442415857", "0xa6e74b588e5af935c8b243e888582ef7718f8714569dd4992920740227518305eb35fab674d21a5551cca44b3e511ef2", "0xa30fc2f3a4cb4f50566e82307de73cd7bd8fe2c1184e9293c136a9b9e926a018d57c6e4f308c95b9eb8299e94d90a2a1", "0xa50c5869ca5d2b40722c056a32f918d47e0b65ca9d7863ca7d2fb4a7b64fe523fe9365cf0573733ceaadebf20b48fff8", "0x83bbdd32c04d17581418cf360749c7a169b55d54f2427390defd9f751f100897b2d800ce6636c5bbc046c47508d60c8c", "0xa82904bdf614de5d8deaff688c8a5e7ac5b3431687acbcda8fa53960b7c417a39c8b2e462d7af91ce6d79260f412db8e", "0xa4362e31ff4b05d278b033cf5eebea20de01714ae16d4115d04c1da4754269873afc8171a6f56c5104bfd7b0db93c3e7", "0xb5b8daa63a3735581e74a021b684a1038cea77168fdb7fdf83c670c2cfabcfc3ab2fc7359069b5f9048188351aef26b5", "0xb48d723894b7782d96ac8433c48faca1bdfa5238019c451a7f47d958097cce3ae599b876cf274269236b9d6ff8b6d7ca", "0x98ffff6a61a3a6205c7820a91ca2e7176fab5dba02bc194c4d14942ac421cb254183c705506ab279e4f8db066f941c6c", "0xae7db24731da2eaa6efc4f7fcba2ecc26940ddd68038dce43acf2cee15b72dc4ef42a7bfdd32946d1ed78786dd7696b3", "0xa656db14f1de9a7eb84f6301b4acb2fbf78bfe867f48a270e416c974ab92821eb4df1cb881b2d600cfed0034ac784641", "0xaa315f8ecba85a5535e9a49e558b15f39520fce5d4bf43131bfbf2e2c9dfccc829074f9083e8d49f405fb221d0bc4c3c", "0x90bffba5d9ff40a62f6c8e9fc402d5b95f6077ed58d030c93e321b8081b77d6b8dac3f63a92a7ddc01585cf2c127d66c", "0xabdd733a36e0e0f05a570d0504e73801bf9b5a25ff2c78786f8b805704997acb2e6069af342538c581144d53149fa6d3", "0xb4a723bb19e8c18a01bd449b1bb3440ddb2017f10bb153da27deb7a6a60e9bb37619d6d5435fbb1ba617687838e01dd0", "0x870016b4678bab3375516db0187a2108b2e840bae4d264b9f4f27dbbc7cc9cac1d7dc582d7a04d6fd1ed588238e5e513", "0x80d33d2e20e8fc170aa3cb4f69fffb72aeafb3b5bb4ea0bc79ab55da14142ca19b2d8b617a6b24d537366e3b49cb67c3", "0xa7ee76aec273aaae03b3b87015789289551969fb175c11557da3ab77e39ab49d24634726f92affae9f4d24003050d974", "0x8415ea4ab69d779ebd42d0fe0c6aef531d6a465a5739e429b1fcf433ec45aa8296c527e965a20f0ec9f340c9273ea3cf", "0x8c7662520794e8b4405d0b33b5cac839784bc86a5868766c06cbc1fa306dbe334978177417b31baf90ce7b0052a29c56", "0x902b2abecc053a3dbdea9897ee21e74821f3a1b98b2d560a514a35799f4680322550fd3a728d4f6d64e1de98033c32b8", "0xa05e84ed9ecab8d508d670c39f2db61ad6e08d2795ec32a3c9d0d3737ef3801618f4fc2a95f90ec2f068606131e076c5", "0x8b9208ff4d5af0c2e3f53c9375da666773ac57197dfabb0d25b1c8d0588ba7f3c15ee9661bb001297f322ea2fbf6928b", "0xa3c827741b34a03254d4451b5ab74a96f2b9f7fb069e2f5adaf54fd97cc7a4d516d378db5ca07da87d8566d6eef13726", "0x8509d8a3f4a0ed378e0a1e28ea02f6bf1d7f6c819c6c2f5297c7df54c895b848f841653e32ba2a2c22c2ff739571acb8", "0xa0ce988b7d3c40b4e496aa83a09e4b5472a2d98679622f32bea23e6d607bc7de1a5374fb162bce0549a67dad948519be", "0xaa8a3dd12bd60e3d2e05f9c683cdcb8eab17fc59134815f8d197681b1bcf65108cba63ac5c58ee632b1e5ed6bba5d474", "0x8b955f1d894b3aefd883fb4b65f14cd37fc2b9db77db79273f1700bef9973bf3fd123897ea2b7989f50003733f8f7f21", "0xac79c00ddac47f5daf8d9418d798d8af89fc6f1682e7e451f71ea3a405b0d36af35388dd2a332af790bc83ca7b819328", "0xa0d44dd2a4438b809522b130d0938c3fe7c5c46379365dbd1810a170a9aa5818e1c783470dd5d0b6d4ac7edbb7330910", "0xa30b69e39ad43dd540a43c521f05b51b5f1b9c4eed54b8162374ae11eac25da4f5756e7b70ce9f3c92c2eeceee7431ed", "0xac43220b762c299c7951222ea19761ab938bf38e4972deef58ed84f4f9c68c230647cf7506d7cbfc08562fcca55f0485", "0xb28233b46a8fb424cfa386a845a3b5399d8489ceb83c8f3e05c22c934798d639c93718b7b68ab3ce24c5358339e41cbb", "0xac30d50ee8ce59a10d4b37a3a35e62cdb2273e5e52232e202ca7d7b8d09d28958ee667fae41a7bb6cdc6fe8f6e6c9c85", "0xb199842d9141ad169f35cc7ff782b274cbaa645fdb727761e0a89edbf0d781a15f8218b4bf4eead326f2903dd88a9cc1", "0x85e018c7ddcad34bb8285a737c578bf741ccd547e68c734bdb3808380e12c5d4ef60fc896b497a87d443ff9abd063b38", "0x8c856e6ba4a815bdb891e1276f93545b7072f6cb1a9aa6aa5cf240976f29f4dee01878638500a6bf1daf677b96b54343", "0xb8a47555fa8710534150e1a3f13eab33666017be6b41005397afa647ea49708565f2b86b77ad4964d140d9ced6b4d585", "0x8cd1f1db1b2f4c85a3f46211599caf512d5439e2d8e184663d7d50166fd3008f0e9253272f898d81007988435f715881", "0xb1f34b14612c973a3eceb716dc102b82ab18afef9de7630172c2780776679a7706a4874e1df3eaadf541fb009731807f", "0xb25464af9cff883b55be2ff8daf610052c02df9a5e147a2cf4df6ce63edcdee6dc535c533590084cc177da85c5dc0baa", "0x91c3c4b658b42d8d3448ae1415d4541d02379a40dc51e36a59bd6e7b9ba3ea51533f480c7c6e8405250ee9b96a466c29", "0x86dc027b95deb74c36a58a1333a03e63cb5ae22d3b29d114cfd2271badb05268c9d0c819a977f5e0c6014b00c1512e3a", "0xae0e6ff58eb5fa35da5107ebeacf222ab8f52a22bb1e13504247c1dfa65320f40d97b0e6b201cb6613476687cb2f0681", "0x8f13415d960b9d7a1d93ef28afc2223e926639b63bdefce0f85e945dfc81670a55df288893a0d8b3abe13c5708f82f91", "0x956f67ca49ad27c1e3a68c1faad5e7baf0160c459094bf6b7baf36b112de935fdfd79fa4a9ea87ea8de0ac07272969f4", "0x835e45e4a67df9fb51b645d37840b3a15c171d571a10b03a406dd69d3c2f22df3aa9c5cbe1e73f8d767ce01c4914ea9a", "0x919b938e56d4b32e2667469d0bdccb95d9dda3341aa907683ee70a14bbbe623035014511c261f4f59b318b610ac90aa3", "0x96b48182121ccd9d689bf1dfdc228175564cd68dc904a99c808a7f0053a6f636c9d953e12198bdf2ea49ea92772f2e18", "0xac5e5a941d567fa38fdbcfa8cf7f85bb304e3401c52d88752bcd516d1fa9bac4572534ea2205e38423c1df065990790f", "0xac0bd594fb85a8d4fc26d6df0fa81f11919401f1ecf9168b891ec7f061a2d9368af99f7fd8d9b43b2ce361e7b8482159", "0x83d92c69ca540d298fe80d8162a1c7af3fa9b49dfb69e85c1d136a3ec39fe419c9fa78e0bb6d96878771fbd37fe92e40", "0xb35443ae8aa66c763c2db9273f908552fe458e96696b90e41dd509c17a5c04ee178e3490d9c6ba2dc0b8f793c433c134", "0x923b2d25aa45b2e580ffd94cbb37dc8110f340f0f011217ee1bd81afb0714c0b1d5fb4db86006cdd2457563276f59c59", "0x96c9125d38fca1a61ac21257b696f8ac3dae78def50285e44d90ea293d591d1c58f703540a7e4e99e070afe4646bbe15", "0xb57946b2332077fbcdcb406b811779aefd54473b5559a163cd65cb8310679b7e2028aa55c12a1401fdcfcac0e6fae29a", "0x845daedc5cf972883835d7e13c937b63753c2200324a3b8082a6c4abb4be06c5f7c629d4abe4bfaf1d80a1f073eb6ce6", "0x91a55dfd0efefcd03dc6dacc64ec93b8d296cb83c0ee72400a36f27246e7f2a60e73b7b70ba65819e9cfb73edb7bd297", "0x8874606b93266455fe8fdd25df9f8d2994e927460af06f2e97dd4d2d90db1e6b06d441b72c2e76504d753badca87fb37", "0x8ee99e6d231274ff9252c0f4e84549da173041299ad1230929c3e3d32399731c4f20a502b4a307642cac9306ccd49d3c", "0x8836497714a525118e20849d6933bb8535fb6f72b96337d49e3133d936999c90a398a740f42e772353b5f1c63581df6d", "0xa6916945e10628f7497a6cdc5e2de113d25f7ade3e41e74d3de48ccd4fce9f2fa9ab69645275002e6f49399b798c40af", "0x9597706983107eb23883e0812e1a2c58af7f3499d50c6e29b455946cb9812fde1aa323d9ed30d1c0ffd455abe32303cd", "0xa24ee89f7f515cc33bdbdb822e7d5c1877d337f3b2162303cfc2dae028011c3a267c5cb4194afa63a4856a6e1c213448", "0x8cd25315e4318801c2776824ae6e7d543cb85ed3bc2498ba5752df2e8142b37653cf9e60104d674be3aeb0a66912e97a", "0xb5085ecbe793180b40dbeb879f4c976eaaccaca3a5246807dced5890e0ed24d35f3f86955e2460e14fb44ff5081c07ba", "0x960188cc0b4f908633a6840963a6fa2205fc42c511c6c309685234911c5304ef4c304e3ae9c9c69daa2fb6a73560c256", "0xa32d0a70bf15d569b4cda5aebe3e41e03c28bf99cdd34ffa6c5d58a097f322772acca904b3a47addb6c7492a7126ebac", "0x977f72d06ad72d4aa4765e0f1f9f4a3231d9f030501f320fe7714cc5d329d08112789fa918c60dd7fdb5837d56bb7fc6", "0x99fa038bb0470d45852bb871620d8d88520adb701712fcb1f278fed2882722b9e729e6cdce44c82caafad95e37d0e6f7", "0xb855e8f4fc7634ada07e83b6c719a1e37acb06394bc8c7dcab7747a8c54e5df3943915f021364bd019fdea103864e55f", "0x88bc2cd7458532e98c596ef59ea2cf640d7cc31b4c33cef9ed065c078d1d4eb49677a67de8e6229cc17ea48bace8ee5a", "0xaaa78a3feaa836d944d987d813f9b9741afb076e6aca1ffa42682ab06d46d66e0c07b8f40b9dbd63e75e81efa1ef7b08", "0xb7b080420cc4d808723b98b2a5b7b59c81e624ab568ecdfdeb8bf3aa151a581b6f56e983ef1b6f909661e25db40b0c69", "0xabee85c462ac9a2c58e54f06c91b3e5cd8c5f9ab5b5deb602b53763c54826ed6deb0d6db315a8d7ad88733407e8d35e2", "0x994d075c1527407547590df53e9d72dd31f037c763848d1662eebd4cefec93a24328c986802efa80e038cb760a5300f5", "0xab8777640116dfb6678e8c7d5b36d01265dfb16321abbfc277da71556a34bb3be04bc4ae90124ed9c55386d2bfb3bda0", "0x967e3a828bc59409144463bcf883a3a276b5f24bf3cbfdd7a42343348cba91e00b46ac285835a9b91eef171202974204", "0x875a9f0c4ffe5bb1d8da5e3c8e41d0397aa6248422a628bd60bfae536a651417d4e8a7d2fb98e13f2dad3680f7bd86d3", "0xacaa330c3e8f95d46b1880126572b238dbb6d04484d2cd4f257ab9642d8c9fc7b212188b9c7ac9e0fd135c520d46b1bf", "0xaceb762edbb0f0c43dfcdb01ea7a1ac5918ca3882b1e7ebc4373521742f1ed5250d8966b498c00b2b0f4d13212e6dd0b", "0x81d072b4ad258b3646f52f399bced97c613b22e7ad76373453d80b1650c0ca87edb291a041f8253b649b6e5429bb4cff", "0x980a47d27416ac39c7c3a0ebe50c492f8c776ea1de44d5159ac7d889b6d554357f0a77f0e5d9d0ff41aae4369eba1fc2", "0x8b4dfd5ef5573db1476d5e43aacfb5941e45d6297794508f29c454fe50ea622e6f068b28b3debe8635cf6036007de2e3", "0xa60831559d6305839515b68f8c3bc7abbd8212cc4083502e19dd682d56ca37c9780fc3ce4ec2eae81ab23b221452dc57", "0x951f6b2c1848ced9e8a2339c65918e00d3d22d3e59a0a660b1eca667d18f8430d737884e9805865ef3ed0fe1638a22d9", "0xb02e38fe790b492aa5e89257c4986c9033a8b67010fa2add9787de857d53759170fdd67715ca658220b4e14b0ca48124", "0xa51007e4346060746e6b0e4797fc08ef17f04a34fe24f307f6b6817edbb8ce2b176f40771d4ae8a60d6152cbebe62653", "0xa510005b05c0b305075b27b243c9d64bcdce85146b6ed0e75a3178b5ff9608213f08c8c9246f2ca6035a0c3e31619860", "0xaaff4ef27a7a23be3419d22197e13676d6e3810ceb06a9e920d38125745dc68a930f1741c9c2d9d5c875968e30f34ab5", "0x864522a9af9857de9814e61383bebad1ba9a881696925a0ea6bfc6eff520d42c506bbe5685a9946ed710e889765be4a0", "0xb63258c080d13f3b7d5b9f3ca9929f8982a6960bdb1b0f8676f4dca823971601672f15e653917bf5d3746bb220504913", "0xb51ce0cb10869121ae310c7159ee1f3e3a9f8ad498827f72c3d56864808c1f21fa2881788f19ece884d3f705cd7bd0c5", "0x95d9cecfc018c6ed510e441cf84c712d9909c778c16734706c93222257f64dcd2a9f1bd0b400ca271e22c9c487014274", "0x8beff4d7d0140b86380ff4842a9bda94c2d2be638e20ac68a4912cb47dbe01a261857536375208040c0554929ced1ddc", "0x891ff49258749e2b57c1e9b8e04b12c77d79c3308b1fb615a081f2aacdfb4b39e32d53e069ed136fdbd43c53b87418fa", "0x9625cad224e163d387738825982d1e40eeff35fe816d10d7541d15fdc4d3eee48009090f3faef4024b249205b0b28f72", "0x8f3947433d9bd01aa335895484b540a9025a19481a1c40b4f72dd676bfcf332713714fd4010bde936eaf9470fd239ed0", "0xa00ec2d67789a7054b53f0e858a8a232706ccc29a9f3e389df7455f1a51a2e75801fd78469a13dbc25d28399ae4c6182", "0xa3f65884506d4a62b8775a0ea0e3d78f5f46bc07910a93cd604022154eabdf1d73591e304d61edc869e91462951975e1", "0xa14eef4fd5dfac311713f0faa9a60415e3d30b95a4590cbf95f2033dffb4d16c02e7ceff3dcd42148a4e3bc49cce2dd4", "0x8afa11c0eef3c540e1e3460bc759bb2b6ea90743623f88e62950c94e370fe4fd01c22b6729beba4dcd4d581198d9358f", "0xafb05548a69f0845ffcc5f5dc63e3cdb93cd270f5655173b9a950394b0583663f2b7164ba6df8d60c2e775c1d9f120af", "0x97f179e01a947a906e1cbeafa083960bc9f1bade45742a3afee488dfb6011c1c6e2db09a355d77f5228a42ccaa7bdf8e", "0x8447fca4d35f74b3efcbd96774f41874ca376bf85b79b6e66c92fa3f14bdd6e743a051f12a7fbfd87f319d1c6a5ce217", "0xa57ca39c23617cd2cf32ff93b02161bd7baf52c4effb4679d9d5166406e103bc8f3c6b5209e17c37dbb02deb8bc72ddd", "0x9667c7300ff80f0140be002b0e36caab07aaee7cce72679197c64d355e20d96196acaf54e06e1382167d081fe6f739c1", "0x828126bb0559ce748809b622677267ca896fa2ee76360fd2c02990e6477e06a667241379ca7e65d61a5b64b96d7867de", "0x8b8835dea6ba8cf61c91f01a4b3d2f8150b687a4ee09b45f2e5fc8f80f208ae5d142d8e3a18153f0722b90214e60c5a7", "0xa98e8ff02049b4da386e3ee93db23bbb13dfeb72f1cfde72587c7e6d962780b7671c63e8ac3fbaeb1a6605e8d79e2f29", "0x87a4892a0026d7e39ef3af632172b88337cb03669dea564bcdb70653b52d744730ebb5d642e20cb627acc9dbb547a26b", "0x877352a22fc8052878a57effc159dac4d75fe08c84d3d5324c0bab6d564cdf868f33ceee515eee747e5856b62cfa0cc7", "0x8b801ba8e2ff019ee62f64b8cb8a5f601fc35423eb0f9494b401050103e1307dc584e4e4b21249cd2c686e32475e96c3", "0xa9e7338d6d4d9bfec91b2af28a8ed13b09415f57a3a00e5e777c93d768fdb3f8e4456ae48a2c6626b264226e911a0e28", "0x99c05fedf40ac4726ed585d7c1544c6e79619a0d3fb6bda75a08c7f3c0008e8d5e19ed4da48de3216135f34a15eba17c", "0xa61cce8a1a8b13a4a650fdbec0eeea8297c352a8238fb7cac95a0df18ed16ee02a3daa2de108fa122aca733bd8ad7855", "0xb97f37da9005b440b4cb05870dd881bf8491fe735844f2d5c8281818583b38e02286e653d9f2e7fa5e74c3c3eb616540", "0xa72164a8554da8e103f692ac5ebb4aece55d5194302b9f74b6f2a05335b6e39beede0bf7bf8c5bfd4d324a784c5fb08c", "0xb87e8221c5341cd9cc8bb99c10fe730bc105550f25ed4b96c0d45e6142193a1b2e72f1b3857373a659b8c09be17b3d91", "0xa41fb1f327ef91dcb7ac0787918376584890dd9a9675c297c45796e32d6e5985b12f9b80be47fc3a8596c245f419d395", "0x90dafa3592bdbb3465c92e2a54c2531822ba0459d45d3e7a7092fa6b823f55af28357cb51896d4ec2d66029c82f08e26", "0xa0a9adc872ebc396557f484f1dd21954d4f4a21c4aa5eec543f5fa386fe590839735c01f236574f7ff95407cd12de103", "0xb8c5c940d58be7538acf8672852b5da3af34f82405ef2ce8e4c923f1362f97fc50921568d0fd2fe846edfb0823e62979", "0x85aaf06a8b2d0dac89dafd00c28533f35dbd074978c2aaa5bef75db44a7b12aeb222e724f395513b9a535809a275e30b", "0x81f3cbe82fbc7028c26a6c1808c604c63ba023a30c9f78a4c581340008dbda5ec07497ee849a2183fcd9124f7936af32", "0xa11ac738de75fd60f15a34209d3825d5e23385796a4c7fc5931822f3f380af977dd0f7b59fbd58eed7777a071e21b680", "0x85a279c493de03db6fa6c3e3c1b1b29adc9a8c4effc12400ae1128da8421954fa8b75ad19e5388fe4543b76fb0812813", "0x83a217b395d59ab20db6c4adb1e9713fc9267f5f31a6c936042fe051ce8b541f579442f3dcf0fa16b9e6de9fd3518191", "0x83a0b86e7d4ed8f9ccdc6dfc8ff1484509a6378fa6f09ed908e6ab9d1073f03011dc497e14304e4e3d181b57de06a5ab", "0xa63ad69c9d25704ce1cc8e74f67818e5ed985f8f851afa8412248b2df5f833f83b95b27180e9e7273833ed0d07113d3b", "0x99b1bc2021e63b561fe44ddd0af81fcc8627a91bfeecbbc989b642bc859abc0c8d636399701aad7bbaf6a385d5f27d61", "0xb53434adb66f4a807a6ad917c6e856321753e559b1add70824e5c1e88191bf6993fccb9b8b911fc0f473fb11743acacd", "0x97ed3b9e6fb99bf5f945d4a41f198161294866aa23f2327818cdd55cb5dc4c1a8eff29dd8b8d04902d6cd43a71835c82", "0xb1e808260e368a18d9d10bdea5d60223ba1713b948c782285a27a99ae50cc5fc2c53d407de07155ecc16fb8a36d744a0", "0xa3eb4665f18f71833fec43802730e56b3ee5a357ea30a888ad482725b169d6f1f6ade6e208ee081b2e2633079b82ba7d", "0xab8beb2c8353fc9f571c18fdd02bdb977fc883313469e1277b0372fbbb33b80dcff354ca41de436d98d2ed710faa467e", "0xaa9071cfa971e4a335a91ad634c98f2be51544cb21f040f2471d01bb97e1df2277ae1646e1ea8f55b7ba9f5c8c599b39", "0x80b7dbfdcaf40f0678012acc634eba44ea51181475180d9deb2050dc4f2de395289edd0223018c81057ec79b04b04c49", "0x89623d7f6cb17aa877af14de842c2d4ab7fd576d61ddd7518b5878620a01ded40b6010de0da3cdf31d837eecf30e9847", "0xa773bb024ae74dd24761f266d4fb27d6fd366a8634febe8235376b1ae9065c2fe12c769f1d0407867dfbe9f5272c352f", "0x8455a561c3aaa6ba64c881a5e13921c592b3a02e968f4fb24a2243c36202795d0366d9cc1a24e916f84d6e158b7aeac7", "0x81d8bfc4b283cf702a40b87a2b96b275bdbf0def17e67d04842598610b67ea08c804d400c3e69fa09ea001eaf345b276", "0xb8f8f82cb11fea1c99467013d7e167ff03deb0c65a677fab76ded58826d1ba29aa7cf9fcd7763615735ea3ad38e28719", "0x89a6a04baf9cccc1db55179e1650b1a195dd91fb0aebc197a25143f0f393524d2589975e3fbfc2547126f0bced7fd6f2", "0xb81b2162df045390f04df07cbd0962e6b6ca94275a63edded58001a2f28b2ae2af2c7a6cba4ecd753869684e77e7e799", "0xa3757f722776e50de45c62d9c4a2ee0f5655a512344c4cbec542d8045332806568dd626a719ef21a4eb06792ca70f204", "0x8c5590df96ec22179a4e8786de41beb44f987a1dcc508eb341eecbc0b39236fdfad47f108f852e87179ccf4e10091e59", "0x87502f026ed4e10167419130b88c3737635c5b9074c364e1dd247cef5ef0fc064b4ae99b187e33301e438bbd2fe7d032", "0xaf925a2165e980ced620ff12289129fe17670a90ae0f4db9d4b39bd887ccb1f5d2514ac9ecf910f6390a8fc66bd5be17", "0x857fca899828cf5c65d26e3e8a6e658542782fc72762b3b9c73514919f83259e0f849a9d4838b40dc905fe43024d0d23", "0x87ffebdbfb69a9e1007ebac4ffcb4090ff13705967b73937063719aa97908986effcb7262fdadc1ae0f95c3690e3245d", "0xa9ff6c347ac6f4c6ab993b748802e96982eaf489dc69032269568412fc9a79e7c2850dfc991b28211b3522ee4454344b", "0xa65b3159df4ec48bebb67cb3663cd744027ad98d970d620e05bf6c48f230fa45bf17527fe726fdf705419bb7a1bb913e", "0x84b97b1e6408b6791831997b03cd91f027e7660fd492a93d95daafe61f02427371c0e237c75706412f442991dfdff989", "0xab761c26527439b209af0ae6afccd9340bbed5fbe098734c3145b76c5d2cd7115d9227b2eb523882b7317fbb09180498", "0xa0479a8da06d7a69c0b0fee60df4e691c19c551f5e7da286dab430bfbcabf31726508e20d26ea48c53365a7f00a3ad34", "0xa732dfc9baa0f4f40b5756d2e8d8937742999623477458e0bc81431a7b633eefc6f53b3b7939fe0a020018549c954054", "0x901502436a1169ba51dc479a5abe7c8d84e0943b16bc3c6a627b49b92cd46263c0005bc324c67509edd693f28e612af1", "0xb627aee83474e7f84d1bab9b7f6b605e33b26297ac6bbf52d110d38ba10749032bd551641e73a383a303882367af429b", "0x95108866745760baef4a46ef56f82da6de7e81c58b10126ebd2ba2cd13d339f91303bf2fb4dd104a6956aa3b13739503", "0x899ed2ade37236cec90056f3569bc50f984f2247792defafcceb49ad0ca5f6f8a2f06573705300e07f0de0c759289ff5", "0xa9f5eee196d608efe4bcef9bf71c646d27feb615e21252cf839a44a49fd89da8d26a758419e0085a05b1d59600e2dc42", "0xb36c6f68fed6e6c85f1f4a162485f24817f2843ec5cbee45a1ebfa367d44892e464949c6669f7972dc7167af08d55d25", "0xaaaede243a9a1b6162afbc8f571a52671a5a4519b4062e3f26777664e245ba873ed13b0492c5dbf0258c788c397a0e9e", "0x972b4fb39c31cbe127bf9a32a5cc10d621ebdd9411df5e5da3d457f03b2ab2cd1f6372d8284a4a9400f0b06ecdbfd38e", "0x8f6ca1e110e959a4b1d9a5ce5f212893cec21db40d64d5ac4d524f352d72198f923416a850bf845bc5a22a79c0ea2619", "0xa0f3c93b22134f66f04b2553a53b738644d1665ceb196b8494b315a4c28236fb492017e4a0de4224827c78e42f9908b7", "0x807fb5ee74f6c8735b0b5ca07e28506214fe4047dbeb00045d7c24f7849e98706aea79771241224939cb749cf1366c7d", "0x915eb1ff034224c0b645442cdb7d669303fdc00ca464f91aaf0b6fde0b220a3a74ff0cb043c26c9f3a5667b3fdaa9420", "0x8fda6cef56ed33fefffa9e6ac8e6f76b1af379f89761945c63dd448801f7bb8ca970504a7105fac2f74f652ccff32327", "0x87380cffdcffb1d0820fa36b63cc081e72187f86d487315177d4d04da4533eb19a0e2ff6115ceab528887819c44a5164", "0x8cd89e03411a18e7f16f968b89fb500c36d47d229f6487b99e62403a980058db5925ce249206743333538adfad168330", "0x974451b1df33522ce7056de9f03e10c70bf302c44b0741a59df3d6877d53d61a7394dcee1dd46e013d7cb9d73419c092", "0x98c35ddf645940260c490f384a49496a7352bb8e3f686feed815b1d38f59ded17b1ad6e84a209e773ed08f7b8ff1e4c2", "0x963f386cf944bb9b2ddebb97171b64253ea0a2894ac40049bdd86cda392292315f3a3d490ca5d9628c890cfb669f0acb", "0x8d507712152babd6d142ee682638da8495a6f3838136088df9424ef50d5ec28d815a198c9a4963610b22e49b4cdf95e9", "0x83d4bc6b0be87c8a4f1e9c53f257719de0c73d85b490a41f7420e777311640937320557ff2f1d9bafd1daaa54f932356", "0x82f5381c965b7a0718441131c4d13999f4cdce637698989a17ed97c8ea2e5bdb5d07719c5f7be8688edb081b23ede0f4", "0xa6ebecab0b72a49dfd01d69fa37a7f74d34fb1d4fef0aa10e3d6fceb9eccd671225c230af89f6eb514250e41a5f91f52", "0x846d185bdad6e11e604df7f753b7a08a28b643674221f0e750ebdb6b86ec584a29c869e131bca868972a507e61403f6a", "0x85a98332292acb744bd1c0fd6fdcf1f889a78a2c9624d79413ffa194cc8dfa7821a4b60cde8081d4b5f71f51168dd67f", "0x8f7d97c3b4597880d73200d074eb813d95432306e82dafc70b580b8e08cb8098b70f2d07b4b3ac6a4d77e92d57035031", "0x8185439c8751e595825d7053518cbe121f191846a38d4dbcb558c3f9d7a3104f3153401adaaaf27843bbe2edb504bfe3", "0xb3c00d8ece1518fca6b1215a139b0a0e26d9cba1b3a424f7ee59f30ce800a5db967279ed60958dd1f3ee69cf4dd1b204", "0xa2e6cb6978e883f9719c3c0d44cfe8de0cc6f644b98f98858433bea8bbe7b612c8aca5952fccce4f195f9d54f9722dc2", "0x99663087e3d5000abbec0fbda4e7342ec38846cc6a1505191fb3f1a337cb369455b7f8531a6eb8b0f7b2c4baf83cbe2b", "0xab0836c6377a4dbc7ca6a4d6cf021d4cd60013877314dd05f351706b128d4af6337711ed3443cb6ca976f40d74070a9a", "0x87abfd5126152fd3bac3c56230579b489436755ea89e0566aa349490b36a5d7b85028e9fb0710907042bcde6a6f5d7e3", "0x974ba1033f75f60e0cf7c718a57ae1da3721cf9d0fb925714c46f027632bdd84cd9e6de4cf4d00bc55465b1c5ebb7384", "0xa607b49d73689ac64f25cec71221d30d53e781e1100d19a2114a21da6507a60166166369d860bd314acb226596525670", "0xa7c2b0b915d7beba94954f2aa7dd08ec075813661e2a3ecca5d28a0733e59583247fed9528eb28aba55b972cdbaf06eb", "0xb8b3123e44128cc8efbe3270f2f94e50ca214a4294c71c3b851f8cbb70cb67fe9536cf07d04bf7fe380e5e3a29dd3c15", "0xa59a07e343b62ad6445a0859a32b58c21a593f9ddbfe52049650f59628c93715aa1f4e1f45b109321756d0eeec8a5429", "0x94f51f8a4ed18a6030d0aaa8899056744bd0e9dc9ac68f62b00355cddab11da5da16798db75f0bfbce0e5bdfe750c0b6", "0x97460a97ca1e1fa5ce243b81425edc0ec19b7448e93f0b55bc9785eedeeafe194a3c8b33a61a5c72990edf375f122777", "0x8fa859a089bc17d698a7ee381f37ce9beadf4e5b44fce5f6f29762bc04f96faff5d58c48c73631290325f05e9a1ecf49", "0xabdf38f3b20fc95eff31de5aa9ef1031abfa48f1305ee57e4d507594570401503476d3bcc493838fc24d6967a3082c7f", "0xb8914bfb82815abb86da35c64d39ab838581bc0bf08967192697d9663877825f2b9d6fbdcf9b410463482b3731361aef", "0xa8187f9d22b193a5f578999954d6ec9aa9b32338ccadb8a3e1ce5bad5ea361d69016e1cdfac44e9d6c54e49dd88561b9", "0xaac262cb7cba7fd62c14daa7b39677cabc1ef0947dd06dd89cac8570006a200f90d5f0353e84f5ff03179e3bebe14231", "0xa630ef5ece9733b8c46c0a2df14a0f37647a85e69c63148e79ffdcc145707053f9f9d305c3f1cf3c7915cb46d33abd07", "0xb102c237cb2e254588b6d53350dfda6901bd99493a3fbddb4121d45e0b475cf2663a40d7b9a75325eda83e4ba1e68cb3", "0x86a930dd1ddcc16d1dfa00aa292cb6c2607d42c367e470aa920964b7c17ab6232a7108d1c2c11fc40fb7496547d0bbf8", "0xa832fdc4500683e72a96cce61e62ac9ee812c37fe03527ad4cf893915ca1962cee80e72d4f82b20c8fc0b764376635a1", "0x88ad985f448dabb04f8808efd90f273f11f5e6d0468b5489a1a6a3d77de342992a73eb842d419034968d733f101ff683", "0x98a8538145f0d86f7fbf9a81c9140f6095c5bdd8960b1c6f3a1716428cd9cca1bf8322e6d0af24e6169abcf7df2b0ff6", "0x9048c6eba5e062519011e177e955a200b2c00b3a0b8615bdecdebc217559d41058d3315f6d05617be531ef0f6aef0e51", "0x833bf225ab6fc68cdcacf1ec1b50f9d05f5410e6cdcd8d56a3081dc2be8a8d07b81534d1ec93a25c2e270313dfb99e3b", "0xa84bcd24c3da5e537e64a811b93c91bfc84d7729b9ead7f79078989a6eb76717d620c1fad17466a0519208651e92f5ff", "0xb7cdd0a3fbd79aed93e1b5a44ca44a94e7af5ed911e4492f332e3a5ed146c7286bde01b52276a2fcc02780d2109874dd", "0x8a19a09854e627cb95750d83c20c67442b66b35896a476358f993ba9ac114d32c59c1b3d0b8787ee3224cf3888b56c64", "0xa9abd5afb8659ee52ada8fa5d57e7dd355f0a7350276f6160bec5fbf70d5f99234dd179eb221c913e22a49ec6d267846", "0x8c13c4274c0d30d184e73eaf812200094bbbd57293780bdadbceb262e34dee5b453991e7f37c7333a654fc71c69d6445", "0xa4320d73296ff8176ce0127ca1921c450e2a9c06eff936681ebaffb5a0b05b17fded24e548454de89aca2dcf6d7a9de4", "0xb2b8b3e15c1f645f07783e5628aba614e60157889db41d8161d977606788842b67f83f361eae91815dc0abd84e09abd5", "0xad26c3aa35ddfddc15719b8bb6c264aaec7065e88ac29ba820eb61f220fef451609a7bb037f3722d022e6c86e4f1dc88", "0xb8615bf43e13ae5d7b8dd903ce37190800cd490f441c09b22aa29d7a29ed2c0417b7a08ead417868f1de2589deaadd80", "0x8d3425e1482cd1e76750a76239d33c06b3554c3c3c87c15cb7ab58b1cee86a4c5c4178b44e23f36928365a1b484bde02", "0x806893a62e38c941a7dd6f249c83af16596f69877cc737d8f73f6b8cd93cbc01177a7a276b2b8c6b0e5f2ad864db5994", "0x86618f17fa4b0d65496b661bbb5ba3bc3a87129d30a4b7d4f515b904f4206ca5253a41f49fd52095861e5e065ec54f21", "0x9551915da1304051e55717f4c31db761dcdcf3a1366c89a4af800a9e99aca93a357bf928307f098e62b44a02cb689a46", "0x8f79c4ec0ec1146cb2a523b52fe33def90d7b5652a0cb9c2d1c8808a32293e00aec6969f5b1538e3a94cd1efa3937f86", "0xa0c03e329a707300081780f1e310671315b4c6a4cedcb29697aedfabb07a9d5df83f27b20e9c44cf6b16e39d9ded5b98", "0x86a7cfa7c8e7ce2c01dd0baec2139e97e8e090ad4e7b5f51518f83d564765003c65968f85481bbb97cb18f005ccc7d9f", "0xa33811770c6dfda3f7f74e6ad0107a187fe622d61b444bbd84fd7ef6e03302e693b093df76f6ab39bb4e02afd84a575a", "0x85480f5c10d4162a8e6702b5e04f801874d572a62a130be94b0c02b58c3c59bdcd48cd05f0a1c2839f88f06b6e3cd337", "0x8e181011564b17f7d787fe0e7f3c87f6b62da9083c54c74fd6c357a1f464c123c1d3d8ade3cf72475000b464b14e2be3", "0x8ee178937294b8c991337e0621ab37e9ffa4ca2bdb3284065c5e9c08aad6785d50cf156270ff9daf9a9127289710f55b", "0x8bd1e8e2d37379d4b172f1aec96f2e41a6e1393158d7a3dbd9a95c8dd4f8e0b05336a42efc11a732e5f22b47fc5c271d", "0x8f3da353cd487c13136a85677de8cedf306faae0edec733cf4f0046f82fa4639db4745b0095ff33a9766aba50de0cbcf", "0x8d187c1e97638df0e4792b78e8c23967dac43d98ea268ca4aabea4e0fa06cb93183fd92d4c9df74118d7cc27bf54415e", "0xa4c992f08c2f8bac0b74b3702fb0c75c9838d2ce90b28812019553d47613c14d8ce514d15443159d700b218c5a312c49", "0xa6fd1874034a34c3ea962a316c018d9493d2b3719bb0ec4edbc7c56b240802b2228ab49bee6f04c8a3e9f6f24a48c1c2", "0xb2efed8e799f8a15999020900dc2c58ece5a3641c90811b86a5198e593d7318b9d53b167818ccdfbe7df2414c9c34011", "0x995ff7de6181ddf95e3ead746089c6148da3508e4e7a2323c81785718b754d356789b902e7e78e2edc6b0cbd4ff22c78", "0x944073d24750a9068cbd020b834afc72d2dde87efac04482b3287b40678ad07588519a4176b10f2172a2c463d063a5cd", "0x99db4b1bb76475a6fd75289986ef40367960279524378cc917525fb6ba02a145a218c1e9caeb99332332ab486a125ac0", "0x89fce4ecd420f8e477af4353b16faabb39e063f3f3c98fde2858b1f2d1ef6eed46f0975a7c08f233b97899bf60ccd60a", "0x8c09a4f07a02b80654798bc63aada39fd638d3e3c4236ccd8a5ca280350c31e4a89e5f4c9aafb34116e71da18c1226b8", "0x85325cfa7ded346cc51a2894257eab56e7488dbff504f10f99f4cd2b630d913003761a50f175ed167e8073f1b6b63fb0", "0xb678b4fbec09a8cc794dcbca185f133578f29e354e99c05f6d07ac323be20aecb11f781d12898168e86f2e0f09aca15e", "0xa249cfcbca4d9ba0a13b5f6aac72bf9b899adf582f9746bb2ad043742b28915607467eb794fca3704278f9136f7642be", "0x9438e036c836a990c5e17af3d78367a75b23c37f807228362b4d13e3ddcb9e431348a7b552d09d11a2e9680704a4514f", "0x925ab70450af28c21a488bfb5d38ac994f784cf249d7fd9ad251bb7fd897a23e23d2528308c03415074d43330dc37ef4", "0xa290563904d5a8c0058fc8330120365bdd2ba1fdbaef7a14bc65d4961bb4217acfaed11ab82669e359531f8bf589b8db", "0xa7e07a7801b871fc9b981a71e195a3b4ba6b6313bc132b04796a125157e78fe5c11a3a46cf731a255ac2d78a4ae78cd0", "0xb26cd2501ee72718b0eebab6fb24d955a71f363f36e0f6dff0ab1d2d7836dab88474c0cef43a2cc32701fca7e82f7df3", "0xa1dc3b6c968f3de00f11275092290afab65b2200afbcfa8ddc70e751fa19dbbc300445d6d479a81bda3880729007e496", "0xa9bc213e28b630889476a095947d323b9ac6461dea726f2dc9084473ae8e196d66fb792a21905ad4ec52a6d757863e7d", "0xb25d178df8c2df8051e7c888e9fa677fde5922e602a95e966db9e4a3d6b23ce043d7dc48a5b375c6b7c78e966893e8c3", "0xa1c8d88d72303692eaa7adf68ea41de4febec40cc14ae551bb4012afd786d7b6444a3196b5d9d5040655a3366d96b7cd", "0xb22bd44f9235a47118a9bbe2ba5a2ba9ec62476061be2e8e57806c1a17a02f9a51403e849e2e589520b759abd0117683", "0xb8add766050c0d69fe81d8d9ea73e1ed05f0135d093ff01debd7247e42dbb86ad950aceb3b50b9af6cdc14ab443b238f", "0xaf2cf95f30ef478f018cf81d70d47d742120b09193d8bb77f0d41a5d2e1a80bfb467793d9e2471b4e0ad0cb2c3b42271", "0x8af5ef2107ad284e246bb56e20fef2a255954f72de791cbdfd3be09f825298d8466064f3c98a50496c7277af32b5c0bc", "0x85dc19558572844c2849e729395a0c125096476388bd1b14fa7f54a7c38008fc93e578da3aac6a52ff1504d6ca82db05", "0xae8c9b43c49572e2e166d704caf5b4b621a3b47827bb2a3bcd71cdc599bba90396fd9a405261b13e831bb5d44c0827d7", "0xa7ba7efede25f02e88f6f4cbf70643e76784a03d97e0fbd5d9437c2485283ad7ca3abb638a5f826cd9f6193e5dec0b6c", "0x94a9d122f2f06ef709fd8016fd4b712d88052245a65a301f5f177ce22992f74ad05552b1f1af4e70d1eac62cef309752", "0x82d999b3e7cf563833b8bc028ff63a6b26eb357dfdb3fd5f10e33a1f80a9b2cfa7814d871b32a7ebfbaa09e753e37c02", "0xaec6edcde234df502a3268dd2c26f4a36a2e0db730afa83173f9c78fcb2b2f75510a02b80194327b792811caefda2725", "0x94c0bfa66c9f91d462e9194144fdd12d96f9bbe745737e73bab8130607ee6ea9d740e2cfcbbd00a195746edb6369ee61", "0xab7573dab8c9d46d339e3f491cb2826cabe8b49f85f1ede78d845fc3995537d1b4ab85140b7d0238d9c24daf0e5e2a7e", "0x87e8b16832843251fe952dadfd01d41890ed4bb4b8fa0254550d92c8cced44368225eca83a6c3ad47a7f81ff8a80c984", "0x9189d2d9a7c64791b19c0773ad4f0564ce6bea94aa275a917f78ad987f150fdb3e5e26e7fef9982ac184897ecc04683f", "0xb3661bf19e2da41415396ae4dd051a9272e8a2580b06f1a1118f57b901fa237616a9f8075af1129af4eabfefedbe2f1c", "0xaf43c86661fb15daf5d910a4e06837225e100fb5680bd3e4b10f79a2144c6ec48b1f8d6e6b98e067d36609a5d038889a", "0x82ac0c7acaa83ddc86c5b4249aae12f28155989c7c6b91e5137a4ce05113c6cbc16f6c44948b0efd8665362d3162f16a", "0x8f268d1195ab465beeeb112cd7ffd5d5548559a8bc01261106d3555533fc1971081b25558d884d552df0db1cddda89d8", "0x8ef7caa5521f3e037586ce8ac872a4182ee20c7921c0065ed9986c047e3dda08294da1165f385d008b40d500f07d895f", "0x8c2f98f6880550573fad46075d3eba26634b5b025ce25a0b4d6e0193352c8a1f0661064027a70fe8190b522405f9f4e3", "0xb7653f353564feb164f0f89ec7949da475b8dad4a4d396d252fc2a884f6932d027b7eb2dc4d280702c74569319ed701a", "0xa026904f4066333befd9b87a8fad791d014096af60cdd668ef919c24dbe295ff31f7a790e1e721ba40cf5105abca67f4", "0x988f982004ada07a22dd345f2412a228d7a96b9cae2c487de42e392afe1e35c2655f829ce07a14629148ce7079a1f142", "0x9616add009067ed135295fb74d5b223b006b312bf14663e547a0d306694ff3a8a7bb9cfc466986707192a26c0bce599f", "0xad4c425de9855f6968a17ee9ae5b15e0a5b596411388cf976df62ecc6c847a6e2ddb2cea792a5f6e9113c2445dba3e5c", "0xb698ac9d86afa3dc69ff8375061f88e3b0cff92ff6dfe747cebaf142e813c011851e7a2830c10993b715e7fd594604a9", "0xa386fa189847bb3b798efca917461e38ead61a08b101948def0f82cd258b945ed4d45b53774b400af500670149e601b7", "0x905c95abda2c68a6559d8a39b6db081c68cef1e1b4be63498004e1b2f408409be9350b5b5d86a30fd443e2b3e445640a", "0x9116dade969e7ce8954afcdd43e5cab64dc15f6c1b8da9d2d69de3f02ba79e6c4f6c7f54d6bf586d30256ae405cd1e41", "0xa3084d173eacd08c9b5084a196719b57e47a0179826fda73466758235d7ecdb87cbcf097bd6b510517d163a85a7c7edd", "0x85bb00415ad3c9be99ff9ba83672cc59fdd24356b661ab93713a3c8eab34e125d8867f628a3c3891b8dc056e69cd0e83", "0x8d58541f9f39ed2ee4478acce5d58d124031338ec11b0d55551f00a5a9a6351faa903a5d7c132dc5e4bb026e9cbd18e4", "0xa622adf72dc250e54f672e14e128c700166168dbe0474cecb340da175346e89917c400677b1bc1c11fcc4cc26591d9db", "0xb3f865014754b688ca8372e8448114fff87bf3ca99856ab9168894d0c4679782c1ced703f5b74e851b370630f5e6ee86", "0xa7e490b2c40c2446fcd91861c020da9742c326a81180e38110558bb5d9f2341f1c1885e79b364e6419023d1cbdc47380", "0xb3748d472b1062e54572badbb8e87ac36534407f74932e7fc5b8392d008e8e89758f1671d1e4d30ab0fa40551b13bb5e", "0x89898a5c5ec4313aabc607b0049fd1ebad0e0c074920cf503c9275b564d91916c2c446d3096491c950b7af3ac5e4b0ed", "0x8eb8c83fef2c9dd30ea44e286e9599ec5c20aba983f702e5438afe2e5b921884327ad8d1566c72395587efac79ca7d56", "0xb92479599e806516ce21fb0bd422a1d1d925335ebe2b4a0a7e044dd275f30985a72b97292477053ac5f00e081430da80", "0xa34ae450a324fe8a3c25a4d653a654f9580ed56bbea213b8096987bbad0f5701d809a17076435e18017fea4d69f414bc", "0x81381afe6433d62faf62ea488f39675e0091835892ecc238e02acf1662669c6d3962a71a3db652f6fe3bc5f42a0e5dc5", "0xa430d475bf8580c59111103316fe1aa79c523ea12f1d47a976bbfae76894717c20220e31cf259f08e84a693da6688d70", "0xb842814c359754ece614deb7d184d679d05d16f18a14b288a401cef5dad2cf0d5ee90bad487b80923fc5573779d4e4e8", "0x971d9a2627ff2a6d0dcf2af3d895dfbafca28b1c09610c466e4e2bff2746f8369de7f40d65b70aed135fe1d72564aa88", "0x8f4ce1c59e22b1ce7a0664caaa7e53735b154cfba8d2c5cc4159f2385843de82ab58ed901be876c6f7fce69cb4130950", "0x86cc9dc321b6264297987000d344fa297ef45bcc2a4df04e458fe2d907ad304c0ea2318e32c3179af639a9a56f3263cf", "0x8229e0876dfe8f665c3fb19b250bd89d40f039bbf1b331468b403655be7be2e104c2fd07b9983580c742d5462ca39a43", "0x99299d73066e8eb128f698e56a9f8506dfe4bd014931e86b6b487d6195d2198c6c5bf15cccb40ccf1f8ddb57e9da44a2", "0xa3a3be37ac554c574b393b2f33d0a32a116c1a7cfeaf88c54299a4da2267149a5ecca71f94e6c0ef6e2f472b802f5189", "0xa91700d1a00387502cdba98c90f75fbc4066fefe7cc221c8f0e660994c936badd7d2695893fde2260c8c11d5bdcdd951", "0x8e03cae725b7f9562c5c5ab6361644b976a68bada3d7ca508abca8dfc80a469975689af1fba1abcf21bc2a190dab397d", "0xb01461ad23b2a8fa8a6d241e1675855d23bc977dbf4714add8c4b4b7469ccf2375cec20e80cedfe49361d1a30414ac5b", "0xa2673bf9bc621e3892c3d7dd4f1a9497f369add8cbaa3472409f4f86bd21ac67cfac357604828adfee6ada1835365029", "0xa042dff4bf0dfc33c178ba1b335e798e6308915128de91b12e5dbbab7c4ac8d60a01f6aea028c3a6d87b9b01e4e74c01", "0x86339e8a75293e4b3ae66b5630d375736b6e6b6b05c5cda5e73fbf7b2f2bd34c18a1d6cefede08625ce3046e77905cb8", "0xaf2ebe1b7d073d03e3d98bc61af83bf26f7a8c130fd607aa92b75db22d14d016481b8aa231e2c9757695f55b7224a27f", "0xa00ee882c9685e978041fd74a2c465f06e2a42ffd3db659053519925be5b454d6f401e3c12c746e49d910e4c5c9c5e8c", "0x978a781c0e4e264e0dad57e438f1097d447d891a1e2aa0d5928f79a9d5c3faae6f258bc94fdc530b7b2fa6a9932bb193", "0xaa4b7ce2e0c2c9e9655bf21e3e5651c8503bce27483017b0bf476be743ba06db10228b3a4c721219c0779747f11ca282", "0xb003d1c459dacbcf1a715551311e45d7dbca83a185a65748ac74d1800bbeaba37765d9f5a1a221805c571910b34ebca8", "0x95b6e531b38648049f0d19de09b881baa1f7ea3b2130816b006ad5703901a05da57467d1a3d9d2e7c73fb3f2e409363c", "0xa6cf9c06593432d8eba23a4f131bb7f72b9bd51ab6b4b772a749fe03ed72b5ced835a349c6d9920dba2a39669cb7c684", "0xaa3d59f6e2e96fbb66195bc58c8704e139fa76cd15e4d61035470bd6e305db9f98bcbf61ac1b95e95b69ba330454c1b3", "0xb57f97959c208361de6d7e86dff2b873068adb0f158066e646f42ae90e650079798f165b5cd713141cd3a2a90a961d9a", "0xa76ee8ed9052f6a7a8c69774bb2597be182942f08115baba03bf8faaeaee526feba86120039fe8ca7b9354c3b6e0a8e6", "0x95689d78c867724823f564627d22d25010f278674c6d2d0cdb10329169a47580818995d1d727ce46c38a1e47943ebb89", "0xab676d2256c6288a88e044b3d9ffd43eb9d5aaee00e8fc60ac921395fb835044c71a26ca948e557fed770f52d711e057", "0x96351c72785c32e5d004b6f4a1259fb8153d631f0c93fed172f18e8ba438fbc5585c1618deeabd0d6d0b82173c2e6170", "0x93dd8d3db576418e22536eba45ab7f56967c6c97c64260d6cddf38fb19c88f2ec5cd0e0156f50e70855eee8a2b879ffd", "0xad6ff16f40f6de3d7a737f8e6cebd8416920c4ff89dbdcd75eabab414af9a6087f83ceb9aff7680aa86bff98bd09c8cc", "0x84de53b11671abc9c38710e19540c5c403817562aeb22a88404cdaff792c1180f717dbdfe8f54940c062c4d032897429", "0x872231b9efa1cdd447b312099a5c164c560440a9441d904e70f5abfc3b2a0d16be9a01aca5e0a2599a61e19407587e3d", "0x88f44ac27094a2aa14e9dc40b099ee6d68f97385950f303969d889ee93d4635e34dff9239103bdf66a4b7cbba3e7eb7a", "0xa59afebadf0260e832f6f44468443562f53fbaf7bcb5e46e1462d3f328ac437ce56edbca617659ac9883f9e13261fad7", "0xb1990e42743a88de4deeacfd55fafeab3bc380cb95de43ed623d021a4f2353530bcab9594389c1844b1c5ea6634c4555", "0x85051e841149a10e83f56764e042182208591396d0ce78c762c4a413e6836906df67f38c69793e158d64fef111407ba3", "0x9778172bbd9b1f2ec6bbdd61829d7b39a7df494a818e31c654bf7f6a30139899c4822c1bf418dd4f923243067759ce63", "0x9355005b4878c87804fc966e7d24f3e4b02bed35b4a77369d01f25a3dcbff7621b08306b1ac85b76fe7b4a3eb5f839b1", "0x8f9dc6a54fac052e236f8f0e1f571ac4b5308a43acbe4cc8183bce26262ddaf7994e41cf3034a4cbeca2c505a151e3b1", "0x8cc59c17307111723fe313046a09e0e32ea0cce62c13814ab7c6408c142d6a0311d801be4af53fc9240523f12045f9ef", "0x8e6057975ed40a1932e47dd3ac778f72ee2a868d8540271301b1aa6858de1a5450f596466494a3e0488be4fbeb41c840", "0x812145efbd6559ae13325d56a15940ca4253b17e72a9728986b563bb5acc13ec86453796506ac1a8f12bd6f9e4a288c3", "0x911da0a6d6489eb3dab2ec4a16e36127e8a291ae68a6c2c9de33e97f3a9b1f00da57a94e270a0de79ecc5ecb45d19e83", "0xb72ea85973f4b2a7e6e71962b0502024e979a73c18a9111130e158541fa47bbaaf53940c8f846913a517dc69982ba9e1", "0xa7a56ad1dbdc55f177a7ad1d0af78447dc2673291e34e8ab74b26e2e2e7d8c5fe5dc89e7ef60f04a9508847b5b3a8188", "0xb52503f6e5411db5d1e70f5fb72ccd6463fa0f197b3e51ca79c7b5a8ab2e894f0030476ada72534fa4eb4e06c3880f90", "0xb51c7957a3d18c4e38f6358f2237b3904618d58b1de5dec53387d25a63772e675a5b714ad35a38185409931157d4b529", "0xb86b4266e719d29c043d7ec091547aa6f65bbf2d8d831d1515957c5c06513b72aa82113e9645ad38a7bc3f5383504fa6", "0xb95b547357e6601667b0f5f61f261800a44c2879cf94e879def6a105b1ad2bbf1795c3b98a90d588388e81789bd02681", "0xa58fd4c5ae4673fa350da6777e13313d5d37ed1dafeeb8f4f171549765b84c895875d9d3ae6a9741f3d51006ef81d962", "0x9398dc348d078a604aadc154e6eef2c0be1a93bb93ba7fe8976edc2840a3a318941338cc4d5f743310e539d9b46613d2", "0x902c9f0095014c4a2f0dccaaab543debba6f4cc82c345a10aaf4e72511725dbed7a34cd393a5f4e48a3e5142b7be84ed", "0xa7c0447849bb44d04a0393a680f6cd390093484a79a147dd238f5d878030d1c26646d88211108e59fe08b58ad20c6fbd", "0x80db045535d6e67a422519f5c89699e37098449d249698a7cc173a26ccd06f60238ae6cc7242eb780a340705c906790c", "0x8e52b451a299f30124505de2e74d5341e1b5597bdd13301cc39b05536c96e4380e7f1b5c7ef076f5b3005a868657f17c", "0x824499e89701036037571761e977654d2760b8ce21f184f2879fda55d3cda1e7a95306b8abacf1caa79d3cc075b9d27f", "0x9049b956b77f8453d2070607610b79db795588c0cec12943a0f5fe76f358dea81e4f57a4692112afda0e2c05c142b26f", "0x81911647d818a4b5f4990bfd4bc13bf7be7b0059afcf1b6839333e8569cdb0172fd2945410d88879349f677abaed5eb3", "0xad4048f19b8194ed45b6317d9492b71a89a66928353072659f5ce6c816d8f21e69b9d1817d793effe49ca1874daa1096", "0x8d22f7b2ddb31458661abd34b65819a374a1f68c01fc6c9887edeba8b80c65bceadb8f57a3eb686374004b836261ef67", "0x92637280c259bc6842884db3d6e32602a62252811ae9b019b3c1df664e8809ffe86db88cfdeb8af9f46435c9ee790267", "0xa2f416379e52e3f5edc21641ea73dc76c99f7e29ea75b487e18bd233856f4c0183429f378d2bfc6cd736d29d6cadfa49", "0x882cb6b76dbdc188615dcf1a8439eba05ffca637dd25197508156e03c930b17b9fed2938506fdd7b77567cb488f96222", "0xb68b621bb198a763fb0634eddb93ed4b5156e59b96c88ca2246fd1aea3e6b77ed651e112ac41b30cd361fadc011d385e", "0xa3cb22f6b675a29b2d1f827cacd30df14d463c93c3502ef965166f20d046af7f9ab7b2586a9c64f4eae4fad2d808a164", "0x8302d9ce4403f48ca217079762ce42cee8bc30168686bb8d3a945fbd5acd53b39f028dce757b825eb63af2d5ae41169d", "0xb2eef1fbd1a176f1f4cd10f2988c7329abe4eb16c7405099fb92baa724ab397bc98734ef7d4b24c0f53dd90f57520d04", "0xa1bbef0bd684a3f0364a66bde9b29326bac7aa3dde4caed67f14fb84fed3de45c55e406702f1495a3e2864d4ee975030", "0x976acdb0efb73e3a3b65633197692dedc2adaed674291ae3df76b827fc866d214e9cac9ca46baefc4405ff13f953d936", "0xb9fbf71cc7b6690f601f0b1c74a19b7d14254183a2daaafec7dc3830cba5ae173d854bbfebeca985d1d908abe5ef0cda", "0x90591d7b483598c94e38969c4dbb92710a1a894bcf147807f1bcbd8aa3ac210b9f2be65519aa829f8e1ccdc83ad9b8cf", "0xa30568577c91866b9c40f0719d46b7b3b2e0b4a95e56196ac80898a2d89cc67880e1229933f2cd28ee3286f8d03414d7", "0x97589a88c3850556b359ec5e891f0937f922a751ac7c95949d3bbc7058c172c387611c0f4cb06351ef02e5178b3dd9e4", "0x98e7bbe27a1711f4545df742f17e3233fbcc63659d7419e1ca633f104cb02a32c84f2fac23ca2b84145c2672f68077ab", "0xa7ddb91636e4506d8b7e92aa9f4720491bb71a72dadc47c7f4410e15f93e43d07d2b371951a0e6a18d1bd087aa96a5c4", "0xa7c006692227a06db40bceac3d5b1daae60b5692dd9b54772bedb5fea0bcc91cbcdb530cac31900ffc70c5b3ffadc969", "0x8d3ec6032778420dfa8be52066ba0e623467df33e4e1901dbadd586c5d750f4ccde499b5197e26b9ea43931214060f69", "0x8d9a8410518ea64f89df319bfd1fc97a0971cdb9ad9b11d1f8fe834042ea7f8dce4db56eeaf179ff8dda93b6db93e5ce", "0xa3c533e9b3aa04df20b9ff635cb1154ce303e045278fcf3f10f609064a5445552a1f93989c52ce852fd0bbd6e2b6c22e", "0x81934f3a7f8c1ae60ec6e4f212986bcc316118c760a74155d06ce0a8c00a9b9669ec4e143ca214e1b995e41271774fd9", "0xab8e2d01a71192093ef8fafa7485e795567cc9db95a93fb7cc4cf63a391ef89af5e2bfad4b827fffe02b89271300407f", "0x83064a1eaa937a84e392226f1a60b7cfad4efaa802f66de5df7498962f7b2649924f63cd9962d47906380b97b9fe80e1", "0xb4f5e64a15c6672e4b55417ee5dc292dcf93d7ea99965a888b1cc4f5474a11e5b6520eacbcf066840b343f4ceeb6bf33", "0xa63d278b842456ef15c278b37a6ea0f27c7b3ffffefca77c7a66d2ea06c33c4631eb242bbb064d730e70a8262a7b848a", "0x83a41a83dbcdf0d22dc049de082296204e848c453c5ab1ba75aa4067984e053acf6f8b6909a2e1f0009ed051a828a73b", "0x819485b036b7958508f15f3c19436da069cbe635b0318ebe8c014cf1ef9ab2df038c81161b7027475bcfa6fff8dd9faf", "0xaa40e38172806e1e045e167f3d1677ef12d5dcdc89b43639a170f68054bd196c4fae34c675c1644d198907a03f76ba57", "0x969bae484883a9ed1fbed53b26b3d4ee4b0e39a6c93ece5b3a49daa01444a1c25727dabe62518546f36b047b311b177c", "0x80a9e73a65da99664988b238096a090d313a0ee8e4235bc102fa79bb337b51bb08c4507814eb5baec22103ec512eaab0", "0x86604379aec5bddda6cbe3ef99c0ac3a3c285b0b1a15b50451c7242cd42ae6b6c8acb717dcca7917838432df93a28502", "0xa23407ee02a495bed06aa7e15f94cfb05c83e6d6fba64456a9bbabfa76b2b68c5c47de00ba169e710681f6a29bb41a22", "0x98cff5ecc73b366c6a01b34ac9066cb34f7eeaf4f38a5429bad2d07e84a237047e2a065c7e8a0a6581017dadb4695deb", "0x8de9f68a938f441f3b7ab84bb1f473c5f9e5c9e139e42b7ccee1d254bd57d0e99c2ccda0f3198f1fc5737f6023dd204e", "0xb0ce48d815c2768fb472a315cad86aa033d0e9ca506f146656e2941829e0acb735590b4fbc713c2d18d3676db0a954ac", "0x82f485cdefd5642a6af58ac6817991c49fac9c10ace60f90b27f1788cc026c2fe8afc83cf499b3444118f9f0103598a8", "0x82c24550ed512a0d53fc56f64cc36b553823ae8766d75d772dacf038c460f16f108f87a39ceef7c66389790f799dbab3", "0x859ffcf1fe9166388316149b9acc35694c0ea534d43f09dae9b86f4aa00a23b27144dda6a352e74b9516e8c8d6fc809c", "0xb8f7f353eec45da77fb27742405e5ad08d95ec0f5b6842025be9def3d9892f85eb5dd0921b41e6eff373618dba215bca", "0x8ccca4436f9017e426229290f5cd05eac3f16571a4713141a7461acfe8ae99cd5a95bf5b6df129148693c533966145da", "0xa2c67ecc19c0178b2994846fea4c34c327a5d786ac4b09d1d13549d5be5996d8a89021d63d65cb814923388f47cc3a03", "0xaa0ff87d676b418ec08f5cbf577ac7e744d1d0e9ebd14615b550eb86931eafd2a36d4732cc5d6fab1713fd7ab2f6f7c0", "0x8aef4730bb65e44efd6bb9441c0ae897363a2f3054867590a2c2ecf4f0224e578c7a67f10b40f8453d9f492ac15a9b2d", "0x86a187e13d8fba5addcfdd5b0410cedd352016c930f913addd769ee09faa6be5ca3e4b1bdb417a965c643a99bd92be42", "0xa0a4e9632a7a094b14b29b78cd9c894218cdf6783e61671e0203865dc2a835350f465fbaf86168f28af7c478ca17bc89", "0xa8c7b02d8deff2cd657d8447689a9c5e2cd74ef57c1314ac4d69084ac24a7471954d9ff43fe0907d875dcb65fd0d3ce5", "0x97ded38760aa7be6b6960b5b50e83b618fe413cbf2bcc1da64c05140bcc32f5e0e709cd05bf8007949953fac5716bad9", "0xb0d293835a24d64c2ae48ce26e550b71a8c94a0883103757fb6b07e30747f1a871707d23389ba2b2065fa6bafe220095", "0x8f9e291bf849feaa575592e28e3c8d4b7283f733d41827262367ea1c40f298c7bcc16505255a906b62bf15d9f1ba85fb", "0x998f4e2d12708b4fd85a61597ca2eddd750f73c9e0c9b3cf0825d8f8e01f1628fd19797dcaed3b16dc50331fc6b8b821", "0xb30d1f8c115d0e63bf48f595dd10908416774c78b3bbb3194192995154d80ea042d2e94d858de5f8aa0261b093c401fd", "0xb5d9c75bb41f964cbff3f00e96d9f1480c91df8913f139f0d385d27a19f57a820f838eb728e46823cbff00e21c660996", "0xa6edec90b5d25350e2f5f0518777634f9e661ec9d30674cf5b156c4801746d62517751d90074830ac0f4b09911c262f1", "0x82f98da1264b6b75b8fbeb6a4d96d6a05b25c24db0d57ba3a38efe3a82d0d4e331b9fc4237d6494ccfe4727206457519", "0xb89511843453cf4ecd24669572d6371b1e529c8e284300c43e0d5bb6b3aaf35aeb634b3cb5c0a2868f0d5e959c1d0772", "0xa82bf065676583e5c1d3b81987aaae5542f522ba39538263a944bb33ea5b514c649344a96c0205a3b197a3f930fcda6c", "0xa37b47ea527b7e06c460776aa662d9a49ff4149d3993f1a974b0dd165f7171770d189b0e2ea54fd5fccb6a14b116e68a", "0xa1017677f97dda818274d47556d09d0e4ccacb23a252f82a6cfe78c630ad46fb9806307445a59fb61262182de3a2b29c", "0xb01e9fcac239ba270e6877b79273ddd768bf8a51d2ed8a051b1c11e18eff3de5920e2fcbfbd26f06d381eddd3b1f1e1b", "0x82fcd53d803b1c8e4ed76adc339b7f3a5962d37042b9683aabac7513ac68775d4a566a9460183926a6a95dbe7d551a1f", "0xa763e78995d55cd21cdb7ef75d9642d6e1c72453945e346ab6690c20a4e1eeec61bb848ef830ae4b56182535e3c71d8f", "0xb769f4db602251d4b0a1186782799bdcef66de33c110999a5775c50b349666ffd83d4c89714c4e376f2efe021a5cfdb2", "0xa59cbd1b785efcfa6e83fc3b1d8cf638820bc0c119726b5368f3fba9dce8e3414204fb1f1a88f6c1ff52e87961252f97", "0x95c8c458fd01aa23ecf120481a9c6332ebec2e8bb70a308d0576926a858457021c277958cf79017ddd86a56cacc2d7db", "0x82eb41390800287ae56e77f2e87709de5b871c8bdb67c10a80fc65f3acb9f7c29e8fa43047436e8933f27449ea61d94d", "0xb3ec25e3545eb83aed2a1f3558d1a31c7edde4be145ecc13b33802654b77dc049b4f0065069dd9047b051e52ab11dcdd", "0xb78a0c715738f56f0dc459ab99e252e3b579b208142836b3c416b704ca1de640ca082f29ebbcee648c8c127df06f6b1e", "0xa4083149432eaaf9520188ebf4607d09cf664acd1f471d4fb654476e77a9eaae2251424ffda78d09b6cb880df35c1219", "0x8c52857d68d6e9672df3db2df2dbf46b516a21a0e8a18eec09a6ae13c1ef8f369d03233320dd1c2c0bbe00abfc1ea18b", "0x8c856089488803066bff3f8d8e09afb9baf20cecc33c8823c1c0836c3d45498c3de37e87c016b705207f60d2b00f8609", "0x831a3df39be959047b2aead06b4dcd3012d7b29417f642b83c9e8ce8de24a3dbbd29c6fdf55e2db3f7ea04636c94e403", "0xaed84d009f66544addabe404bf6d65af7779ce140dc561ff0c86a4078557b96b2053b7b8a43432ffb18cd814f143b9da", "0x93282e4d72b0aa85212a77b336007d8ba071eea17492da19860f1ad16c1ea8867ccc27ef5c37c74b052465cc11ea4f52", "0xa7b78b8c8d057194e8d68767f1488363f77c77bddd56c3da2bc70b6354c7aa76247c86d51f7371aa38a4aa7f7e3c0bb7", "0xb1c77283d01dcd1bde649b5b044eac26befc98ff57cbee379fb5b8e420134a88f2fc7f0bf04d15e1fbd45d29e7590fe6", "0xa4aa8de70330a73b2c6458f20a1067eed4b3474829b36970a8df125d53bbdda4f4a2c60063b7cccb0c80fc155527652f", "0x948a6c79ba1b8ad7e0bed2fae2f0481c4e41b4d9bbdd9b58164e28e9065700e83f210c8d5351d0212e0b0b68b345b3a5", "0x86a48c31dcbbf7b082c92d28e1f613a2378a910677d7db3a349dc089e4a1e24b12eee8e8206777a3a8c64748840b7387", "0x976adb1af21e0fc34148917cf43d933d7bfd3fd12ed6c37039dcd5a4520e3c6cf5868539ba5bf082326430deb8a4458d", "0xb93e1a4476f2c51864bb4037e7145f0635eb2827ab91732b98d49b6c07f6ac443111aa1f1da76d1888665cb897c3834e", "0x8afd46fb23bf869999fa19784b18a432a1f252d09506b8dbb756af900518d3f5f244989b3d7c823d9029218c655d3dc6", "0x83f1e59e3abeed18cdc632921672673f1cb6e330326e11c4e600e13e0d5bc11bdc970ae12952e15103a706fe720bf4d6", "0x90ce4cc660714b0b673d48010641c09c00fc92a2c596208f65c46073d7f349dd8e6e077ba7dcef9403084971c3295b76", "0x8b09b0f431a7c796561ecf1549b85048564de428dac0474522e9558b6065fede231886bc108539c104ce88ebd9b5d1b0", "0x85d6e742e2fb16a7b0ba0df64bc2c0dbff9549be691f46a6669bca05e89c884af16822b85faefefb604ec48c8705a309", "0xa87989ee231e468a712c66513746fcf03c14f103aadca0eac28e9732487deb56d7532e407953ab87a4bf8961588ef7b0", "0xb00da10efe1c29ee03c9d37d5918e391ae30e48304e294696b81b434f65cf8c8b95b9d1758c64c25e534d045ba28696f", "0x91c0e1fb49afe46c7056400baa06dbb5f6e479db78ee37e2d76c1f4e88994357e257b83b78624c4ef6091a6c0eb8254d", "0x883fb797c498297ccbf9411a3e727c3614af4eccde41619b773dc7f3259950835ee79453debf178e11dec4d3ada687a0", "0xa14703347e44eb5059070b2759297fcfcfc60e6893c0373eea069388eba3950aa06f1c57cd2c30984a2d6f9e9c92c79e", "0xafebc7585b304ceba9a769634adff35940e89cd32682c78002822aab25eec3edc29342b7f5a42a56a1fec67821172ad5", "0xaea3ff3822d09dba1425084ca95fd359718d856f6c133c5fabe2b2eed8303b6e0ba0d8698b48b93136a673baac174fd9", "0xaf2456a09aa777d9e67aa6c7c49a1845ea5cdda2e39f4c935c34a5f8280d69d4eec570446998cbbe31ede69a91e90b06", "0x82cada19fed16b891ef3442bafd49e1f07c00c2f57b2492dd4ee36af2bd6fd877d6cb41188a4d6ce9ec8d48e8133d697", "0x82a21034c832287f616619a37c122cee265cc34ae75e881fcaea4ea7f689f3c2bc8150bbf7dbcfd123522bfb7f7b1d68", "0x86877217105f5d0ec3eeff0289fc2a70d505c9fdf7862e8159553ef60908fb1a27bdaf899381356a4ef4649072a9796c", "0x82b196e49c6e861089a427c0b4671d464e9d15555ffb90954cd0d630d7ae02eb3d98ceb529d00719c2526cd96481355a", "0xa29b41d0d43d26ce76d4358e0db2b77df11f56e389f3b084d8af70a636218bd3ac86b36a9fe46ec9058c26a490f887f7", "0xa4311c4c20c4d7dd943765099c50f2fd423e203ccfe98ff00087d205467a7873762510cac5fdce7a308913ed07991ed7", "0xb1f040fc5cc51550cb2c25cf1fd418ecdd961635a11f365515f0cb4ffb31da71f48128c233e9cc7c0cf3978d757ec84e", "0xa9ebae46f86d3bd543c5f207ed0d1aed94b8375dc991161d7a271f01592912072e083e2daf30c146430894e37325a1b9", "0x826418c8e17ad902b5fe88736323a47e0ca7a44bce4cbe27846ec8fe81de1e8942455dda6d30e192cdcc73e11df31256", "0x85199db563427c5edcbac21f3d39fec2357be91fb571982ddcdc4646b446ad5ced84410de008cb47b3477ee0d532daf8", "0xb7eed9cd400b2ca12bf1d9ae008214b8561fb09c8ad9ff959e626ffde00fee5ff2f5b6612e231f2a1a9b1646fcc575e3", "0x8b40bf12501dcbac78f5a314941326bfcddf7907c83d8d887d0bb149207f85d80cd4dfbd7935439ea7b14ea39a3fded7", "0x83e3041af302485399ba6cd5120e17af61043977083887e8d26b15feec4a6b11171ac5c06e6ad0971d4b58a81ff12af3", "0x8f5b9a0eecc589dbf8c35a65d5e996a659277ef6ea509739c0cb7b3e2da9895e8c8012de662e5b23c5fa85d4a8f48904", "0x835d71ed5e919d89d8e6455f234f3ff215462c4e3720c371ac8c75e83b19dfe3ae15a81547e4dc1138e5f5997f413cc9", "0x8b7d2e4614716b1db18e9370176ea483e6abe8acdcc3dcdf5fb1f4d22ca55d652feebdccc171c6de38398d9f7bfdec7a", "0x93eace72036fe57d019676a02acf3d224cf376f166658c1bf705db4f24295881d477d6fdd7916efcfceff8c7a063deda", "0xb1ac460b3d516879a84bc886c54f020a9d799e7c49af3e4d7de5bf0d2793c852254c5d8fe5616147e6659512e5ccb012", "0xacd0947a35cb167a48bcd9667620464b54ac0e78f9316b4aa92dcaab5422d7a732087e52e1c827faa847c6b2fe6e7766", "0x94ac33d21c3d12ff762d32557860e911cd94d666609ddcc42161b9c16f28d24a526e8b10bb03137257a92cec25ae637d", "0x832e02058b6b994eadd8702921486241f9a19e68ed1406dad545e000a491ae510f525ccf9d10a4bba91c68f2c53a0f58", "0x9471035d14f78ff8f463b9901dd476b587bb07225c351161915c2e9c6114c3c78a501379ab6fb4eb03194c457cbd22bf", "0xab64593e034c6241d357fcbc32d8ea5593445a5e7c24cac81ad12bd2ef01843d477a36dc1ba21dbe63b440750d72096a", "0x9850f3b30045e927ad3ec4123a32ed2eb4c911f572b6abb79121873f91016f0d80268de8b12e2093a4904f6e6cab7642", "0x987212c36b4722fe2e54fa30c52b1e54474439f9f35ca6ad33c5130cd305b8b54b532dd80ffd2c274105f20ce6d79f6e", "0x8b4d0c6abcb239b5ed47bef63bc17efe558a27462c8208fa652b056e9eae9665787cd1aee34fbb55beb045c8bfdb882b", "0xa9f3483c6fee2fe41312d89dd4355d5b2193ac413258993805c5cbbf0a59221f879386d3e7a28e73014f10e65dd503d9", "0xa2225da3119b9b7c83d514b9f3aeb9a6d9e32d9cbf9309cbb971fd53c4b2c001d10d880a8ad8a7c281b21d85ceca0b7c", "0xa050be52e54e676c151f7a54453bbb707232f849beab4f3bf504b4d620f59ed214409d7c2bd3000f3ff13184ccda1c35", "0xadbccf681e15b3edb6455a68d292b0a1d0f5a4cb135613f5e6db9943f02181341d5755875db6ee474e19ace1c0634a28", "0x8b6eff675632a6fad0111ec72aacc61c7387380eb87933fd1d098856387d418bd38e77d897e65d6fe35951d0627c550b", "0xaabe2328ddf90989b15e409b91ef055cb02757d34987849ae6d60bef2c902bf8251ed21ab30acf39e500d1d511e90845", "0x92ba4eb1f796bc3d8b03515f65c045b66e2734c2da3fc507fdd9d6b5d1e19ab3893726816a32141db7a31099ca817d96", "0x8a98b3cf353138a1810beb60e946183803ef1d39ac4ea92f5a1e03060d35a4774a6e52b14ead54f6794d5f4022b8685c", "0x909f8a5c13ec4a59b649ed3bee9f5d13b21d7f3e2636fd2bb3413c0646573fdf9243d63083356f12f5147545339fcd55", "0x9359d914d1267633141328ed0790d81c695fea3ddd2d406c0df3d81d0c64931cf316fe4d92f4353c99ff63e2aefc4e34", "0xb88302031681b54415fe8fbfa161c032ea345c6af63d2fb8ad97615103fd4d4281c5a9cae5b0794c4657b97571a81d3b", "0x992c80192a519038082446b1fb947323005b275e25f2c14c33cc7269e0ec038581cc43705894f94bad62ae33a8b7f965", "0xa78253e3e3eece124bef84a0a8807ce76573509f6861d0b6f70d0aa35a30a123a9da5e01e84969708c40b0669eb70aa6", "0x8d5724de45270ca91c94792e8584e676547d7ac1ac816a6bb9982ee854eb5df071d20545cdfd3771cd40f90e5ba04c8e", "0x825a6f586726c68d45f00ad0f5a4436523317939a47713f78fd4fe81cd74236fdac1b04ecd97c2d0267d6f4981d7beb1" ], "g2_monomial": [ "0x93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8", "0xb5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2", "0xb5337ba0ce5d37224290916e268e2060e5c14f3f9fc9e1ec3af5a958e7a0303122500ce18f1a4640bf66525bd10e763501fe986d86649d8d45143c08c3209db3411802c226e9fe9a55716ac4a0c14f9dcef9e70b2bb309553880dc5025eab3cc", "0xb3c1dcdc1f62046c786f0b82242ef283e7ed8f5626f72542aa2c7a40f14d9094dd1ebdbd7457ffdcdac45fd7da7e16c51200b06d791e5e43e257e45efdf0bd5b06cd2333beca2a3a84354eb48662d83aef5ecf4e67658c851c10b13d8d87c874", "0x954d91c7688983382609fca9e211e461f488a5971fd4e40d7e2892037268eacdfd495cfa0a7ed6eb0eb11ac3ae6f651716757e7526abe1e06c64649d80996fd3105c20c4c94bc2b22d97045356fe9d791f21ea6428ac48db6f9e68e30d875280", "0x88a6b6bb26c51cf9812260795523973bb90ce80f6820b6c9048ab366f0fb96e48437a7f7cb62aedf64b11eb4dfefebb0147608793133d32003cb1f2dc47b13b5ff45f1bb1b2408ea45770a08dbfaec60961acb8119c47b139a13b8641e2c9487", "0x85cd7be9728bd925d12f47fb04b32d9fad7cab88788b559f053e69ca18e463113ecc8bbb6dbfb024835f901b3a957d3108d6770fb26d4c8be0a9a619f6e3a4bf15cbfd48e61593490885f6cee30e4300c5f9cf5e1c08e60a2d5b023ee94fcad0", "0x80477dba360f04399821a48ca388c0fa81102dd15687fea792ee8c1114e00d1bc4839ad37ac58900a118d863723acfbe08126ea883be87f50e4eabe3b5e72f5d9e041db8d9b186409fd4df4a7dde38c0e0a3b1ae29b098e5697e7f110b6b27e4", "0xb7a6aec08715a9f8672a2b8c367e407be37e59514ac19dd4f0942a68007bba3923df22da48702c63c0d6b3efd3c2d04e0fe042d8b5a54d562f9f33afc4865dcbcc16e99029e25925580e87920c399e710d438ac1ce3a6dc9b0d76c064a01f6f7", "0xac1b001edcea02c8258aeffbf9203114c1c874ad88dae1184fadd7d94cd09053649efd0ca413400e6e9b5fa4eac33261000af88b6bd0d2abf877a4f0355d2fb4d6007adb181695201c5432e50b850b51b3969f893bddf82126c5a71b042b7686", "0x90043fda4de53fb364fab2c04be5296c215599105ecff0c12e4917c549257125775c29f2507124d15f56e30447f367db0596c33237242c02d83dfd058735f1e3c1ff99069af55773b6d51d32a68bf75763f59ec4ee7267932ae426522b8aaab6", "0xa8660ce853e9dc08271bf882e29cd53397d63b739584dda5263da4c7cc1878d0cf6f3e403557885f557e184700575fee016ee8542dec22c97befe1d10f414d22e84560741cdb3e74c30dda9b42eeaaf53e27822de2ee06e24e912bf764a9a533", "0x8fe3921a96d0d065e8aa8fce9aa42c8e1461ca0470688c137be89396dd05103606dab6cdd2a4591efd6addf72026c12e065da7be276dee27a7e30afa2bd81c18f1516e7f068f324d0bad9570b95f6bd02c727cd2343e26db0887c3e4e26dceda", "0x8ae1ad97dcb9c192c9a3933541b40447d1dc4eebf380151440bbaae1e120cc5cdf1bcea55180b128d8e180e3af623815191d063cc0d7a47d55fb7687b9d87040bf7bc1a7546b07c61db5ccf1841372d7c2fe4a5431ffff829f3c2eb590b0b710", "0x8c2fa96870a88150f7876c931e2d3cc2adeaaaf5c73ef5fa1cf9dfa0991ae4819f9321af7e916e5057d87338e630a2f21242c29d76963cf26035b548d2a63d8ad7bd6efefa01c1df502cbdfdfe0334fb21ceb9f686887440f713bf17a89b8081", "0xb9aa98e2f02bb616e22ee5dd74c7d1049321ac9214d093a738159850a1dbcc7138cb8d26ce09d8296368fd5b291d74fa17ac7cc1b80840fdd4ee35e111501e3fa8485b508baecda7c1ab7bd703872b7d64a2a40b3210b6a70e8a6ffe0e5127e3", "0x9292db67f8771cdc86854a3f614a73805bf3012b48f1541e704ea4015d2b6b9c9aaed36419769c87c49f9e3165f03edb159c23b3a49c4390951f78e1d9b0ad997129b17cdb57ea1a6638794c0cca7d239f229e589c5ae4f9fe6979f7f8cba1d7", "0x91cd9e86550f230d128664f7312591fee6a84c34f5fc7aed557bcf986a409a6de722c4330453a305f06911d2728626e611acfdf81284f77f60a3a1595053a9479964fd713117e27c0222cc679674b03bc8001501aaf9b506196c56de29429b46", "0xa9516b73f605cc31b89c68b7675dc451e6364595243d235339437f556cf22d745d4250c1376182273be2d99e02c10eee047410a43eff634d051aeb784e76cb3605d8e079b9eb6ad1957dfdf77e1cd32ce4a573c9dfcc207ca65af6eb187f6c3d", "0xa9667271f7d191935cc8ad59ef3ec50229945faea85bfdfb0d582090f524436b348aaa0183b16a6231c00332fdac2826125b8c857a2ed9ec66821cfe02b3a2279be2412441bc2e369b255eb98614e4be8490799c4df22f18d47d24ec70bba5f7", "0xa4371144d2aa44d70d3cb9789096d3aa411149a6f800cb46f506461ee8363c8724667974252f28aea61b6030c05930ac039c1ee64bb4bd56532a685cae182bf2ab935eee34718cffcb46cae214c77aaca11dbb1320faf23c47247db1da04d8dc", "0x89a7eb441892260b7e81168c386899cd84ffc4a2c5cad2eae0d1ab9e8b5524662e6f660fe3f8bfe4c92f60b060811bc605b14c5631d16709266886d7885a5eb5930097127ec6fb2ebbaf2df65909cf48f253b3d5e22ae48d3e9a2fd2b01f447e", "0x9648c42ca97665b5eccb49580d8532df05eb5a68db07f391a2340769b55119eaf4c52fe4f650c09250fa78a76c3a1e271799b8333cc2628e3d4b4a6a3e03da1f771ecf6516dd63236574a7864ff07e319a6f11f153406280d63af9e2b5713283", "0x9663bf6dd446ea7a90658ee458578d4196dc0b175ef7fcfa75f44d41670850774c2e46c5a6be132a2c072a3c0180a24f0305d1acac49d2d79878e5cda80c57feda3d01a6af12e78b5874e2a4b3717f11c97503b41a4474e2e95b179113726199", "0xb212aeb4814e0915b432711b317923ed2b09e076aaf558c3ae8ef83f9e15a83f9ea3f47805b2750ab9e8106cb4dc6ad003522c84b03dc02829978a097899c773f6fb31f7fe6b8f2d836d96580f216fec20158f1590c3e0d7850622e15194db05", "0x925f005059bf07e9ceccbe66c711b048e236ade775720d0fe479aebe6e23e8af281225ad18e62458dc1b03b42ad4ca290d4aa176260604a7aad0d9791337006fbdebe23746f8060d42876f45e4c83c3643931392fde1cd13ff8bddf8111ef974", "0x9553edb22b4330c568e156a59ef03b26f5c326424f830fe3e8c0b602f08c124730ffc40bc745bec1a22417adb22a1a960243a10565c2be3066bfdb841d1cd14c624cd06e0008f4beb83f972ce6182a303bee3fcbcabc6cfe48ec5ae4b7941bfc", "0x935f5a404f0a78bdcce709899eda0631169b366a669e9b58eacbbd86d7b5016d044b8dfc59ce7ed8de743ae16c2343b50e2f925e88ba6319e33c3fc76b314043abad7813677b4615c8a97eb83cc79de4fedf6ccbcfa4d4cbf759a5a84e4d9742", "0xa5b014ab936eb4be113204490e8b61cd38d71da0dec7215125bcd131bf3ab22d0a32ce645bca93e7b3637cf0c2db3d6601a0ddd330dc46f9fae82abe864ffc12d656c88eb50c20782e5bb6f75d18760666f43943abb644b881639083e122f557", "0x935b7298ae52862fa22bf03bfc1795b34c70b181679ae27de08a9f5b4b884f824ef1b276b7600efa0d2f1d79e4a470d51692fd565c5cf8343dd80e5d3336968fc21c09ba9348590f6206d4424eb229e767547daefa98bc3aa9f421158dee3f2a", "0x9830f92446e708a8f6b091cc3c38b653505414f8b6507504010a96ffda3bcf763d5331eb749301e2a1437f00e2415efb01b799ad4c03f4b02de077569626255ac1165f96ea408915d4cf7955047620da573e5c439671d1fa5c833fb11de7afe6", "0x840dcc44f673fff3e387af2bb41e89640f2a70bcd2b92544876daa92143f67c7512faf5f90a04b7191de01f3e2b1bde00622a20dc62ca23bbbfaa6ad220613deff43908382642d4d6a86999f662efd64b1df448b68c847cfa87630a3ffd2ec76", "0x92950c895ed54f7f876b2fda17ecc9c41b7accfbdd42c210cc5b475e0737a7279f558148531b5c916e310604a1de25a80940c94fe5389ae5d6a5e9c371be67bceea1877f5401725a6595bcf77ece60905151b6dfcb68b75ed2e708c73632f4fd", "0x8010246bf8e94c25fd029b346b5fbadb404ef6f44a58fd9dd75acf62433d8cc6db66974f139a76e0c26dddc1f329a88214dbb63276516cf325c7869e855d07e0852d622c332ac55609ba1ec9258c45746a2aeb1af0800141ee011da80af175d4", "0xb0f1bad257ebd187bdc3f37b23f33c6a5d6a8e1f2de586080d6ada19087b0e2bf23b79c1b6da1ee82271323f5bdf3e1b018586b54a5b92ab6a1a16bb3315190a3584a05e6c37d5ca1e05d702b9869e27f513472bcdd00f4d0502a107773097da", "0x9636d24f1ede773ce919f309448dd7ce023f424afd6b4b69cb98c2a988d849a283646dc3e469879daa1b1edae91ae41f009887518e7eb5578f88469321117303cd3ac2d7aee4d9cb5f82ab9ae3458e796dfe7c24284b05815acfcaa270ff22e2", "0xb373feb5d7012fd60578d7d00834c5c81df2a23d42794fed91aa9535a4771fde0341c4da882261785e0caca40bf83405143085e7f17e55b64f6c5c809680c20b050409bf3702c574769127c854d27388b144b05624a0e24a1cbcc4d08467005b", "0xb15680648949ce69f82526e9b67d9b55ce5c537dc6ab7f3089091a9a19a6b90df7656794f6edc87fb387d21573ffc847062623685931c2790a508cbc8c6b231dd2c34f4d37d4706237b1407673605a604bcf6a50cc0b1a2db20485e22b02c17e", "0x8817e46672d40c8f748081567b038a3165f87994788ec77ee8daea8587f5540df3422f9e120e94339be67f186f50952504cb44f61e30a5241f1827e501b2de53c4c64473bcc79ab887dd277f282fbfe47997a930dd140ac08b03efac88d81075", "0xa6e4ef6c1d1098f95aae119905f87eb49b909d17f9c41bcfe51127aa25fee20782ea884a7fdf7d5e9c245b5a5b32230b07e0dbf7c6743bf52ee20e2acc0b269422bd6cf3c07115df4aa85b11b2c16630a07c974492d9cdd0ec325a3fabd95044", "0x8634aa7c3d00e7f17150009698ce440d8e1b0f13042b624a722ace68ead870c3d2212fbee549a2c190e384d7d6ac37ce14ab962c299ea1218ef1b1489c98906c91323b94c587f1d205a6edd5e9d05b42d591c26494a6f6a029a2aadb5f8b6f67", "0x821a58092900bdb73decf48e13e7a5012a3f88b06288a97b855ef51306406e7d867d613d9ec738ebacfa6db344b677d21509d93f3b55c2ebf3a2f2a6356f875150554c6fff52e62e3e46f7859be971bf7dd9d5b3e1d799749c8a97c2e04325df", "0x8dba356577a3a388f782e90edb1a7f3619759f4de314ad5d95c7cc6e197211446819c4955f99c5fc67f79450d2934e3c09adefc91b724887e005c5190362245eec48ce117d0a94d6fa6db12eda4ba8dde608fbbd0051f54dcf3bb057adfb2493", "0xa32a690dc95c23ed9fb46443d9b7d4c2e27053a7fcc216d2b0020a8cf279729c46114d2cda5772fd60a97016a07d6c5a0a7eb085a18307d34194596f5b541cdf01b2ceb31d62d6b55515acfd2b9eec92b27d082fbc4dc59fc63b551eccdb8468", "0xa040f7f4be67eaf0a1d658a3175d65df21a7dbde99bfa893469b9b43b9d150fc2e333148b1cb88cfd0447d88fa1a501d126987e9fdccb2852ecf1ba907c2ca3d6f97b055e354a9789854a64ecc8c2e928382cf09dda9abde42bbdf92280cdd96", "0x864baff97fa60164f91f334e0c9be00a152a416556b462f96d7c43b59fe1ebaff42f0471d0bf264976f8aa6431176eb905bd875024cf4f76c13a70bede51dc3e47e10b9d5652d30d2663b3af3f08d5d11b9709a0321aba371d2ef13174dcfcaf", "0x95a46f32c994133ecc22db49bad2c36a281d6b574c83cfee6680b8c8100466ca034b815cfaedfbf54f4e75188e661df901abd089524e1e0eb0bf48d48caa9dd97482d2e8c1253e7e8ac250a32fd066d5b5cb08a8641bdd64ecfa48289dca83a3", "0xa2cce2be4d12144138cb91066e0cd0542c80b478bf467867ebef9ddaf3bd64e918294043500bf5a9f45ee089a8d6ace917108d9ce9e4f41e7e860cbce19ac52e791db3b6dde1c4b0367377b581f999f340e1d6814d724edc94cb07f9c4730774", "0xb145f203eee1ac0a1a1731113ffa7a8b0b694ef2312dabc4d431660f5e0645ef5838e3e624cfe1228cfa248d48b5760501f93e6ab13d3159fc241427116c4b90359599a4cb0a86d0bb9190aa7fabff482c812db966fd2ce0a1b48cb8ac8b3bca", "0xadabe5d215c608696e03861cbd5f7401869c756b3a5aadc55f41745ad9478145d44393fec8bb6dfc4ad9236dc62b9ada0f7ca57fe2bae1b71565dbf9536d33a68b8e2090b233422313cc96afc7f1f7e0907dc7787806671541d6de8ce47c4cd0", "0xae7845fa6b06db53201c1080e01e629781817f421f28956589c6df3091ec33754f8a4bd4647a6bb1c141ac22731e3c1014865d13f3ed538dcb0f7b7576435133d9d03be655f8fbb4c9f7d83e06d1210aedd45128c2b0c9bab45a9ddde1c862a5", "0x9159eaa826a24adfa7adf6e8d2832120ebb6eccbeb3d0459ffdc338548813a2d239d22b26451fda98cc0c204d8e1ac69150b5498e0be3045300e789bcb4e210d5cd431da4bdd915a21f407ea296c20c96608ded0b70d07188e96e6c1a7b9b86b", "0xa9fc6281e2d54b46458ef564ffaed6944bff71e389d0acc11fa35d3fcd8e10c1066e0dde5b9b6516f691bb478e81c6b20865281104dcb640e29dc116daae2e884f1fe6730d639dbe0e19a532be4fb337bf52ae8408446deb393d224eee7cfa50", "0x84291a42f991bfb36358eedead3699d9176a38f6f63757742fdbb7f631f2c70178b1aedef4912fed7b6cf27e88ddc7eb0e2a6aa4b999f3eb4b662b93f386c8d78e9ac9929e21f4c5e63b12991fcde93aa64a735b75b535e730ff8dd2abb16e04", "0xa1b7fcacae181495d91765dfddf26581e8e39421579c9cbd0dd27a40ea4c54af3444a36bf85a11dda2114246eaddbdd619397424bb1eb41b5a15004b902a590ede5742cd850cf312555be24d2df8becf48f5afba5a8cd087cb7be0a521728386", "0x92feaaf540dbd84719a4889a87cdd125b7e995a6782911931fef26da9afcfbe6f86aaf5328fe1f77631491ce6239c5470f44c7791506c6ef1626803a5794e76d2be0af92f7052c29ac6264b7b9b51f267ad820afc6f881460521428496c6a5f1", "0xa525c925bfae1b89320a5054acc1fa11820f73d0cf28d273092b305467b2831fab53b6daf75fb926f332782d50e2522a19edcd85be5eb72f1497193c952d8cd0bcc5d43b39363b206eae4cb1e61668bde28a3fb2fc1e0d3d113f6dfadb799717", "0x98752bb6f5a44213f40eda6aa4ff124057c1b13b6529ab42fe575b9afa66e59b9c0ed563fb20dff62130c436c3e905ee17dd8433ba02c445b1d67182ab6504a90bbe12c26a754bbf734665c622f76c62fe2e11dd43ce04fd2b91a8463679058b", "0xa9aa9a84729f7c44219ff9e00e651e50ddea3735ef2a73fdf8ed8cd271961d8ed7af5cd724b713a89a097a3fe65a3c0202f69458a8b4c157c62a85668b12fc0d3957774bc9b35f86c184dd03bfefd5c325da717d74192cc9751c2073fe9d170e", "0xb221c1fd335a4362eff504cd95145f122bf93ea02ae162a3fb39c75583fc13a932d26050e164da97cff3e91f9a7f6ff80302c19dd1916f24acf6b93b62f36e9665a8785413b0c7d930c7f1668549910f849bca319b00e59dd01e5dec8d2edacc", "0xa71e2b1e0b16d754b848f05eda90f67bedab37709550171551050c94efba0bfc282f72aeaaa1f0330041461f5e6aa4d11537237e955e1609a469d38ed17f5c2a35a1752f546db89bfeff9eab78ec944266f1cb94c1db3334ab48df716ce408ef", "0xb990ae72768779ba0b2e66df4dd29b3dbd00f901c23b2b4a53419226ef9232acedeb498b0d0687c463e3f1eead58b20b09efcefa566fbfdfe1c6e48d32367936142d0a734143e5e63cdf86be7457723535b787a9cfcfa32fe1d61ad5a2617220", "0x8d27e7fbff77d5b9b9bbc864d5231fecf817238a6433db668d5a62a2c1ee1e5694fdd90c3293c06cc0cb15f7cbeab44d0d42be632cb9ff41fc3f6628b4b62897797d7b56126d65b694dcf3e298e3561ac8813fbd7296593ced33850426df42db", "0xa92039a08b5502d5b211a7744099c9f93fa8c90cedcb1d05e92f01886219dd464eb5fb0337496ad96ed09c987da4e5f019035c5b01cc09b2a18b8a8dd419bc5895388a07e26958f6bd26751929c25f89b8eb4a299d822e2d26fec9ef350e0d3c", "0x92dcc5a1c8c3e1b28b1524e3dd6dbecd63017c9201da9dbe077f1b82adc08c50169f56fc7b5a3b28ec6b89254de3e2fd12838a761053437883c3e01ba616670cea843754548ef84bcc397de2369adcca2ab54cd73c55dc68d87aec3fc2fe4f10" ] } ================================================ FILE: testing/networks/80094/spec.toml ================================================ # Mainnet Chain Spec Configuration # Gwei value constants max-effective-balance = 10_000_000_000_000_000 effective-balance-increment = 10_000_000_000_000 # Hysteresis parameters hysteresis-quotient = 4 hysteresis-downward-multiplier = 1 hysteresis-upward-multiplier = 5 # Time parameters slots-per-epoch = 192 slots-per-historical-root = 8 min-epochs-to-inactivity-penalty = 4 # Signature domains domain-type-beacon-proposer = "0x00000000" domain-type-beacon-attester = "0x01000000" domain-type-randao = "0x02000000" domain-type-deposit = "0x03000000" domain-type-voluntary-exit = "0x04000000" domain-type-selection-proof = "0x05000000" domain-type-aggregate-and-proof = "0x06000000" domain-type-application-mask = "0x00000001" # Eth1-related values deposit-contract-address = "0x4242424242424242424242424242424242424242" max-deposits-per-block = 16 deposit-eth1-chain-id = 80094 eth1-follow-distance = 1 target-seconds-per-eth1-block = 2 # Fork-related values genesis-time = 1_737_381_600 deneb-one-fork-time = 1_738_415_507 electra-fork-time = 1_749_056_400 electra-one-fork-time = 1_756_915_200 fulu-fork-time = 9_999_999_999_999_999 # State list lengths epochs-per-historical-vector = 8 epochs-per-slashings-vector = 8 historical-roots-limit = 8 validator-registry-limit = 1_099_511_627_776 # Capella values max-withdrawals-per-payload = 16 max-validators-per-withdrawals-sweep = 31 # Deneb values min-epochs-for-blobs-sidecars-request = 4096 max-blob-commitments-per-block = 4096 max-blobs-per-block = 6 field-elements-per-blob = 4096 bytes-per-blob = 131072 # Berachain genesis values validator-set-cap = 69 evm-inflation-address = "0x0000000000000000000000000000000000000000" evm-inflation-per-block = 0 # Deneb1 value changes evm-inflation-address-deneb-one = "0x656b95E550C07a9ffe548bd4085c72418Ceb1dba" evm-inflation-per-block-deneb-one = 5_750_000_000 # Electra values min-activation-balance = 250_000_000_000_000 min-validator-withdrawability-delay = 256 # Fulu values (BRIP-0008 hysteresis + PoL vNext -- TODO: update values) hysteresis-quotient-fulu = 100 hysteresis-upward-multiplier-fulu = 10 evm-inflation-address-fulu = "0x0000000000000000000000000000000000000000" evm-inflation-per-block-fulu = 0 [block-delay-configuration] max-block-delay = 300_000_000_000 target-block-time = 2_000_000_000 const-block-delay = 500_000_000 consensus-update-height = 9_983_085 consensus-enable-height = 9_983_086 ================================================ FILE: testing/quick/compare_test.go ================================================ //go:build quick // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package compare_test import ( "bytes" "testing" "testing/quick" datypes "github.com/berachain/beacon-kit/da/types" zspec "github.com/protolambda/zrnt/eth2/configs" ztree "github.com/protolambda/ztyp/tree" pprim "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" pethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1" ) var ( c = quick.Config{MaxCount: 10_000} hFn = ztree.GetHashFn() spec = zspec.Mainnet ) // TODO: None of the iterations makes it to `HashTreeRoot` as they all get caught by the nil checks. // A custom generator is required like TestExecPayload. Test is skipped for now as it is not useful as is. func TestBlobSidecarTreeRootPrysm(t *testing.T) { t.Parallel() t.Skip() f := func(sidecar *datypes.BlobSidecar) bool { // skip these cases lest we trigger a // nil-pointer dereference in fastssz if sidecar == nil || sidecar.InclusionProof == nil || sidecar.SignedBeaconBlockHeader == nil || sidecar.SignedBeaconBlockHeader.Header == nil || // prysm allows only sidecars whose InclusionProof has // length 17, while beaconKit allows different length. // We only keep 17 long Inclusion proofs for proper comparison len(sidecar.InclusionProof) != 17 { return true } sBlkHeader := sidecar.SignedBeaconBlockHeader blkHeader := sBlkHeader.Header pBlobSidecar := &pethpb.BlobSidecar{ Index: sidecar.Index, Blob: sidecar.Blob[:], KzgCommitment: sidecar.KzgCommitment[:], KzgProof: sidecar.KzgProof[:], SignedBlockHeader: &pethpb.SignedBeaconBlockHeader{ Header: &pethpb.BeaconBlockHeader{ Slot: pprim.Slot(blkHeader.Slot), ProposerIndex: pprim.ValidatorIndex(blkHeader.ProposerIndex), ParentRoot: blkHeader.ParentBlockRoot[:], StateRoot: blkHeader.StateRoot[:], BodyRoot: blkHeader.BodyRoot[:], }, Signature: sBlkHeader.Signature[:], }, } // Setup inclusion proofs inclusionProofs := sidecar.InclusionProof pBlobSidecar.CommitmentInclusionProof = make([][]byte, len(inclusionProofs)) for i, proof := range inclusionProofs { pBlobSidecar.CommitmentInclusionProof[i] = proof[:] } beaconRoot := sidecar.HashTreeRoot() prysmRoot, err := pBlobSidecar.HashTreeRoot() if err != nil { t.Error(err) } return bytes.Equal(prysmRoot[:], beaconRoot[:]) } if err := quick.Check(f, &c); err != nil { t.Error(err) } } ================================================ FILE: testing/quick/execution_payload_test.go ================================================ //go:build quick // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package compare_test import ( "bytes" "math/rand" "reflect" "testing" "testing/quick" "unsafe" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" bytesprimitives "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" zcommon "github.com/protolambda/zrnt/eth2/beacon/common" zdeneb "github.com/protolambda/zrnt/eth2/beacon/deneb" ztree "github.com/protolambda/ztyp/tree" zview "github.com/protolambda/ztyp/view" ) // --- Helper Struct --- // execPayloadExported mirrors the exported fields of ExecutionPayload. // Note that forkVersion is unexported and omitted. type execPayloadExported struct { // ParentHash is the hash of the parent block. ParentHash common.ExecutionHash `json:"parentHash"` // FeeRecipient is the address of the fee recipient. FeeRecipient common.ExecutionAddress `json:"feeRecipient"` // StateRoot is the root of the state trie. StateRoot common.Bytes32 `json:"stateRoot"` // ReceiptsRoot is the root of the receipts trie. ReceiptsRoot common.Bytes32 `json:"receiptsRoot"` // LogsBloom is the bloom filter for the logs. LogsBloom bytesprimitives.B256 `json:"logsBloom"` // Random is the prevRandao value. Random common.Bytes32 `json:"prevRandao"` // Number is the block number. Number math.U64 `json:"blockNumber"` // GasLimit is the gas limit for the block. GasLimit math.U64 `json:"gasLimit"` // GasUsed is the amount of gas used in the block. GasUsed math.U64 `json:"gasUsed"` // Timestamp is the timestamp of the block. Timestamp math.U64 `json:"timestamp"` // ExtraData is the extra data of the block. ExtraData bytesprimitives.Bytes `json:"extraData"` // BaseFeePerGas is the base fee per gas. BaseFeePerGas *math.U256 `json:"baseFeePerGas"` // BlockHash is the hash of the block. BlockHash common.ExecutionHash `json:"blockHash"` // Transactions is the list of transactions in the block. Transactions engineprimitives.Transactions `json:"transactions"` // Withdrawals is the list of withdrawals in the block. Withdrawals []*engineprimitives.Withdrawal `json:"withdrawals"` // BlobGasUsed is the amount of blob gas used in the block. BlobGasUsed math.U64 `json:"blobGasUsed"` // ExcessBlobGas is the amount of excess blob gas in the block. ExcessBlobGas math.U64 `json:"excessBlobGas"` } // --- Local Alias Type --- // TestExecPayload is our alias for ExecutionPayload. type TestExecPayload ctypes.ExecutionPayload // generateWithdrawals generates a slice of *engineprimitives.Withdrawal // with a random length up to maxLen. func generateWithdrawals(r *rand.Rand, maxLen int) []*engineprimitives.Withdrawal { n := r.Intn(maxLen + 1) // length between 0 and maxLen withdrawals := make([]*engineprimitives.Withdrawal, n) // For each element, use quick.Value to generate a withdrawal. withdrawalType := reflect.TypeOf(engineprimitives.Withdrawal{}) for i := 0; i < n; i++ { v, ok := quick.Value(withdrawalType, r) if !ok { panic("failed to generate withdrawal") } w := v.Interface().(engineprimitives.Withdrawal) withdrawals[i] = &w } return withdrawals } // Generate implements quick.Generator for *TestExecPayload. func (p *TestExecPayload) Generate(r *rand.Rand, size int) reflect.Value { // Step 1: Generate a value for the helper struct, which contains only exported fields. var exp execPayloadExported v, ok := quick.Value(reflect.TypeOf(exp), r) if !ok { panic("failed to generate execPayloadExported") } exp = v.Interface().(execPayloadExported) // Step 2: Copy exported fields from exp into our alias. var tep TestExecPayload tep.ParentHash = exp.ParentHash tep.FeeRecipient = exp.FeeRecipient tep.StateRoot = exp.StateRoot tep.ReceiptsRoot = exp.ReceiptsRoot tep.LogsBloom = exp.LogsBloom tep.Random = exp.Random tep.Number = exp.Number tep.GasLimit = exp.GasLimit tep.GasUsed = exp.GasUsed tep.Timestamp = exp.Timestamp tep.ExtraData = exp.ExtraData tep.BaseFeePerGas = exp.BaseFeePerGas tep.BlockHash = exp.BlockHash tep.Transactions = exp.Transactions tep.Withdrawals = exp.Withdrawals tep.BlobGasUsed = exp.BlobGasUsed tep.ExcessBlobGas = exp.ExcessBlobGas // Step 3: Generate withdrawals. Default withdrawals generation only generates a maximum length of 1 so we need a custom helper. tep.Withdrawals = generateWithdrawals(r, int(constants.MaxWithdrawalsPerPayload)) // Step 4: Set the unexported forkVersion via the setter. // Convert our alias pointer to the production *ctypes.ExecutionPayload. orig := (*ctypes.ExecutionPayload)(&tep) supported := version.GetSupportedVersions() orig.Versionable = ctypes.NewVersionable(supported[r.Intn(len(supported))]) // Step 5 set a fixed value for BaseFee to avoid panicks. Could be its own generator. orig.BaseFeePerGas = math.NewU256(123) // Return a reflect.Value representing a pointer to our alias. return reflect.ValueOf(&tep) } func TestExecutionPayloadHashTreeRootZrnt(t *testing.T) { t.Parallel() f := func(testPayload *TestExecPayload) bool { // Convert the generated value back to the production type. payload := (*ctypes.ExecutionPayload)(testPayload) typeRoot := payload.HashTreeRoot() baseFeePerGas := zview.Uint256View{} baseFeePerGas.SetFromBig(payload.BaseFeePerGas.ToBig()) zpayload := zdeneb.ExecutionPayload{ ParentHash: ztree.Root(payload.ParentHash), FeeRecipient: zcommon.Eth1Address(payload.FeeRecipient), StateRoot: ztree.Root(payload.StateRoot), ReceiptsRoot: ztree.Root(payload.ReceiptsRoot), LogsBloom: zcommon.LogsBloom(payload.LogsBloom), PrevRandao: ztree.Root(payload.Random), BlockNumber: zview.Uint64View(payload.Number), GasLimit: zview.Uint64View(payload.GasLimit), GasUsed: zview.Uint64View(payload.GasUsed), Timestamp: zcommon.Timestamp(payload.Timestamp), ExtraData: []byte(payload.ExtraData), BaseFeePerGas: baseFeePerGas, BlockHash: ztree.Root(payload.BlockHash), Transactions: *(*zcommon.PayloadTransactions)( unsafe.Pointer(&payload.Transactions)), BlobGasUsed: zview.Uint64View(payload.BlobGasUsed.Unwrap()), ExcessBlobGas: zview.Uint64View(payload.ExcessBlobGas.Unwrap()), } var zWithdrawals zcommon.Withdrawals for _, withdrawal := range payload.Withdrawals { zWithdrawal := zcommon.Withdrawal{ Index: zcommon.WithdrawalIndex(withdrawal.Index), ValidatorIndex: zcommon.ValidatorIndex(withdrawal.Validator), Address: zcommon.Eth1Address(withdrawal.Address), Amount: zcommon.Gwei(withdrawal.Amount), } zWithdrawals = append(zWithdrawals, zWithdrawal) } zpayload.Withdrawals = zWithdrawals zRoot := zpayload.HashTreeRoot(spec, hFn) containerRoot := payload.HashTreeRoot() return bytes.Equal(typeRoot[:], containerRoot[:]) && bytes.Equal(typeRoot[:], zRoot[:]) } if err := quick.Check(f, &c); err != nil { t.Error(err) } } ================================================ FILE: testing/simulated/chaos_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "context" "time" "github.com/berachain/beacon-kit/execution/client" "github.com/cometbft/cometbft/abci/types" ) // TestProcessProposal_CrashedExecutionClient_Errors effectively serves as a test for how a valid node would react to // a valid block being proposed but the execution client has crashed. func (s *SimulatedSuite) TestProcessProposal_CrashedExecutionClient_Errors() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens post Deneb1 fork. startTime := time.Now() // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, proposalTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) currentHeight := int64(blockHeight + coreLoopIterations) // Prepare a valid block proposal. proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: proposalTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(proposal) // Reset the log buffer to discard old logs we don't care about. s.LogBuffer.Reset() // Kill the execution client. err = s.ElHandle.Close() s.Require().NoError(err) // Process the proposal containing the valid block. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: proposalTime, }) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) s.Require().Contains(s.LogBuffer.String(), client.ErrBadConnection.Error()) } // TestContextHandling_SIGINT_SafeShutdown mimicks the expected outcome of a SIGINT by calling context cancel and stop services. func (s *SimulatedSuite) TestContextHandling_SIGINT_SafeShutdown() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens post Deneb1 fork. startTime := time.Now() // Run through core loop iterations to bypass any startup edge cases. proposals, _, proposalTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) currentHeight := int64(blockHeight + coreLoopIterations) s.LogBuffer.Reset() // Kill the EL (execution layer) err = s.ElHandle.Close() s.Require().NoError(err) type proposalResult struct { proposal *types.PrepareProposalResponse err error } // Capture result of prepare proposal resultCh := make(chan proposalResult, 1) // Prepare proposal in a separate goroutine since it will block due to retrying on the crashed EL. go func() { proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: proposalTime, ProposerAddress: nodeAddress, }) resultCh <- proposalResult{ proposal: proposal, err: err, } }() // Mimic the behavior of the shutdown function when a SIGINT is observed. s.CtxAppCancelFn() s.TestNode.ServiceRegistry.StopAll() // Wait 2 seconds for PrepareProposal to return its result. select { case res := <-resultCh: s.Require().NoError(res.err) s.Require().Empty(res.proposal) // Shutdown is the last service that is completed and indicates s.Require().Contains(s.LogBuffer.String(), "All services stopped") case <-time.After(2 * time.Second): s.T().Error("PrepareProposal did not finish within 2 seconds after shutdown") } } // TestContextHandling_CancelledContext_Rejected tests that ABCI requests are rejected if the context is cancelled func (s *SimulatedSuite) TestContextHandling_CancelledContext_Rejected() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens post Deneb1 fork. startTime := time.Now() // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, proposalTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) currentHeight := int64(blockHeight + coreLoopIterations) // Kill the EL err = s.ElHandle.Close() s.Require().NoError(err) // Cancel the App s.CtxAppCancelFn() s.LogBuffer.Reset() proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: proposalTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().Empty(proposal) processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: proposalTime, }) s.Require().Error(err, context.Canceled) s.Require().Nil(processResp) finalizeResp, err := s.SimComet.Comet.FinalizeBlock(s.CtxComet, &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: proposalTime, }) s.Require().Error(err, context.Canceled) s.Require().Nil(finalizeResp) _, err = s.SimComet.Comet.Commit(s.CtxComet, &types.CommitRequest{}) s.Require().Error(err, context.Canceled) } ================================================ FILE: testing/simulated/components.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated import ( "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config/spec" "github.com/berachain/beacon-kit/node-core/components" ) func FixedComponents(t *testing.T) []any { t.Helper() c := []any{ components.ProvideAttributesFactory, components.ProvideAvailabilityStore, components.ProvideDepositContract, components.ProvideBlockStore, components.ProvideBlsSigner, components.ProvideBlobProcessor, components.ProvideBlobProofVerifier, components.ProvideChainService, components.ProvideNode, components.ProvideConfig, components.ProvideServerConfig, components.ProvideDepositStore, components.ProvideEngineClient, components.ProvideExecutionEngine, components.ProvideJWTSecret, components.ProvideLocalBuilder, components.ProvideReportingService, components.ProvideServiceRegistry, components.ProvideSidecarFactory, components.ProvideStateProcessor, components.ProvideKVStore, components.ProvideStorageBackend, components.ProvideTelemetrySink, components.ProvideTelemetryService, components.ProvideTrustedSetup, components.ProvideValidatorService, components.ProvideNodeAPIServer, components.ProvideShutDownService, } return c } // ProvideElectraGenesisChainSpec provides a chain spec with pectra as the genesis. func ProvideElectraGenesisChainSpec() (chain.Spec, error) { specData := spec.TestnetChainSpecData() // Both Deneb1 and Electra happen in genesis. specData.GenesisTime = 0 specData.Deneb1ForkTime = 0 specData.ElectraForkTime = 0 specData.Electra1ForkTime = 9223372036854775807 specData.FuluForkTime = 9223372036854775807 // We set slots per epoch to 2 for faster observation of withdrawal behaviour specData.SlotsPerEpoch = 2 // We set this to 4 so tests are faster specData.MinValidatorWithdrawabilityDelay = 4 chainSpec, err := chain.NewSpec(specData) if err != nil { return nil, err } return chainSpec, nil } // ProvideSimulationChainSpec provides a default chain-spec equivalent to testnet. // Bypasses the need for environment variables. func ProvideSimulationChainSpec() (chain.Spec, error) { specData := spec.TestnetChainSpecData() specData.GenesisTime = 0 // Arbitrary number specData.Deneb1ForkTime = 30 // High number as we don't want to activate electra. specData.ElectraForkTime = 9999999999999999 specData.Electra1ForkTime = 9999999999999999 specData.FuluForkTime = 9999999999999999 chainSpec, err := chain.NewSpec(specData) if err != nil { return nil, err } return chainSpec, nil } // ProvidePectraForkTestChainSpec provides a chain spec with pectra at timestamp 10 func ProvidePectraForkTestChainSpec() (chain.Spec, error) { specData := spec.TestnetChainSpecData() specData.GenesisTime = 0 specData.Deneb1ForkTime = 0 specData.ElectraForkTime = 10 specData.Electra1ForkTime = 9223372036854775807 specData.FuluForkTime = 9223372036854775807 chainSpec, err := chain.NewSpec(specData) if err != nil { return nil, err } return chainSpec, nil } // ProvidePectraWithdrawalTestChainSpec provides a chain spec used for withdrawal testing func ProvidePectraWithdrawalTestChainSpec() (chain.Spec, error) { specData := spec.TestnetChainSpecData() specData.GenesisTime = 0 specData.Deneb1ForkTime = 0 specData.ElectraForkTime = 10 specData.Electra1ForkTime = 9223372036854775807 specData.FuluForkTime = 9223372036854775807 // We set slots per epoch to 1 for faster observation of withdrawal behaviour specData.SlotsPerEpoch = 1 // We set this to 4 so tests are faster specData.MinValidatorWithdrawabilityDelay = 4 // Reduced validator set cap so eviction withdrawals are easier to trigger specData.ValidatorSetCap = 1 chainSpec, err := chain.NewSpec(specData) if err != nil { return nil, err } return chainSpec, nil } ================================================ FILE: testing/simulated/el-genesis-files/eth-genesis.json ================================================ { "config": { "chainId": 80069, "homesteadBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "istanbulBlock": 0, "muirGlacierBlock": 0, "berlinBlock": 0, "londonBlock": 0, "arrowGlacierBlock": 0, "grayGlacierBlock": 0, "mergeNetsplitBlock": 0, "shanghaiTime": 0, "cancunTime": 0, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true, "ethash": {}, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 } }, "berachain": { "prague1": { "time": 9223372036854775807, "baseFeeChangeDenominator": 48, "minimumBaseFeeWei": 10000000000, "polDistributorAddress": "0x4200000000000000000000000000000000000042" }, "prague2": { "time": 9223372036854775807, "minimumBaseFeeWei": 0 } } }, "coinbase": "0x0000000000000000000000000000000000000000", "difficulty": "0x0", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", "nonce": "0x0000000000000000", "timestamp": "0x0", "alloc": { "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4": { "balance": "0x123450000000000000000" }, "0x56898d1aFb10cad584961eb96AcD476C6826e41E": { "balance": "0x12345000000000000000000" }, "0x1e2e53c2451d0f9ED4B7952991BE0c95165D5c01": { "balance": "0x12345000000000000000000" }, "0x3bd0E8f1B1E8Ec99a4E1762F4058F9884C93af31": { "balance": "0x12345000000000000000000" }, "0xD073a84e2ccDF91a9025179330438485E886D206": { "balance": "0x12345000000000000000000" }, "0x8a88215ae882dfA519730c40109556c1C235729f": { "balance": "0x12345000000000000000000" }, "0x1a0A57e5e6a66aD732295ddAF0aed286a4e64310": { "balance": "0x12345000000000000000000" }, "0x185F4Eebd01614aE3d12a5E49b184B054C46d37B": { "balance": "0x12345000000000000000000" }, "0xdb96E9cDD1e457b602f97d33e51736D7a5216496": { "balance": "0x12345000000000000000000" }, "0x44a5FBfa7d6f3Fd92cca01f6764509f8Fc33dfa5": { "balance": "0x12345000000000000000000" }, "0x3649839562C8dA64E6215EB0f5371629Ead9729D": { "balance": "0x12345000000000000000000" }, "0x51e15e71c865FE702C9347610667f83658A20e00": { "balance": "0x12345000000000000000000" }, "0xBC9BC89b295a14F3976234Cc37C73e3D286f3a49": { "balance": "0x12345000000000000000000" }, "0x12De044207a90709Ef2602D3D9D945d64dAe6147": { "balance": "0x12345000000000000000000" }, "0x4Afe0DFDAcc91F0fA2AEe39F9eAd66b64d03EbD6": { "balance": "0x12345000000000000000000" }, "0xBC3c03b4185A6F10618CC4E7B9f4AdD59AB5FbbA": { "balance": "0x12345000000000000000000" }, "0xDc6De65f6070b409125217a12Cf576A208Cc1998": { "balance": "0x12345000000000000000000" }, "0xF60fD8632Fc77E19b3A0637d115d0fdd06F36968": { "balance": "0x12345000000000000000000" }, "0xbcC90AD39D377cA0b7b4F36eC463103E2728C33F": { "balance": "0x12345000000000000000000" }, "0x6F69542fC88fF84C480FFf510aB7108120447247": { "balance": "0x12345000000000000000000" }, "0x2f6eB3D9a41157322dE01A6E707F6F118Cb00A7b": { "balance": "0x12345000000000000000000" }, "0x187bE38A1f448b0F42423151A683dCAea949008B": { "balance": "0x12345000000000000000000" }, "0xA1d283f1a11A36D20FF38F29e12CA8F7Cf8709c1": { "balance": "0x12345000000000000000000" }, "0x868a33C94F91398B6245e1f0E4CF128B2F28714B": { "balance": "0x12345000000000000000000" }, "0x67c942Ef50Fc690eA779067a6A0d444a8234baB5": { "balance": "0x12345000000000000000000" }, "0xDE8E0E641E2Fb52c22460e6a1533c6BD13A00B37": { "balance": "0x12345000000000000000000" }, "0x9beFa0FB7a1A9E6cC7596204DbB8962E87091D64": { "balance": "0x12345000000000000000000" }, "0x62cB9bF32EA104f6D5eBf6879e876439f9492E4B": { "balance": "0x12345000000000000000000" }, "0xdb9cB94B166DfdC9F337EA63b32B448d993d7008": { "balance": "0x12345000000000000000000" }, "0x7c4d7dB81c544B768E1f4782011077202B74B5C0": { "balance": "0x12345000000000000000000" }, "0xaEf63D7F7e2637c99FeA1B63366b244B4da12D70": { "balance": "0x12345000000000000000000" }, "0x3DFb4173ec41EB976260fd689E5AB9772C66beaf": { "balance": "0x12345000000000000000000" }, "0x5145b1B855bca67A119CB02A42aF4Bdbc66B725C": { "balance": "0x12345000000000000000000" }, "0xf4b2eb959A4C4b0E148340676999FC0446D446D4": { "balance": "0x12345000000000000000000" }, "0xb86d37333072eFb48cEaa46C67271A27CA5Bda82": { "balance": "0x12345000000000000000000" }, "0x6CBcF4198fDA91D00fD469340E6DF6df086159e3": { "balance": "0x12345000000000000000000" }, "0xE7F444b5f772281384117674002d540131e533Ca": { "balance": "0x12345000000000000000000" }, "0x719Be866A77CeEc1BaC4FD37910c0975eFd52f55": { "balance": "0x12345000000000000000000" }, "0x0e10cDAd84D788843aF48673C5b260A02ef78742": { "balance": "0x12345000000000000000000" }, "0xcB6632daA65e6c921c2963C37320f63f54fC8fE3": { "balance": "0x12345000000000000000000" }, "0xDe5C7198e2416baB7e7a1EA758858Cd7301740bF": { "balance": "0x12345000000000000000000" }, "0x25fc16D8E2314B305dF05C032E617638284801D6": { "balance": "0x12345000000000000000000" }, "0xD2a3b89AE8D2c3bD39E2F24612ecFCD8600360C9": { "balance": "0x12345000000000000000000" }, "0x2F4fD8a82A1400E654eeEC59b0e588445ffE0F96": { "balance": "0x12345000000000000000000" }, "0x10FdFa4EFc83d6CC42F5ef14c13da8b98E458214": { "balance": "0x12345000000000000000000" }, "0x49cE37B2019bb2d0B8b6a094ef87a6Dd625454A0": { "balance": "0x12345000000000000000000" }, "0x800830F031ab1dd5895a5ec5B561427AD18f9ea8": { "balance": "0x12345000000000000000000" }, "0x3124d9885b11B52c56A2aee610AfCf5740d484F0": { "balance": "0x12345000000000000000000" }, "0xA6177defF3b768b1D678EdF7583b8cf210C777c0": { "balance": "0x12345000000000000000000" }, "0xF99139D2FCc5E25F57B0B91fd382a21B3AFF9cbA": { "balance": "0x12345000000000000000000" }, "0xC4DD08191B4d5173e3698491A11e05b63F9Ee097": { "balance": "0x12345000000000000000000" }, "0xB8865B4B8C56861534CC07ebBD2EA569a9a16323": { "balance": "0x12345000000000000000000" }, "0x2B9935698dc5c19Ab7414AE22f27Da5F4478008a": { "balance": "0x12345000000000000000000" }, "0xAC3c80F41C3049A89Aba8072FFbFc38a90fb6D8c": { "balance": "0x12345000000000000000000" }, "0xD6D4Fb22B91FAa54700852a05698B37d45514166": { "balance": "0x12345000000000000000000" }, "0xAf325Ccc92ae883DEF1634D499d8B093192D7a0c": { "balance": "0x12345000000000000000000" }, "0x7469CeEf99FB67e4990c5F1c085a1B39b2902331": { "balance": "0x12345000000000000000000" }, "0x14DA5251a1EB236238969575ccE943e2Fb0f4AA1": { "balance": "0x12345000000000000000000" }, "0xF9f58a87C3f0B3A4a0592938c80C41a7c659f855": { "balance": "0x12345000000000000000000" }, "0x1CF7e940A657eE706718CF180eb21864DE9672C3": { "balance": "0x12345000000000000000000" }, "0x440C37b22e8D7469128Ea7De6ac2f31419B4A8b1": { "balance": "0x12345000000000000000000" }, "0x4bD04ABA9fc709835b1EE4789195d10E9e8E53F5": { "balance": "0x12345000000000000000000" }, "0x4dC3aC871b22F8a98197B0aae976a8dE08e5Bebe": { "balance": "0x12345000000000000000000" }, "0x1f1D0FCa7e19b799c315d4fDf31bA50e6A2AB153": { "balance": "0x12345000000000000000000" }, "0x28879749Dda99387bdB43295B28bdF251d999F3b": { "balance": "0x12345000000000000000000" }, "0xC4eD09A472B82516daa3A4d8D1E38AE94CF4855C": { "balance": "0x12345000000000000000000" }, "0xf22FbA9cBeB75ED353931418E9eca71EF1Ab9921": { "balance": "0x12345000000000000000000" }, "0xC59D8935c0570E75BA0E55E3C661f535C86e368B": { "balance": "0x12345000000000000000000" }, "0xf97a36c417D33D1fC60a9163A8715e1aecb29102": { "balance": "0x12345000000000000000000" }, "0x4245537d9e3fb36fBBf054247FfFB28b0d931503": { "balance": "0x12345000000000000000000" }, "0xFeb1eafa0154D291e28e393FAF10Bc89e5cCbB22": { "balance": "0x12345000000000000000000" }, "0xf11D16e2EE6BefED82Fbca0b005906E09303aB95": { "balance": "0x12345000000000000000000" }, "0x9C75eD1A37ae420b4FC0a1F4c26B673227Fd3AFa": { "balance": "0x12345000000000000000000" }, "0x6a354C708fd248FD778F6adF75E41AA554700F68": { "balance": "0x12345000000000000000000" }, "0xea94749deFcc40dC5992687974b1C84B1bB9D6df": { "balance": "0x12345000000000000000000" }, "0x7689BE67b205EB5d32811d95D60587Eae4F3036F": { "balance": "0x12345000000000000000000" }, "0xdBfb742BD2e0e6E353cb61E75B9e11257aC8fB1A": { "balance": "0x12345000000000000000000" }, "0x2E5f031578e8FF82199aaF16f42c44D43Fe61819": { "balance": "0x12345000000000000000000" }, "0x611a42A2EF62c2461D123e3F0B64b93938bc4781": { "balance": "0x12345000000000000000000" }, "0x1a0c826048DF0E4661E3c53bBd447d497E3f701F": { "balance": "0x12345000000000000000000" }, "0x7f0E54bc3C1a72405646F5dFbBE0D4565c649fe2": { "balance": "0x12345000000000000000000" }, "0x54e1F990Dc0B7367F1E8eD96dA63BC4bca0E8061": { "balance": "0x12345000000000000000000" }, "0xbE651bc261b9Da5499a24Bf4214fD494c6e1F5Ac": { "balance": "0x12345000000000000000000" }, "0xD3c5dAC705289cD005C402C79C8445a47502d8be": { "balance": "0x12345000000000000000000" }, "0xE5981AA0807eb05611cDb666e32e53b2001bd61d": { "balance": "0x12345000000000000000000" }, "0x0fb648Cb08e21602AF61AF53fE104E29d46433F7": { "balance": "0x12345000000000000000000" }, "0x0474f52d25529c4db5f4E72F43303dA71B3541C6": { "balance": "0x12345000000000000000000" }, "0xe3024d098953661638d59E06f7FcD0B61c424854": { "balance": "0x12345000000000000000000" }, "0x8b1e58f651CacaAa40291d2a6E0a6404d7Ed99e6": { "balance": "0x12345000000000000000000" }, "0x8724C57fb8f38A1FccA7177543dd1D8FcD49E5aa": { "balance": "0x12345000000000000000000" }, "0xd0F043dED28773953562f824334C4cbb84210AE7": { "balance": "0x12345000000000000000000" }, "0xE3d2b9191EaBD3636A5dd057D522335cfae8c7CF": { "balance": "0x12345000000000000000000" }, "0x3f51B3BB6A18141282Ba002F7709c7E2f337F961": { "balance": "0x12345000000000000000000" }, "0xf6B6A52aA9BD788837c6682f47ACE009BD84b6fc": { "balance": "0x12345000000000000000000" }, "0x795B761Db5969B7ba53472d5D37c230C859a472F": { "balance": "0x12345000000000000000000" }, "0x7d7f187C2A05cDDCF700dCF2E02c96E7eF03f9B0": { "balance": "0x12345000000000000000000" }, "0x2d88ECD4d8F4b0A954886eE8C0802aE14684cd07": { "balance": "0x12345000000000000000000" }, "0x92B3feac5b7816Dcef96a303c1D5112271A70D2c": { "balance": "0x12345000000000000000000" }, "0x5DD7bc3BEE395831ce499315ecAFE81DE0556F99": { "balance": "0x12345000000000000000000" }, "0x5227aaebCA3E5e893547A667666E2e4e12Ca20e0": { "balance": "0x12345000000000000000000" }, "0x47575DAE85403cD408d4639068D1187C427B9897": { "balance": "0x12345000000000000000000" }, "0xE69ac59e1DF47291AaB8DEc540C796f81De7c892": { "balance": "0x12345000000000000000000" }, "0xb87fb371Bd3C2093b608cd0E7a8dDD60Bb05C995": { "balance": "0x12345000000000000000000" }, "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": { "balance": "0x0", "nonce": "0x1", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500" }, "0x4e59b44847b379578588920cA78FbF26c0B4956C": { "balance": "0x0", "nonce": "0x1", "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3" }, "0x4242424242424242424242424242424242424242": { "balance": "0x0", "nonce": "0x1", "code": "0x608060405260043610610093575f3560e01c8063577212fe11610066578063c53925d91161004c578063c53925d914610231578063e12cf4cb14610250578063fea7ab7714610263575f80fd5b8063577212fe146101cc5780639eaffa96146101ed575f80fd5b806301ffc9a7146100975780632dfdf0b5146100cb5780633523f9bd14610103578063560036ec14610126575b5f80fd5b3480156100a2575f80fd5b506100b66100b1366004610bb7565b610282565b60405190151581526020015b60405180910390f35b3480156100d6575f80fd5b505f546100ea9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100c2565b34801561010e575f80fd5b5061011860015481565b6040519081526020016100c2565b348015610131575f80fd5b50610193610140366004610c2a565b80516020818301810180516003825292820191909301209152546bffffffffffffffffffffffff8116906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1682565b604080516bffffffffffffffffffffffff909316835273ffffffffffffffffffffffffffffffffffffffff9091166020830152016100c2565b3480156101d7575f80fd5b506101eb6101e6366004610d5f565b61031a565b005b3480156101f8575f80fd5b5061020c610207366004610d5f565b6103e7565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c2565b34801561023c575f80fd5b506101eb61024b366004610d5f565b610428565b6101eb61025e366004610dc1565b61063d565b34801561026e575f80fd5b506101eb61027d366004610e70565b61095c565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061031457507fffffffff0000000000000000000000000000000000000000000000000000000082167f136f920d00000000000000000000000000000000000000000000000000000000145b92915050565b6002828260405161032c929190610ec0565b908152604051908190036020019020543373ffffffffffffffffffffffffffffffffffffffff90911614610383576103837f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b60038282604051610395929190610ec0565b9081526040519081900360200181205f90556103b49083908390610ec0565b604051908190038120907f1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db905f90a25050565b5f600283836040516103fa929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f6003838360405161043b929190610ec0565b908152604051908190036020019020805490915073ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000820416906bffffffffffffffffffffffff163382146104b4576104b47f819a0d0b00000000000000000000000000000000000000000000000000000000610afc565b6bffffffffffffffffffffffff42166104d06201518083610efc565b6bffffffffffffffffffffffff16111561050d5761050d7fe8966d7a00000000000000000000000000000000000000000000000000000000610afc565b5f60028686604051610520929190610ec0565b9081526040519081900360200181205473ffffffffffffffffffffffffffffffffffffffff169150839060029061055a9089908990610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556003906105bf9088908890610ec0565b9081526040519081900360200181205f90556105de9087908790610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a2505050505050565b6030861461066e5761066e7f9f10647200000000000000000000000000000000000000000000000000000000610afc565b6020841461069f5761069f7fb39bca1600000000000000000000000000000000000000000000000000000000610afc565b606082146106d0576106d07f4be6321b00000000000000000000000000000000000000000000000000000000610afc565b5f73ffffffffffffffffffffffffffffffffffffffff16600288886040516106f9929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16036108375773ffffffffffffffffffffffffffffffffffffffff8116610768576107687f51969a7a00000000000000000000000000000000000000000000000000000000610afc565b806002888860405161077b929190610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556107dd9088908890610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff841683525f6020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a261087c565b73ffffffffffffffffffffffffffffffffffffffff81161561087c5761087c7fc4142b4100000000000000000000000000000000000000000000000000000000610afc565b5f610885610b04565b90506509184e72a00067ffffffffffffffff821610156108c8576108c87f0e1eddda00000000000000000000000000000000000000000000000000000000610afc565b5f80547f68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46918a918a918a918a9187918b918b9167ffffffffffffffff16908061091083610f20565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405161094a989796959493929190610f93565b60405180910390a15050505050505050565b5f6002848460405161096f929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690503381146109c7576109c77f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b73ffffffffffffffffffffffffffffffffffffffff8216610a0b57610a0b7fd92e233d00000000000000000000000000000000000000000000000000000000610afc565b5f60038585604051610a1e929190610ec0565b908152604051908190036020018120426bffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff86166c01000000000000000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000161781559150610a969086908690610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff8681168452851660208401524283830152905190917f7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f919081900360600190a25050505050565b805f5260045ffd5b5f610b13633b9aca003461102b565b15610b4157610b417f40567b3800000000000000000000000000000000000000000000000000000000610afc565b5f610b50633b9aca003461103e565b905067ffffffffffffffff811115610b8b57610b8b7f2aa6673400000000000000000000000000000000000000000000000000000000610afc565b610b955f34610b9a565b919050565b5f385f3884865af1610bb35763b12d13eb5f526004601cfd5b5050565b5f60208284031215610bc7575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610bf6575f80fd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215610c3a575f80fd5b813567ffffffffffffffff811115610c50575f80fd5b8201601f81018413610c60575f80fd5b803567ffffffffffffffff811115610c7a57610c7a610bfd565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715610ce657610ce6610bfd565b604052818152828201602001861015610cfd575f80fd5b816020840160208301375f91810160200191909152949350505050565b5f8083601f840112610d2a575f80fd5b50813567ffffffffffffffff811115610d41575f80fd5b602083019150836020828501011115610d58575f80fd5b9250929050565b5f8060208385031215610d70575f80fd5b823567ffffffffffffffff811115610d86575f80fd5b610d9285828601610d1a565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b95575f80fd5b5f805f805f805f6080888a031215610dd7575f80fd5b873567ffffffffffffffff811115610ded575f80fd5b610df98a828b01610d1a565b909850965050602088013567ffffffffffffffff811115610e18575f80fd5b610e248a828b01610d1a565b909650945050604088013567ffffffffffffffff811115610e43575f80fd5b610e4f8a828b01610d1a565b9094509250610e62905060608901610d9e565b905092959891949750929550565b5f805f60408486031215610e82575f80fd5b833567ffffffffffffffff811115610e98575f80fd5b610ea486828701610d1a565b9094509250610eb7905060208501610d9e565b90509250925092565b818382375f9101908152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6bffffffffffffffffffffffff818116838216019081111561031457610314610ecf565b5f67ffffffffffffffff821667ffffffffffffffff8103610f4357610f43610ecf565b60010192915050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60a081525f610fa660a083018a8c610f4c565b8281036020840152610fb981898b610f4c565b905067ffffffffffffffff871660408401528281036060840152610fde818688610f4c565b91505067ffffffffffffffff831660808301529998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261103957611039610ffe565b500690565b5f8261104c5761104c610ffe565b50049056fea164736f6c634300081a000a" }, "0x4200000000000000000000000000000000000042": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063163db71b1461003857806360644a6b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b610065610060366004610137565b610067565b005b336002600160a01b031461008e57604051632f3a162d60e11b815260040160405180910390fd5b5f8054908061009c836101a5565b909155505060405163999da65b60e01b81526043602160991b019063999da65b906100cd90859085906004016101c9565b5f604051808303815f87803b1580156100e4575f80fd5b505af11580156100f6573d5f803e3d5ffd5b505050507f60b106db8802e863a4a9dc4af78cb0dd63feb55ad4ee60f0453c13309bfdbdd4828260405161012b9291906101c9565b60405180910390a15050565b5f8060208385031215610148575f80fd5b823567ffffffffffffffff81111561015e575f80fd5b8301601f8101851361016e575f80fd5b803567ffffffffffffffff811115610184575f80fd5b856020828401011115610195575f80fd5b6020919091019590945092505050565b5f600182016101c257634e487b7160e01b5f52601160045260245ffd5b5060010190565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c2930abe9036c3b4b2592fab2f2fd516d3698f5c696d82745ddc0af43f7096a764736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" }, "0x4200000000000000000000000000000000000043": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c80634b28f9a214610038578063999da65b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b6100656100603660046100b8565b610067565b005b5f8054908061007583610126565b91905055507fb3a8fa51f8d3759f320e88b7f8d3fb73a2a51b31b3324b37833c4816cf41e7c45f546040516100ac91815260200190565b60405180910390a15050565b5f80602083850312156100c9575f80fd5b823567ffffffffffffffff8111156100df575f80fd5b8301601f810185136100ef575f80fd5b803567ffffffffffffffff811115610105575f80fd5b856020828401011115610116575f80fd5b6020919091019590945092505050565b5f6001820161014357634e487b7160e01b5f52601160045260245ffd5b506001019056fea2646970667358221220350dbb7eed9e4d6e4ff72594b0582b0b2e4c1d6b11c3e5ad382201b47a638cc664736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" } } } ================================================ FILE: testing/simulated/el-genesis-files/pectra-eth-genesis.json ================================================ { "config": { "chainId": 80069, "homesteadBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "istanbulBlock": 0, "muirGlacierBlock": 0, "berlinBlock": 0, "londonBlock": 0, "arrowGlacierBlock": 0, "grayGlacierBlock": 0, "mergeNetsplitBlock": 0, "shanghaiTime": 0, "cancunTime": 0, "pragueTime": 0, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true, "ethash": {}, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 }, "prague": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 } }, "berachain": { "prague1": { "time": 9223372036854775807, "baseFeeChangeDenominator": 48, "minimumBaseFeeWei": 10000000000, "polDistributorAddress": "0x4200000000000000000000000000000000000042" }, "prague2": { "time": 9223372036854775807, "minimumBaseFeeWei": 0 } } }, "coinbase": "0x0000000000000000000000000000000000000000", "difficulty": "0x0", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", "nonce": "0x0000000000000000", "timestamp": "0x0", "alloc": { "0x00000961Ef480Eb55e80D19ad83579A64c007002": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd", "nonce": "0x1", "balance": "0x0", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } }, "0x0000BBdDc7CE488642fb579F8B00f3a590007251": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", "nonce": "0x1", "balance": "0x0", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } }, "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4": { "balance": "0x123450000000000000000" }, "0x56898d1aFb10cad584961eb96AcD476C6826e41E": { "balance": "0x12345000000000000000000" }, "0x1e2e53c2451d0f9ED4B7952991BE0c95165D5c01": { "balance": "0x12345000000000000000000" }, "0x3bd0E8f1B1E8Ec99a4E1762F4058F9884C93af31": { "balance": "0x12345000000000000000000" }, "0xD073a84e2ccDF91a9025179330438485E886D206": { "balance": "0x12345000000000000000000" }, "0x8a88215ae882dfA519730c40109556c1C235729f": { "balance": "0x12345000000000000000000" }, "0x1a0A57e5e6a66aD732295ddAF0aed286a4e64310": { "balance": "0x12345000000000000000000" }, "0x185F4Eebd01614aE3d12a5E49b184B054C46d37B": { "balance": "0x12345000000000000000000" }, "0xdb96E9cDD1e457b602f97d33e51736D7a5216496": { "balance": "0x12345000000000000000000" }, "0x44a5FBfa7d6f3Fd92cca01f6764509f8Fc33dfa5": { "balance": "0x12345000000000000000000" }, "0x3649839562C8dA64E6215EB0f5371629Ead9729D": { "balance": "0x12345000000000000000000" }, "0x51e15e71c865FE702C9347610667f83658A20e00": { "balance": "0x12345000000000000000000" }, "0xBC9BC89b295a14F3976234Cc37C73e3D286f3a49": { "balance": "0x12345000000000000000000" }, "0x12De044207a90709Ef2602D3D9D945d64dAe6147": { "balance": "0x12345000000000000000000" }, "0x4Afe0DFDAcc91F0fA2AEe39F9eAd66b64d03EbD6": { "balance": "0x12345000000000000000000" }, "0xBC3c03b4185A6F10618CC4E7B9f4AdD59AB5FbbA": { "balance": "0x12345000000000000000000" }, "0xDc6De65f6070b409125217a12Cf576A208Cc1998": { "balance": "0x12345000000000000000000" }, "0xF60fD8632Fc77E19b3A0637d115d0fdd06F36968": { "balance": "0x12345000000000000000000" }, "0xbcC90AD39D377cA0b7b4F36eC463103E2728C33F": { "balance": "0x12345000000000000000000" }, "0x6F69542fC88fF84C480FFf510aB7108120447247": { "balance": "0x12345000000000000000000" }, "0x2f6eB3D9a41157322dE01A6E707F6F118Cb00A7b": { "balance": "0x12345000000000000000000" }, "0x187bE38A1f448b0F42423151A683dCAea949008B": { "balance": "0x12345000000000000000000" }, "0xA1d283f1a11A36D20FF38F29e12CA8F7Cf8709c1": { "balance": "0x12345000000000000000000" }, "0x868a33C94F91398B6245e1f0E4CF128B2F28714B": { "balance": "0x12345000000000000000000" }, "0x67c942Ef50Fc690eA779067a6A0d444a8234baB5": { "balance": "0x12345000000000000000000" }, "0xDE8E0E641E2Fb52c22460e6a1533c6BD13A00B37": { "balance": "0x12345000000000000000000" }, "0x9beFa0FB7a1A9E6cC7596204DbB8962E87091D64": { "balance": "0x12345000000000000000000" }, "0x62cB9bF32EA104f6D5eBf6879e876439f9492E4B": { "balance": "0x12345000000000000000000" }, "0xdb9cB94B166DfdC9F337EA63b32B448d993d7008": { "balance": "0x12345000000000000000000" }, "0x7c4d7dB81c544B768E1f4782011077202B74B5C0": { "balance": "0x12345000000000000000000" }, "0xaEf63D7F7e2637c99FeA1B63366b244B4da12D70": { "balance": "0x12345000000000000000000" }, "0x3DFb4173ec41EB976260fd689E5AB9772C66beaf": { "balance": "0x12345000000000000000000" }, "0x5145b1B855bca67A119CB02A42aF4Bdbc66B725C": { "balance": "0x12345000000000000000000" }, "0xf4b2eb959A4C4b0E148340676999FC0446D446D4": { "balance": "0x12345000000000000000000" }, "0xb86d37333072eFb48cEaa46C67271A27CA5Bda82": { "balance": "0x12345000000000000000000" }, "0x6CBcF4198fDA91D00fD469340E6DF6df086159e3": { "balance": "0x12345000000000000000000" }, "0xE7F444b5f772281384117674002d540131e533Ca": { "balance": "0x12345000000000000000000" }, "0x719Be866A77CeEc1BaC4FD37910c0975eFd52f55": { "balance": "0x12345000000000000000000" }, "0x0e10cDAd84D788843aF48673C5b260A02ef78742": { "balance": "0x12345000000000000000000" }, "0xcB6632daA65e6c921c2963C37320f63f54fC8fE3": { "balance": "0x12345000000000000000000" }, "0xDe5C7198e2416baB7e7a1EA758858Cd7301740bF": { "balance": "0x12345000000000000000000" }, "0x25fc16D8E2314B305dF05C032E617638284801D6": { "balance": "0x12345000000000000000000" }, "0xD2a3b89AE8D2c3bD39E2F24612ecFCD8600360C9": { "balance": "0x12345000000000000000000" }, "0x2F4fD8a82A1400E654eeEC59b0e588445ffE0F96": { "balance": "0x12345000000000000000000" }, "0x10FdFa4EFc83d6CC42F5ef14c13da8b98E458214": { "balance": "0x12345000000000000000000" }, "0x49cE37B2019bb2d0B8b6a094ef87a6Dd625454A0": { "balance": "0x12345000000000000000000" }, "0x800830F031ab1dd5895a5ec5B561427AD18f9ea8": { "balance": "0x12345000000000000000000" }, "0x3124d9885b11B52c56A2aee610AfCf5740d484F0": { "balance": "0x12345000000000000000000" }, "0xA6177defF3b768b1D678EdF7583b8cf210C777c0": { "balance": "0x12345000000000000000000" }, "0xF99139D2FCc5E25F57B0B91fd382a21B3AFF9cbA": { "balance": "0x12345000000000000000000" }, "0xC4DD08191B4d5173e3698491A11e05b63F9Ee097": { "balance": "0x12345000000000000000000" }, "0xB8865B4B8C56861534CC07ebBD2EA569a9a16323": { "balance": "0x12345000000000000000000" }, "0x2B9935698dc5c19Ab7414AE22f27Da5F4478008a": { "balance": "0x12345000000000000000000" }, "0xAC3c80F41C3049A89Aba8072FFbFc38a90fb6D8c": { "balance": "0x12345000000000000000000" }, "0xD6D4Fb22B91FAa54700852a05698B37d45514166": { "balance": "0x12345000000000000000000" }, "0xAf325Ccc92ae883DEF1634D499d8B093192D7a0c": { "balance": "0x12345000000000000000000" }, "0x7469CeEf99FB67e4990c5F1c085a1B39b2902331": { "balance": "0x12345000000000000000000" }, "0x14DA5251a1EB236238969575ccE943e2Fb0f4AA1": { "balance": "0x12345000000000000000000" }, "0xF9f58a87C3f0B3A4a0592938c80C41a7c659f855": { "balance": "0x12345000000000000000000" }, "0x1CF7e940A657eE706718CF180eb21864DE9672C3": { "balance": "0x12345000000000000000000" }, "0x440C37b22e8D7469128Ea7De6ac2f31419B4A8b1": { "balance": "0x12345000000000000000000" }, "0x4bD04ABA9fc709835b1EE4789195d10E9e8E53F5": { "balance": "0x12345000000000000000000" }, "0x4dC3aC871b22F8a98197B0aae976a8dE08e5Bebe": { "balance": "0x12345000000000000000000" }, "0x1f1D0FCa7e19b799c315d4fDf31bA50e6A2AB153": { "balance": "0x12345000000000000000000" }, "0x28879749Dda99387bdB43295B28bdF251d999F3b": { "balance": "0x12345000000000000000000" }, "0xC4eD09A472B82516daa3A4d8D1E38AE94CF4855C": { "balance": "0x12345000000000000000000" }, "0xf22FbA9cBeB75ED353931418E9eca71EF1Ab9921": { "balance": "0x12345000000000000000000" }, "0xC59D8935c0570E75BA0E55E3C661f535C86e368B": { "balance": "0x12345000000000000000000" }, "0xf97a36c417D33D1fC60a9163A8715e1aecb29102": { "balance": "0x12345000000000000000000" }, "0x4245537d9e3fb36fBBf054247FfFB28b0d931503": { "balance": "0x12345000000000000000000" }, "0xFeb1eafa0154D291e28e393FAF10Bc89e5cCbB22": { "balance": "0x12345000000000000000000" }, "0xf11D16e2EE6BefED82Fbca0b005906E09303aB95": { "balance": "0x12345000000000000000000" }, "0x9C75eD1A37ae420b4FC0a1F4c26B673227Fd3AFa": { "balance": "0x12345000000000000000000" }, "0x6a354C708fd248FD778F6adF75E41AA554700F68": { "balance": "0x12345000000000000000000" }, "0xea94749deFcc40dC5992687974b1C84B1bB9D6df": { "balance": "0x12345000000000000000000" }, "0x7689BE67b205EB5d32811d95D60587Eae4F3036F": { "balance": "0x12345000000000000000000" }, "0xdBfb742BD2e0e6E353cb61E75B9e11257aC8fB1A": { "balance": "0x12345000000000000000000" }, "0x2E5f031578e8FF82199aaF16f42c44D43Fe61819": { "balance": "0x12345000000000000000000" }, "0x611a42A2EF62c2461D123e3F0B64b93938bc4781": { "balance": "0x12345000000000000000000" }, "0x1a0c826048DF0E4661E3c53bBd447d497E3f701F": { "balance": "0x12345000000000000000000" }, "0x7f0E54bc3C1a72405646F5dFbBE0D4565c649fe2": { "balance": "0x12345000000000000000000" }, "0x54e1F990Dc0B7367F1E8eD96dA63BC4bca0E8061": { "balance": "0x12345000000000000000000" }, "0xbE651bc261b9Da5499a24Bf4214fD494c6e1F5Ac": { "balance": "0x12345000000000000000000" }, "0xD3c5dAC705289cD005C402C79C8445a47502d8be": { "balance": "0x12345000000000000000000" }, "0xE5981AA0807eb05611cDb666e32e53b2001bd61d": { "balance": "0x12345000000000000000000" }, "0x0fb648Cb08e21602AF61AF53fE104E29d46433F7": { "balance": "0x12345000000000000000000" }, "0x0474f52d25529c4db5f4E72F43303dA71B3541C6": { "balance": "0x12345000000000000000000" }, "0xe3024d098953661638d59E06f7FcD0B61c424854": { "balance": "0x12345000000000000000000" }, "0x8b1e58f651CacaAa40291d2a6E0a6404d7Ed99e6": { "balance": "0x12345000000000000000000" }, "0x8724C57fb8f38A1FccA7177543dd1D8FcD49E5aa": { "balance": "0x12345000000000000000000" }, "0xd0F043dED28773953562f824334C4cbb84210AE7": { "balance": "0x12345000000000000000000" }, "0xE3d2b9191EaBD3636A5dd057D522335cfae8c7CF": { "balance": "0x12345000000000000000000" }, "0x3f51B3BB6A18141282Ba002F7709c7E2f337F961": { "balance": "0x12345000000000000000000" }, "0xf6B6A52aA9BD788837c6682f47ACE009BD84b6fc": { "balance": "0x12345000000000000000000" }, "0x795B761Db5969B7ba53472d5D37c230C859a472F": { "balance": "0x12345000000000000000000" }, "0x7d7f187C2A05cDDCF700dCF2E02c96E7eF03f9B0": { "balance": "0x12345000000000000000000" }, "0x2d88ECD4d8F4b0A954886eE8C0802aE14684cd07": { "balance": "0x12345000000000000000000" }, "0x92B3feac5b7816Dcef96a303c1D5112271A70D2c": { "balance": "0x12345000000000000000000" }, "0x5DD7bc3BEE395831ce499315ecAFE81DE0556F99": { "balance": "0x12345000000000000000000" }, "0x5227aaebCA3E5e893547A667666E2e4e12Ca20e0": { "balance": "0x12345000000000000000000" }, "0x47575DAE85403cD408d4639068D1187C427B9897": { "balance": "0x12345000000000000000000" }, "0xE69ac59e1DF47291AaB8DEc540C796f81De7c892": { "balance": "0x12345000000000000000000" }, "0xb87fb371Bd3C2093b608cd0E7a8dDD60Bb05C995": { "balance": "0x12345000000000000000000" }, "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": { "balance": "0x0", "nonce": "0x1", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500" }, "0x4e59b44847b379578588920cA78FbF26c0B4956C": { "balance": "0x0", "nonce": "0x1", "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3" }, "0x4242424242424242424242424242424242424242": { "balance": "0x0", "nonce": "0x1", "code": "0x608060405260043610610093575f3560e01c8063577212fe11610066578063c53925d91161004c578063c53925d914610231578063e12cf4cb14610250578063fea7ab7714610263575f80fd5b8063577212fe146101cc5780639eaffa96146101ed575f80fd5b806301ffc9a7146100975780632dfdf0b5146100cb5780633523f9bd14610103578063560036ec14610126575b5f80fd5b3480156100a2575f80fd5b506100b66100b1366004610bb7565b610282565b60405190151581526020015b60405180910390f35b3480156100d6575f80fd5b505f546100ea9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100c2565b34801561010e575f80fd5b5061011860015481565b6040519081526020016100c2565b348015610131575f80fd5b50610193610140366004610c2a565b80516020818301810180516003825292820191909301209152546bffffffffffffffffffffffff8116906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1682565b604080516bffffffffffffffffffffffff909316835273ffffffffffffffffffffffffffffffffffffffff9091166020830152016100c2565b3480156101d7575f80fd5b506101eb6101e6366004610d5f565b61031a565b005b3480156101f8575f80fd5b5061020c610207366004610d5f565b6103e7565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c2565b34801561023c575f80fd5b506101eb61024b366004610d5f565b610428565b6101eb61025e366004610dc1565b61063d565b34801561026e575f80fd5b506101eb61027d366004610e70565b61095c565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061031457507fffffffff0000000000000000000000000000000000000000000000000000000082167f136f920d00000000000000000000000000000000000000000000000000000000145b92915050565b6002828260405161032c929190610ec0565b908152604051908190036020019020543373ffffffffffffffffffffffffffffffffffffffff90911614610383576103837f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b60038282604051610395929190610ec0565b9081526040519081900360200181205f90556103b49083908390610ec0565b604051908190038120907f1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db905f90a25050565b5f600283836040516103fa929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f6003838360405161043b929190610ec0565b908152604051908190036020019020805490915073ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000820416906bffffffffffffffffffffffff163382146104b4576104b47f819a0d0b00000000000000000000000000000000000000000000000000000000610afc565b6bffffffffffffffffffffffff42166104d06201518083610efc565b6bffffffffffffffffffffffff16111561050d5761050d7fe8966d7a00000000000000000000000000000000000000000000000000000000610afc565b5f60028686604051610520929190610ec0565b9081526040519081900360200181205473ffffffffffffffffffffffffffffffffffffffff169150839060029061055a9089908990610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556003906105bf9088908890610ec0565b9081526040519081900360200181205f90556105de9087908790610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a2505050505050565b6030861461066e5761066e7f9f10647200000000000000000000000000000000000000000000000000000000610afc565b6020841461069f5761069f7fb39bca1600000000000000000000000000000000000000000000000000000000610afc565b606082146106d0576106d07f4be6321b00000000000000000000000000000000000000000000000000000000610afc565b5f73ffffffffffffffffffffffffffffffffffffffff16600288886040516106f9929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16036108375773ffffffffffffffffffffffffffffffffffffffff8116610768576107687f51969a7a00000000000000000000000000000000000000000000000000000000610afc565b806002888860405161077b929190610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556107dd9088908890610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff841683525f6020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a261087c565b73ffffffffffffffffffffffffffffffffffffffff81161561087c5761087c7fc4142b4100000000000000000000000000000000000000000000000000000000610afc565b5f610885610b04565b90506509184e72a00067ffffffffffffffff821610156108c8576108c87f0e1eddda00000000000000000000000000000000000000000000000000000000610afc565b5f80547f68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46918a918a918a918a9187918b918b9167ffffffffffffffff16908061091083610f20565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405161094a989796959493929190610f93565b60405180910390a15050505050505050565b5f6002848460405161096f929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690503381146109c7576109c77f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b73ffffffffffffffffffffffffffffffffffffffff8216610a0b57610a0b7fd92e233d00000000000000000000000000000000000000000000000000000000610afc565b5f60038585604051610a1e929190610ec0565b908152604051908190036020018120426bffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff86166c01000000000000000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000161781559150610a969086908690610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff8681168452851660208401524283830152905190917f7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f919081900360600190a25050505050565b805f5260045ffd5b5f610b13633b9aca003461102b565b15610b4157610b417f40567b3800000000000000000000000000000000000000000000000000000000610afc565b5f610b50633b9aca003461103e565b905067ffffffffffffffff811115610b8b57610b8b7f2aa6673400000000000000000000000000000000000000000000000000000000610afc565b610b955f34610b9a565b919050565b5f385f3884865af1610bb35763b12d13eb5f526004601cfd5b5050565b5f60208284031215610bc7575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610bf6575f80fd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215610c3a575f80fd5b813567ffffffffffffffff811115610c50575f80fd5b8201601f81018413610c60575f80fd5b803567ffffffffffffffff811115610c7a57610c7a610bfd565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715610ce657610ce6610bfd565b604052818152828201602001861015610cfd575f80fd5b816020840160208301375f91810160200191909152949350505050565b5f8083601f840112610d2a575f80fd5b50813567ffffffffffffffff811115610d41575f80fd5b602083019150836020828501011115610d58575f80fd5b9250929050565b5f8060208385031215610d70575f80fd5b823567ffffffffffffffff811115610d86575f80fd5b610d9285828601610d1a565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b95575f80fd5b5f805f805f805f6080888a031215610dd7575f80fd5b873567ffffffffffffffff811115610ded575f80fd5b610df98a828b01610d1a565b909850965050602088013567ffffffffffffffff811115610e18575f80fd5b610e248a828b01610d1a565b909650945050604088013567ffffffffffffffff811115610e43575f80fd5b610e4f8a828b01610d1a565b9094509250610e62905060608901610d9e565b905092959891949750929550565b5f805f60408486031215610e82575f80fd5b833567ffffffffffffffff811115610e98575f80fd5b610ea486828701610d1a565b9094509250610eb7905060208501610d9e565b90509250925092565b818382375f9101908152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6bffffffffffffffffffffffff818116838216019081111561031457610314610ecf565b5f67ffffffffffffffff821667ffffffffffffffff8103610f4357610f43610ecf565b60010192915050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60a081525f610fa660a083018a8c610f4c565b8281036020840152610fb981898b610f4c565b905067ffffffffffffffff871660408401528281036060840152610fde818688610f4c565b91505067ffffffffffffffff831660808301529998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261103957611039610ffe565b500690565b5f8261104c5761104c610ffe565b50049056fea164736f6c634300081a000a" }, "0x4200000000000000000000000000000000000042": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063163db71b1461003857806360644a6b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b610065610060366004610137565b610067565b005b336002600160a01b031461008e57604051632f3a162d60e11b815260040160405180910390fd5b5f8054908061009c836101a5565b909155505060405163999da65b60e01b81526043602160991b019063999da65b906100cd90859085906004016101c9565b5f604051808303815f87803b1580156100e4575f80fd5b505af11580156100f6573d5f803e3d5ffd5b505050507f60b106db8802e863a4a9dc4af78cb0dd63feb55ad4ee60f0453c13309bfdbdd4828260405161012b9291906101c9565b60405180910390a15050565b5f8060208385031215610148575f80fd5b823567ffffffffffffffff81111561015e575f80fd5b8301601f8101851361016e575f80fd5b803567ffffffffffffffff811115610184575f80fd5b856020828401011115610195575f80fd5b6020919091019590945092505050565b5f600182016101c257634e487b7160e01b5f52601160045260245ffd5b5060010190565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c2930abe9036c3b4b2592fab2f2fd516d3698f5c696d82745ddc0af43f7096a764736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" }, "0x4200000000000000000000000000000000000043": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c80634b28f9a214610038578063999da65b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b6100656100603660046100b8565b610067565b005b5f8054908061007583610126565b91905055507fb3a8fa51f8d3759f320e88b7f8d3fb73a2a51b31b3324b37833c4816cf41e7c45f546040516100ac91815260200190565b60405180910390a15050565b5f80602083850312156100c9575f80fd5b823567ffffffffffffffff8111156100df575f80fd5b8301601f810185136100ef575f80fd5b803567ffffffffffffffff811115610105575f80fd5b856020828401011115610116575f80fd5b6020919091019590945092505050565b5f6001820161014357634e487b7160e01b5f52601160045260245ffd5b506001019056fea2646970667358221220350dbb7eed9e4d6e4ff72594b0582b0b2e4c1d6b11c3e5ad382201b47a638cc664736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" } } } ================================================ FILE: testing/simulated/el-genesis-files/pectra-fork-genesis.json ================================================ { "config": { "chainId": 80069, "homesteadBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "istanbulBlock": 0, "muirGlacierBlock": 0, "berlinBlock": 0, "londonBlock": 0, "arrowGlacierBlock": 0, "grayGlacierBlock": 0, "mergeNetsplitBlock": 0, "shanghaiTime": 0, "cancunTime": 0, "pragueTime": 10, "terminalTotalDifficulty": 0, "terminalTotalDifficultyPassed": true, "ethash": {}, "blobSchedule": { "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 }, "prague": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 } }, "berachain": { "prague1": { "time": 9223372036854775807, "baseFeeChangeDenominator": 48, "minimumBaseFeeWei": 10000000000, "polDistributorAddress": "0x4200000000000000000000000000000000000042" }, "prague2": { "time": 9223372036854775807, "minimumBaseFeeWei": 0 } } }, "coinbase": "0x0000000000000000000000000000000000000000", "difficulty": "0x0", "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000658bdf435d810c91414ec09147daa6db624063790000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "gasLimit": "0x1c9c380", "nonce": "0x0000000000000000", "timestamp": "0x0", "alloc": { "0x00000961Ef480Eb55e80D19ad83579A64c007002": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd", "nonce": "0x1", "balance": "0x0", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } }, "0x0000BBdDc7CE488642fb579F8B00f3a590007251": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd", "nonce": "0x1", "balance": "0x0", "storage": { "0x0000000000000000000000000000000000000000000000000000000000000000": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" } }, "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4": { "balance": "0x84595161401484a000000" }, "0x56898d1aFb10cad584961eb96AcD476C6826e41E": { "balance": "0x12345000000000000000000" }, "0x1e2e53c2451d0f9ED4B7952991BE0c95165D5c01": { "balance": "0x12345000000000000000000" }, "0x3bd0E8f1B1E8Ec99a4E1762F4058F9884C93af31": { "balance": "0x12345000000000000000000" }, "0xD073a84e2ccDF91a9025179330438485E886D206": { "balance": "0x12345000000000000000000" }, "0x8a88215ae882dfA519730c40109556c1C235729f": { "balance": "0x12345000000000000000000" }, "0x1a0A57e5e6a66aD732295ddAF0aed286a4e64310": { "balance": "0x12345000000000000000000" }, "0x185F4Eebd01614aE3d12a5E49b184B054C46d37B": { "balance": "0x12345000000000000000000" }, "0xdb96E9cDD1e457b602f97d33e51736D7a5216496": { "balance": "0x12345000000000000000000" }, "0x44a5FBfa7d6f3Fd92cca01f6764509f8Fc33dfa5": { "balance": "0x12345000000000000000000" }, "0x3649839562C8dA64E6215EB0f5371629Ead9729D": { "balance": "0x12345000000000000000000" }, "0x51e15e71c865FE702C9347610667f83658A20e00": { "balance": "0x12345000000000000000000" }, "0xBC9BC89b295a14F3976234Cc37C73e3D286f3a49": { "balance": "0x12345000000000000000000" }, "0x12De044207a90709Ef2602D3D9D945d64dAe6147": { "balance": "0x12345000000000000000000" }, "0x4Afe0DFDAcc91F0fA2AEe39F9eAd66b64d03EbD6": { "balance": "0x12345000000000000000000" }, "0xBC3c03b4185A6F10618CC4E7B9f4AdD59AB5FbbA": { "balance": "0x12345000000000000000000" }, "0xDc6De65f6070b409125217a12Cf576A208Cc1998": { "balance": "0x12345000000000000000000" }, "0xF60fD8632Fc77E19b3A0637d115d0fdd06F36968": { "balance": "0x12345000000000000000000" }, "0xbcC90AD39D377cA0b7b4F36eC463103E2728C33F": { "balance": "0x12345000000000000000000" }, "0x6F69542fC88fF84C480FFf510aB7108120447247": { "balance": "0x12345000000000000000000" }, "0x2f6eB3D9a41157322dE01A6E707F6F118Cb00A7b": { "balance": "0x12345000000000000000000" }, "0x187bE38A1f448b0F42423151A683dCAea949008B": { "balance": "0x12345000000000000000000" }, "0xA1d283f1a11A36D20FF38F29e12CA8F7Cf8709c1": { "balance": "0x12345000000000000000000" }, "0x868a33C94F91398B6245e1f0E4CF128B2F28714B": { "balance": "0x12345000000000000000000" }, "0x67c942Ef50Fc690eA779067a6A0d444a8234baB5": { "balance": "0x12345000000000000000000" }, "0xDE8E0E641E2Fb52c22460e6a1533c6BD13A00B37": { "balance": "0x12345000000000000000000" }, "0x9beFa0FB7a1A9E6cC7596204DbB8962E87091D64": { "balance": "0x12345000000000000000000" }, "0x62cB9bF32EA104f6D5eBf6879e876439f9492E4B": { "balance": "0x12345000000000000000000" }, "0xdb9cB94B166DfdC9F337EA63b32B448d993d7008": { "balance": "0x12345000000000000000000" }, "0x7c4d7dB81c544B768E1f4782011077202B74B5C0": { "balance": "0x12345000000000000000000" }, "0xaEf63D7F7e2637c99FeA1B63366b244B4da12D70": { "balance": "0x12345000000000000000000" }, "0x3DFb4173ec41EB976260fd689E5AB9772C66beaf": { "balance": "0x12345000000000000000000" }, "0x5145b1B855bca67A119CB02A42aF4Bdbc66B725C": { "balance": "0x12345000000000000000000" }, "0xf4b2eb959A4C4b0E148340676999FC0446D446D4": { "balance": "0x12345000000000000000000" }, "0xb86d37333072eFb48cEaa46C67271A27CA5Bda82": { "balance": "0x12345000000000000000000" }, "0x6CBcF4198fDA91D00fD469340E6DF6df086159e3": { "balance": "0x12345000000000000000000" }, "0xE7F444b5f772281384117674002d540131e533Ca": { "balance": "0x12345000000000000000000" }, "0x719Be866A77CeEc1BaC4FD37910c0975eFd52f55": { "balance": "0x12345000000000000000000" }, "0x0e10cDAd84D788843aF48673C5b260A02ef78742": { "balance": "0x12345000000000000000000" }, "0xcB6632daA65e6c921c2963C37320f63f54fC8fE3": { "balance": "0x12345000000000000000000" }, "0xDe5C7198e2416baB7e7a1EA758858Cd7301740bF": { "balance": "0x12345000000000000000000" }, "0x25fc16D8E2314B305dF05C032E617638284801D6": { "balance": "0x12345000000000000000000" }, "0xD2a3b89AE8D2c3bD39E2F24612ecFCD8600360C9": { "balance": "0x12345000000000000000000" }, "0x2F4fD8a82A1400E654eeEC59b0e588445ffE0F96": { "balance": "0x12345000000000000000000" }, "0x10FdFa4EFc83d6CC42F5ef14c13da8b98E458214": { "balance": "0x12345000000000000000000" }, "0x49cE37B2019bb2d0B8b6a094ef87a6Dd625454A0": { "balance": "0x12345000000000000000000" }, "0x800830F031ab1dd5895a5ec5B561427AD18f9ea8": { "balance": "0x12345000000000000000000" }, "0x3124d9885b11B52c56A2aee610AfCf5740d484F0": { "balance": "0x12345000000000000000000" }, "0xA6177defF3b768b1D678EdF7583b8cf210C777c0": { "balance": "0x12345000000000000000000" }, "0xF99139D2FCc5E25F57B0B91fd382a21B3AFF9cbA": { "balance": "0x12345000000000000000000" }, "0xC4DD08191B4d5173e3698491A11e05b63F9Ee097": { "balance": "0x12345000000000000000000" }, "0xB8865B4B8C56861534CC07ebBD2EA569a9a16323": { "balance": "0x12345000000000000000000" }, "0x2B9935698dc5c19Ab7414AE22f27Da5F4478008a": { "balance": "0x12345000000000000000000" }, "0xAC3c80F41C3049A89Aba8072FFbFc38a90fb6D8c": { "balance": "0x12345000000000000000000" }, "0xD6D4Fb22B91FAa54700852a05698B37d45514166": { "balance": "0x12345000000000000000000" }, "0xAf325Ccc92ae883DEF1634D499d8B093192D7a0c": { "balance": "0x12345000000000000000000" }, "0x7469CeEf99FB67e4990c5F1c085a1B39b2902331": { "balance": "0x12345000000000000000000" }, "0x14DA5251a1EB236238969575ccE943e2Fb0f4AA1": { "balance": "0x12345000000000000000000" }, "0xF9f58a87C3f0B3A4a0592938c80C41a7c659f855": { "balance": "0x12345000000000000000000" }, "0x1CF7e940A657eE706718CF180eb21864DE9672C3": { "balance": "0x12345000000000000000000" }, "0x440C37b22e8D7469128Ea7De6ac2f31419B4A8b1": { "balance": "0x12345000000000000000000" }, "0x4bD04ABA9fc709835b1EE4789195d10E9e8E53F5": { "balance": "0x12345000000000000000000" }, "0x4dC3aC871b22F8a98197B0aae976a8dE08e5Bebe": { "balance": "0x12345000000000000000000" }, "0x1f1D0FCa7e19b799c315d4fDf31bA50e6A2AB153": { "balance": "0x12345000000000000000000" }, "0x28879749Dda99387bdB43295B28bdF251d999F3b": { "balance": "0x12345000000000000000000" }, "0xC4eD09A472B82516daa3A4d8D1E38AE94CF4855C": { "balance": "0x12345000000000000000000" }, "0xf22FbA9cBeB75ED353931418E9eca71EF1Ab9921": { "balance": "0x12345000000000000000000" }, "0xC59D8935c0570E75BA0E55E3C661f535C86e368B": { "balance": "0x12345000000000000000000" }, "0xf97a36c417D33D1fC60a9163A8715e1aecb29102": { "balance": "0x12345000000000000000000" }, "0x4245537d9e3fb36fBBf054247FfFB28b0d931503": { "balance": "0x12345000000000000000000" }, "0xFeb1eafa0154D291e28e393FAF10Bc89e5cCbB22": { "balance": "0x12345000000000000000000" }, "0xf11D16e2EE6BefED82Fbca0b005906E09303aB95": { "balance": "0x12345000000000000000000" }, "0x9C75eD1A37ae420b4FC0a1F4c26B673227Fd3AFa": { "balance": "0x12345000000000000000000" }, "0x6a354C708fd248FD778F6adF75E41AA554700F68": { "balance": "0x12345000000000000000000" }, "0xea94749deFcc40dC5992687974b1C84B1bB9D6df": { "balance": "0x12345000000000000000000" }, "0x7689BE67b205EB5d32811d95D60587Eae4F3036F": { "balance": "0x12345000000000000000000" }, "0xdBfb742BD2e0e6E353cb61E75B9e11257aC8fB1A": { "balance": "0x12345000000000000000000" }, "0x2E5f031578e8FF82199aaF16f42c44D43Fe61819": { "balance": "0x12345000000000000000000" }, "0x611a42A2EF62c2461D123e3F0B64b93938bc4781": { "balance": "0x12345000000000000000000" }, "0x1a0c826048DF0E4661E3c53bBd447d497E3f701F": { "balance": "0x12345000000000000000000" }, "0x7f0E54bc3C1a72405646F5dFbBE0D4565c649fe2": { "balance": "0x12345000000000000000000" }, "0x54e1F990Dc0B7367F1E8eD96dA63BC4bca0E8061": { "balance": "0x12345000000000000000000" }, "0xbE651bc261b9Da5499a24Bf4214fD494c6e1F5Ac": { "balance": "0x12345000000000000000000" }, "0xD3c5dAC705289cD005C402C79C8445a47502d8be": { "balance": "0x12345000000000000000000" }, "0xE5981AA0807eb05611cDb666e32e53b2001bd61d": { "balance": "0x12345000000000000000000" }, "0x0fb648Cb08e21602AF61AF53fE104E29d46433F7": { "balance": "0x12345000000000000000000" }, "0x0474f52d25529c4db5f4E72F43303dA71B3541C6": { "balance": "0x12345000000000000000000" }, "0xe3024d098953661638d59E06f7FcD0B61c424854": { "balance": "0x12345000000000000000000" }, "0x8b1e58f651CacaAa40291d2a6E0a6404d7Ed99e6": { "balance": "0x12345000000000000000000" }, "0x8724C57fb8f38A1FccA7177543dd1D8FcD49E5aa": { "balance": "0x12345000000000000000000" }, "0xd0F043dED28773953562f824334C4cbb84210AE7": { "balance": "0x12345000000000000000000" }, "0xE3d2b9191EaBD3636A5dd057D522335cfae8c7CF": { "balance": "0x12345000000000000000000" }, "0x3f51B3BB6A18141282Ba002F7709c7E2f337F961": { "balance": "0x12345000000000000000000" }, "0xf6B6A52aA9BD788837c6682f47ACE009BD84b6fc": { "balance": "0x12345000000000000000000" }, "0x795B761Db5969B7ba53472d5D37c230C859a472F": { "balance": "0x12345000000000000000000" }, "0x7d7f187C2A05cDDCF700dCF2E02c96E7eF03f9B0": { "balance": "0x12345000000000000000000" }, "0x2d88ECD4d8F4b0A954886eE8C0802aE14684cd07": { "balance": "0x12345000000000000000000" }, "0x92B3feac5b7816Dcef96a303c1D5112271A70D2c": { "balance": "0x12345000000000000000000" }, "0x5DD7bc3BEE395831ce499315ecAFE81DE0556F99": { "balance": "0x12345000000000000000000" }, "0x5227aaebCA3E5e893547A667666E2e4e12Ca20e0": { "balance": "0x12345000000000000000000" }, "0x47575DAE85403cD408d4639068D1187C427B9897": { "balance": "0x12345000000000000000000" }, "0xE69ac59e1DF47291AaB8DEc540C796f81De7c892": { "balance": "0x12345000000000000000000" }, "0xb87fb371Bd3C2093b608cd0E7a8dDD60Bb05C995": { "balance": "0x12345000000000000000000" }, "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02": { "balance": "0x0", "nonce": "0x1", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500" }, "0x4e59b44847b379578588920cA78FbF26c0B4956C": { "balance": "0x0", "nonce": "0x1", "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3" }, "0x4242424242424242424242424242424242424242": { "balance": "0x0", "nonce": "0x1", "code": "0x608060405260043610610093575f3560e01c8063577212fe11610066578063c53925d91161004c578063c53925d914610231578063e12cf4cb14610250578063fea7ab7714610263575f80fd5b8063577212fe146101cc5780639eaffa96146101ed575f80fd5b806301ffc9a7146100975780632dfdf0b5146100cb5780633523f9bd14610103578063560036ec14610126575b5f80fd5b3480156100a2575f80fd5b506100b66100b1366004610bb7565b610282565b60405190151581526020015b60405180910390f35b3480156100d6575f80fd5b505f546100ea9067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016100c2565b34801561010e575f80fd5b5061011860015481565b6040519081526020016100c2565b348015610131575f80fd5b50610193610140366004610c2a565b80516020818301810180516003825292820191909301209152546bffffffffffffffffffffffff8116906c01000000000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1682565b604080516bffffffffffffffffffffffff909316835273ffffffffffffffffffffffffffffffffffffffff9091166020830152016100c2565b3480156101d7575f80fd5b506101eb6101e6366004610d5f565b61031a565b005b3480156101f8575f80fd5b5061020c610207366004610d5f565b6103e7565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100c2565b34801561023c575f80fd5b506101eb61024b366004610d5f565b610428565b6101eb61025e366004610dc1565b61063d565b34801561026e575f80fd5b506101eb61027d366004610e70565b61095c565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000148061031457507fffffffff0000000000000000000000000000000000000000000000000000000082167f136f920d00000000000000000000000000000000000000000000000000000000145b92915050565b6002828260405161032c929190610ec0565b908152604051908190036020019020543373ffffffffffffffffffffffffffffffffffffffff90911614610383576103837f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b60038282604051610395929190610ec0565b9081526040519081900360200181205f90556103b49083908390610ec0565b604051908190038120907f1c0a7e1bd09da292425c039309671a03de56b89a0858598aab6df6ce84b006db905f90a25050565b5f600283836040516103fa929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16905092915050565b5f6003838360405161043b929190610ec0565b908152604051908190036020019020805490915073ffffffffffffffffffffffffffffffffffffffff6c01000000000000000000000000820416906bffffffffffffffffffffffff163382146104b4576104b47f819a0d0b00000000000000000000000000000000000000000000000000000000610afc565b6bffffffffffffffffffffffff42166104d06201518083610efc565b6bffffffffffffffffffffffff16111561050d5761050d7fe8966d7a00000000000000000000000000000000000000000000000000000000610afc565b5f60028686604051610520929190610ec0565b9081526040519081900360200181205473ffffffffffffffffffffffffffffffffffffffff169150839060029061055a9089908990610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556003906105bf9088908890610ec0565b9081526040519081900360200181205f90556105de9087908790610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff808716845284166020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a2505050505050565b6030861461066e5761066e7f9f10647200000000000000000000000000000000000000000000000000000000610afc565b6020841461069f5761069f7fb39bca1600000000000000000000000000000000000000000000000000000000610afc565b606082146106d0576106d07f4be6321b00000000000000000000000000000000000000000000000000000000610afc565b5f73ffffffffffffffffffffffffffffffffffffffff16600288886040516106f9929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff16036108375773ffffffffffffffffffffffffffffffffffffffff8116610768576107687f51969a7a00000000000000000000000000000000000000000000000000000000610afc565b806002888860405161077b929190610ec0565b908152604051908190036020018120805473ffffffffffffffffffffffffffffffffffffffff939093167fffffffffffffffffffffffff0000000000000000000000000000000000000000909316929092179091556107dd9088908890610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff841683525f6020840152917f0adffd98d3072c48341843974dffd7a910bb849ba6ca04163d43bb26feb17403910160405180910390a261087c565b73ffffffffffffffffffffffffffffffffffffffff81161561087c5761087c7fc4142b4100000000000000000000000000000000000000000000000000000000610afc565b5f610885610b04565b90506509184e72a00067ffffffffffffffff821610156108c8576108c87f0e1eddda00000000000000000000000000000000000000000000000000000000610afc565b5f80547f68af751683498a9f9be59fe8b0d52a64dd155255d85cdb29fea30b1e3f891d46918a918a918a918a9187918b918b9167ffffffffffffffff16908061091083610f20565b91906101000a81548167ffffffffffffffff021916908367ffffffffffffffff16021790555060405161094a989796959493929190610f93565b60405180910390a15050505050505050565b5f6002848460405161096f929190610ec0565b9081526040519081900360200190205473ffffffffffffffffffffffffffffffffffffffff1690503381146109c7576109c77f7c214f0400000000000000000000000000000000000000000000000000000000610afc565b73ffffffffffffffffffffffffffffffffffffffff8216610a0b57610a0b7fd92e233d00000000000000000000000000000000000000000000000000000000610afc565b5f60038585604051610a1e929190610ec0565b908152604051908190036020018120426bffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff86166c01000000000000000000000000027fffffffffffffffffffffffffffffffffffffffff000000000000000000000000161781559150610a969086908690610ec0565b6040805191829003822073ffffffffffffffffffffffffffffffffffffffff8681168452851660208401524283830152905190917f7640ec3c8c4695deadda414dd20400acf275297a7c38715f9237657e97ddba5f919081900360600190a25050505050565b805f5260045ffd5b5f610b13633b9aca003461102b565b15610b4157610b417f40567b3800000000000000000000000000000000000000000000000000000000610afc565b5f610b50633b9aca003461103e565b905067ffffffffffffffff811115610b8b57610b8b7f2aa6673400000000000000000000000000000000000000000000000000000000610afc565b610b955f34610b9a565b919050565b5f385f3884865af1610bb35763b12d13eb5f526004601cfd5b5050565b5f60208284031215610bc7575f80fd5b81357fffffffff0000000000000000000000000000000000000000000000000000000081168114610bf6575f80fd5b9392505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b5f60208284031215610c3a575f80fd5b813567ffffffffffffffff811115610c50575f80fd5b8201601f81018413610c60575f80fd5b803567ffffffffffffffff811115610c7a57610c7a610bfd565b6040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0603f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f8501160116810181811067ffffffffffffffff82111715610ce657610ce6610bfd565b604052818152828201602001861015610cfd575f80fd5b816020840160208301375f91810160200191909152949350505050565b5f8083601f840112610d2a575f80fd5b50813567ffffffffffffffff811115610d41575f80fd5b602083019150836020828501011115610d58575f80fd5b9250929050565b5f8060208385031215610d70575f80fd5b823567ffffffffffffffff811115610d86575f80fd5b610d9285828601610d1a565b90969095509350505050565b803573ffffffffffffffffffffffffffffffffffffffff81168114610b95575f80fd5b5f805f805f805f6080888a031215610dd7575f80fd5b873567ffffffffffffffff811115610ded575f80fd5b610df98a828b01610d1a565b909850965050602088013567ffffffffffffffff811115610e18575f80fd5b610e248a828b01610d1a565b909650945050604088013567ffffffffffffffff811115610e43575f80fd5b610e4f8a828b01610d1a565b9094509250610e62905060608901610d9e565b905092959891949750929550565b5f805f60408486031215610e82575f80fd5b833567ffffffffffffffff811115610e98575f80fd5b610ea486828701610d1a565b9094509250610eb7905060208501610d9e565b90509250925092565b818382375f9101908152919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b6bffffffffffffffffffffffff818116838216019081111561031457610314610ecf565b5f67ffffffffffffffff821667ffffffffffffffff8103610f4357610f43610ecf565b60010192915050565b81835281816020850137505f602082840101525f60207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b60a081525f610fa660a083018a8c610f4c565b8281036020840152610fb981898b610f4c565b905067ffffffffffffffff871660408401528281036060840152610fde818688610f4c565b91505067ffffffffffffffff831660808301529998505050505050505050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b5f8261103957611039610ffe565b500690565b5f8261104c5761104c610ffe565b50049056fea164736f6c634300081a000a" }, "0x4200000000000000000000000000000000000042": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c8063163db71b1461003857806360644a6b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b610065610060366004610137565b610067565b005b336002600160a01b031461008e57604051632f3a162d60e11b815260040160405180910390fd5b5f8054908061009c836101a5565b909155505060405163999da65b60e01b81526043602160991b019063999da65b906100cd90859085906004016101c9565b5f604051808303815f87803b1580156100e4575f80fd5b505af11580156100f6573d5f803e3d5ffd5b505050507f60b106db8802e863a4a9dc4af78cb0dd63feb55ad4ee60f0453c13309bfdbdd4828260405161012b9291906101c9565b60405180910390a15050565b5f8060208385031215610148575f80fd5b823567ffffffffffffffff81111561015e575f80fd5b8301601f8101851361016e575f80fd5b803567ffffffffffffffff811115610184575f80fd5b856020828401011115610195575f80fd5b6020919091019590945092505050565b5f600182016101c257634e487b7160e01b5f52601160045260245ffd5b5060010190565b60208152816020820152818360408301375f818301604090810191909152601f909201601f1916010191905056fea2646970667358221220c2930abe9036c3b4b2592fab2f2fd516d3698f5c696d82745ddc0af43f7096a764736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" }, "0x4200000000000000000000000000000000000043": { "code": "0x608060405234801561000f575f80fd5b5060043610610034575f3560e01c80634b28f9a214610038578063999da65b14610052575b5f80fd5b6100405f5481565b60405190815260200160405180910390f35b6100656100603660046100b8565b610067565b005b5f8054908061007583610126565b91905055507fb3a8fa51f8d3759f320e88b7f8d3fb73a2a51b31b3324b37833c4816cf41e7c45f546040516100ac91815260200190565b60405180910390a15050565b5f80602083850312156100c9575f80fd5b823567ffffffffffffffff8111156100df575f80fd5b8301601f810185136100ef575f80fd5b803567ffffffffffffffff811115610105575f80fd5b856020828401011115610116575f80fd5b6020919091019590945092505050565b5f6001820161014357634e487b7160e01b5f52601160045260245ffd5b506001019056fea2646970667358221220350dbb7eed9e4d6e4ff72594b0582b0b2e4c1d6b11c3e5ad382201b47a638cc664736f6c634300081a0033", "nonce": "0x1", "balance": "0x0" } } } ================================================ FILE: testing/simulated/execution/execnode.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package execution import ( "fmt" "net/http" "path/filepath" "testing" "github.com/berachain/beacon-kit/primitives/net/url" "github.com/ory/dockertest" "github.com/ory/dockertest/docker" "github.com/stretchr/testify/require" ) // ExecNode represents a test instance of an execution client node running inside a Docker container. // The CmdStrBuilder field is used to generate the command string that initializes and runs the node. type ExecNode struct { homeDir string image docker.PullImageOptions CmdStrBuilder func(genesisFile string) string } // NewExecNode returns a new ExecNode instance configured with the given home directory, // Docker image options, and a command string builder. func NewExecNode(homeDir string, image docker.PullImageOptions, builder func(genesisFile string) string) *ExecNode { return &ExecNode{ homeDir: homeDir, image: image, CmdStrBuilder: builder, } } // Start launches the execution client container using dockertest, waits until the client is ready, // and returns the container resource along with the connection URL for the Auth RPC endpoint. func (e *ExecNode) Start(t *testing.T, genesisFile string) (*Resource, *url.ConnectionURL, *url.ConnectionURL) { t.Helper() // Create a new Docker pool. pool, err := dockertest.NewPool("") require.NoError(t, err, "failed to create Docker pool") require.NotNil(t, pool, "Docker pool is nil") // Verify that we can connect to the Docker daemon. err = pool.Client.Ping() require.NoErrorf(t, err, "could not connect to Docker: %s", err) // Pull the image if it is not already present. err = pool.Client.PullImage(e.image, docker.AuthConfiguration{}) require.NoError(t, err, "failed to pull image") // Resolve the absolute path to the local test files. absPath, err := filepath.Abs("../files") require.NoError(t, err, "failed to determine absolute path for test files") require.NotNil(t, e.CmdStrBuilder, "CmdStrBuilder is nil") cmdStr := e.CmdStrBuilder(genesisFile) // Run the container with custom commands that initialize and run the client. resource, err := pool.RunWithOptions(&dockertest.RunOptions{ Repository: e.image.Repository, Tag: e.image.Tag, // Override the default entrypoint to use /bin/sh so we can chain commands. Entrypoint: []string{"/bin/sh"}, Cmd: []string{ "-c", cmdStr, }, // Expose required ports for EL RPC, Auth RPC, and P2P communication. ExposedPorts: []string{"8545/tcp", "8551/tcp", "30303/tcp"}, // Bind mount the local test data and JWT files to the container. Mounts: []string{ fmt.Sprintf("%s:/%s", e.homeDir, "testdata"), fmt.Sprintf("%s:/%s", absPath, "testing/files"), }, }) require.NoError(t, err, "failed to run container") // Build the connection URLs for EL RPC and Auth RPC. elRPC, err := url.NewFromRaw("http://" + resource.GetHostPort("8545/tcp")) require.NoError(t, err, "failed to create EL RPC URL") authRPC, err := url.NewFromRaw("http://" + resource.GetHostPort("8551/tcp")) require.NoError(t, err, "failed to create Auth RPC URL") t.Logf("Auth RPC URL: %s", authRPC.String()) // Wait until the EL RPC endpoint is available by retrying HTTP GET requests. err = pool.Retry(func() error { resp, httpErr := http.Get(elRPC.String()) if httpErr != nil { return httpErr } defer resp.Body.Close() return nil }) require.NoError(t, err, "Container did not become ready in time") return &Resource{Resource: resource}, authRPC, elRPC } ================================================ FILE: testing/simulated/execution/geth.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package execution import ( "fmt" "github.com/ory/dockertest/docker" ) // NewGethNode creates a new execution node configured for Geth by using the default Geth command builder. func NewGethNode(homeDir string, image docker.PullImageOptions) *ExecNode { return NewExecNode(homeDir, image, defaultGethCmdStrBuilder) } // ValidGethImage returns the default Docker image options for the Geth node. func ValidGethImage() docker.PullImageOptions { return docker.PullImageOptions{ Repository: "ghcr.io/berachain/bera-geth", Tag: "latest", } } // defaultGethCmdStrBuilder returns a command string tailored for running a Geth node. func defaultGethCmdStrBuilder(genesisFile string) string { return fmt.Sprintf(` bera-geth init --datadir /tmp/gethdata /testdata/%s && bera-geth --http --http.addr 0.0.0.0 --http.api eth,net,web3,debug \ --authrpc.addr 0.0.0.0 \ --authrpc.jwtsecret /testing/files/jwt.hex \ --authrpc.vhosts '*' \ --datadir /tmp/gethdata \ --ipcpath /tmp/gethdata/bera-geth.ipc \ --syncmode full \ --verbosity 4 \ --nodiscover `, genesisFile) } ================================================ FILE: testing/simulated/execution/resource.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package execution import "github.com/ory/dockertest" // Resource manages a *dockertest.Resource with added utility. type Resource struct { *dockertest.Resource isClosed bool } func (r *Resource) Close() error { if r.isClosed { return nil } r.isClosed = true return r.Resource.Close() } ================================================ FILE: testing/simulated/execution/reth.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package execution import ( "fmt" "github.com/ory/dockertest/docker" ) // NewRethNode creates a new execution node configured for Reth by using the default Reth command builder. func NewRethNode(homeDir string, image docker.PullImageOptions) *ExecNode { return NewExecNode(homeDir, image, defaultRethCmdStrBuilder) } // NewRethNodeWithEngineOverride creates a new execution node configured for Reth by using the Reth // command builder with the --engine.always-process-payload-attributes-on-canonical-head flag. func NewRethNodeWithEngineOverride(homeDir string, image docker.PullImageOptions) *ExecNode { return NewExecNode(homeDir, image, rethWithEngineOverrideFlagCmdStrBuilder) } // ValidRethImage returns the default Docker image options for the Reth node. func ValidRethImage() docker.PullImageOptions { return docker.PullImageOptions{ Repository: "ghcr.io/berachain/bera-reth", Tag: "nightly", } } // defaultRethCmdStrBuilder returns a command string tailored for running a Reth node. func defaultRethCmdStrBuilder(genesisFile string) string { return fmt.Sprintf(` bera-reth node --http --http.addr 0.0.0.0 --http.api eth,net,web3,debug \ --chain=/testdata/%s \ --authrpc.addr 0.0.0.0 \ --authrpc.jwtsecret /testing/files/jwt.hex \ --datadir /tmp/rethdata \ --full \ --engine.persistence-threshold=0 \ --engine.memory-block-buffer-target=0 \ -vvvv \ `, genesisFile) } // rethWithEngineOverrideFlagCmdStrBuilder returns a command string tailored for running a Reth node // with the --engine.always-process-payload-attributes-on-canonical-head flag. func rethWithEngineOverrideFlagCmdStrBuilder(genesisFile string) string { return fmt.Sprintf(` bera-reth node --http --http.addr 0.0.0.0 --http.api eth,net,web3,debug \ --chain=/testdata/%s \ --authrpc.addr 0.0.0.0 \ --authrpc.jwtsecret /testing/files/jwt.hex \ --datadir /tmp/rethdata \ --full \ --engine.persistence-threshold=0 \ --engine.memory-block-buffer-target=0 \ --engine.always-process-payload-attributes-on-canonical-head \ -vvvv \ `, genesisFile) } ================================================ FILE: testing/simulated/execution/simulation_client.go ================================================ //go:build simulated // // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package execution import ( "context" "math/big" "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/primitives/encoding/json" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" ) // SimulationClient calls `eth_simulateV1` on a Geth node. type SimulationClient struct { engineClient *client.EngineClient } // TransactionArgs represents the fields needed to construct a dynamic-fee transaction. type TransactionArgs struct { From common.Address `json:"from"` To common.Address `json:"to"` Gas *hexutil.Uint64 `json:"gas"` GasPrice *hexutil.Big `json:"gasPrice"` MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` Value *hexutil.Big `json:"value"` Nonce *hexutil.Uint64 `json:"nonce"` Input *hexutil.Bytes `json:"input"` AccessList types.AccessList `json:"accessList,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"` // BlobTxType fields. BlobFeeCap *hexutil.Big `json:"maxFeePerBlobGas"` BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"` Blobs []kzg4844.Blob Commitments []kzg4844.Commitment Proofs []kzg4844.Proof } // BlockOverrides holds optional block-level overrides for simulation. type BlockOverrides struct { Number *hexutil.Big `json:"number,omitempty"` Difficulty *hexutil.Big `json:"difficulty,omitempty"` Time *hexutil.Uint64 `json:"time,omitempty"` GasLimit *hexutil.Uint64 `json:"gasLimit,omitempty"` FeeRecipient *common.Address `json:"feeRecipient,omitempty"` PrevRandao *common.Hash `json:"prevRandao,omitempty"` BaseFeePerGas *hexutil.Big `json:"baseFeePerGas,omitempty"` BlobBaseFee *hexutil.Big `json:"blobBaseFee,omitempty"` BeaconRoot *common.Hash `json:"beaconRoot,omitempty"` Withdrawals types.Withdrawals } // SimBlock is a block containing calls and optional overrides for simulation. type SimBlock struct { Calls []TransactionArgs `json:"calls"` BlockOverrides *BlockOverrides `json:"blockOverrides"` } // SimOpts groups all parameters for `eth_simulateV1`. type SimOpts struct { BlockStateCalls []*SimBlock `json:"blockStateCalls"` Validation bool `json:"validation"` TraceTransfers bool `json:"traceTransfers"` } // CallResult describes the outcome of an individual simulated transaction. type CallResult struct { ReturnData hexutil.Bytes `json:"returnData"` Logs json.RawMessage `json:"logs"` GasUsed *hexutil.Uint64 `json:"gasUsed"` Status hexutil.Uint64 `json:"status"` } // SimulatedBlock is the response structure returned by `eth_simulateV1`. type SimulatedBlock struct { BaseFeePerGas *hexutil.Big `json:"baseFeePerGas"` BlobGasUsed *hexutil.Big `json:"blobGasUsed"` Calls []CallResult `json:"calls"` Difficulty *hexutil.Big `json:"difficulty"` ExcessBlobGas *hexutil.Big `json:"excessBlobGas"` ExtraData hexutil.Bytes `json:"extraData"` GasLimit *hexutil.Uint64 `json:"gasLimit"` GasUsed *hexutil.Uint64 `json:"gasUsed"` Hash common.Hash `json:"hash"` LogsBloom hexutil.Bytes `json:"logsBloom"` Miner common.Address `json:"miner"` MixHash common.Hash `json:"mixHash"` Nonce hexutil.Bytes `json:"nonce"` Number *hexutil.Big `json:"number"` ParentBeaconBlockRoot common.Hash `json:"parentBeaconBlockRoot"` ParentHash common.Hash `json:"parentHash"` ReceiptsRoot common.Hash `json:"receiptsRoot"` Sha3Uncles common.Hash `json:"sha3Uncles"` Size *hexutil.Uint64 `json:"size"` StateRoot common.Hash `json:"stateRoot"` Timestamp *hexutil.Uint64 `json:"timestamp"` Transactions []common.Hash `json:"transactions"` TransactionsRoot common.Hash `json:"transactionsRoot"` Uncles []common.Hash `json:"uncles"` Withdrawals types.Withdrawals `json:"withdrawals"` WithdrawalsRoot common.Hash `json:"withdrawalsRoot"` } // NewSimulationClient returns a client for eth_simulateV1 calls. func NewSimulationClient(cli *client.EngineClient) *SimulationClient { return &SimulationClient{cli} } // Simulate calls `eth_simulateV1` with the provided block number and options. func (c *SimulationClient) Simulate( ctx context.Context, blockNumber int64, opts *SimOpts, ) ([]*SimulatedBlock, error) { var result []*SimulatedBlock blockNumberInput := hexutil.Uint64(blockNumber) if err := c.engineClient.Call(ctx, &result, "eth_simulateV1", opts, blockNumberInput); err != nil { return nil, err } return result, nil } // TxsToTransactionArgs converts a slice of Geth transactions to TransactionArgs suitable for simulation. // The transactions must be dynamic-fee (EIP-1559 or EIP-4844) type. // TODO: use the LatestSigner based on a Geth ChainConfig parsed from an EL Genesis File as have currently hardcoded Cancun Signer. func TxsToTransactionArgs(chainID uint64, txs []*types.Transaction) ([]TransactionArgs, error) { signer := types.NewCancunSigner(big.NewInt(int64(chainID))) args := make([]TransactionArgs, len(txs)) for i, tx := range txs { sender, err := signer.Sender(tx) if err != nil { return nil, err } gas := hexutil.Uint64(tx.Gas()) feeCap := hexutil.Big(*tx.GasFeeCap()) tipCap := hexutil.Big(*tx.GasTipCap()) val := hexutil.Big(*tx.Value()) nonce := hexutil.Uint64(tx.Nonce()) data := hexutil.Bytes(tx.Data()) chainIDHex := hexutil.Big(*big.NewInt(int64(chainID))) call := TransactionArgs{ From: sender, To: *tx.To(), Gas: &gas, MaxFeePerGas: &feeCap, MaxPriorityFeePerGas: &tipCap, Value: &val, Nonce: &nonce, Input: &data, AccessList: tx.AccessList(), ChainID: &chainIDHex, } if sidecar := tx.BlobTxSidecar(); sidecar != nil { blobCap := hexutil.Big(*tx.BlobGasFeeCap()) call.BlobHashes = tx.BlobHashes() call.BlobFeeCap = &blobCap call.Blobs = sidecar.Blobs call.Commitments = sidecar.Commitments call.Proofs = sidecar.Proofs } args[i] = call } return args, nil } ================================================ FILE: testing/simulated/homedir.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated import ( "context" "fmt" "io" "os" "os/exec" "path" "path/filepath" "testing" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/cli/commands/genesis" "github.com/berachain/beacon-kit/cli/commands/initialize" "github.com/berachain/beacon-kit/cli/commands/server/types" genesisutils "github.com/berachain/beacon-kit/cli/utils/genesis" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/primitives/common" cmtcfg "github.com/cometbft/cometbft/config" "github.com/cosmos/cosmos-sdk/client" "github.com/stretchr/testify/require" ) const TestnetBeaconChainID = "testnet-beacon-80069" const WithdrawalExecutionAddress = "0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4" // InitializeHomeDirs sets up one or more temporary home directories with the // necessary genesis state and configuration files for testing. It returns a // CometBFT config per home directory along with the computed genesis validators // root. When multiple directories are provided, premined deposits are // consolidated into the first directory and the resulting genesis file is // replicated to all others. func InitializeHomeDirs( t *testing.T, chainSpec chain.Spec, elGenesisPath string, tempHomeDirs ...string, ) ([]*cmtcfg.Config, common.Root) { t.Helper() require.NotEmpty(t, tempHomeDirs, "at least one home directory is required") n := len(tempHomeDirs) t.Logf("Initializing %d home director(ies): %v", n, tempHomeDirs) configs := make([]*cmtcfg.Config, n) for i, dir := range tempHomeDirs { configs[i] = createCometConfig(t, dir) initCommand(t, chainSpec, configs[i].RootDir) } depositAmount := chainSpec.MaxEffectiveBalance() withdrawalAddress, err := common.NewExecutionAddressFromHex(WithdrawalExecutionAddress) require.NoError(t, err, "failed to create withdrawal address") for i, cfg := range configs { signer := GetBlsSigner(cfg.RootDir) err = genesis.AddGenesisDeposit(chainSpec, cfg, signer, depositAmount, withdrawalAddress, "") require.NoError(t, err, "failed to add genesis deposit %d", i+1) } primaryDir := filepath.Join(configs[0].RootDir, "config", "premined-deposits") for i := 1; i < n; i++ { copyMissingFiles(t, filepath.Join(configs[i].RootDir, "config", "premined-deposits"), primaryDir) } err = genesis.CollectGenesisDeposits(configs[0]) require.NoError(t, err, "failed to collect genesis deposits") if n > 1 { srcGenesis := filepath.Join(configs[0].RootDir, "config", "genesis.json") data, readErr := os.ReadFile(srcGenesis) require.NoError(t, readErr, "failed to read genesis file: %s", srcGenesis) for i := 1; i < n; i++ { dst := filepath.Join(configs[i].RootDir, "config", "genesis.json") require.NoError(t, os.WriteFile(dst, data, 0o600), "failed to write genesis file: %s", dst) } } for i, cfg := range configs { err = genesis.SetDepositStorage(chainSpec, cfg, elGenesisPath) require.NoError(t, err, "failed to set deposit storage %d", i+1) err = genesis.AddExecutionPayload(chainSpec, path.Join(cfg.RootDir, filepath.Base(elGenesisPath)), cfg) require.NoError(t, err, "failed to add execution payload %d", i+1) } genesisValidatorsRoot, err := genesisutils.ComputeValidatorsRootFromFile( path.Join(configs[0].RootDir, "config/genesis.json"), chainSpec, ) require.NoError(t, err, "failed to compute validators root") for i := 1; i < n; i++ { root, rootErr := genesisutils.ComputeValidatorsRootFromFile( path.Join(configs[i].RootDir, "config/genesis.json"), chainSpec, ) require.NoError(t, rootErr, "failed to compute validators root %d", i+1) require.Equal(t, genesisValidatorsRoot, root, "validators' roots should be equal") } return configs, genesisValidatorsRoot } func CopyHomeDir(t *testing.T, sourceHomeDir, targetHomeDir string) { t.Logf("Copying home directory to: %s", targetHomeDir) srcPath := filepath.Join(filepath.Clean(sourceHomeDir), ".") cmd := exec.Command("sh", "-c", fmt.Sprintf("cp -r %s/* %s", srcPath, targetHomeDir)) err := cmd.Run() require.NoError(t, err) } // createCometConfig creates a default CometBFT configuration with the home directory set. func createCometConfig(t *testing.T, tempHomeDir string) *cmtcfg.Config { t.Helper() cmtCfg := cometbft.DefaultConfig() cmtCfg.RootDir = tempHomeDir return cmtCfg } // initCommand runs the initialization command to prepare the home directory. // This function emulates the 'beacond init' command. func initCommand(t *testing.T, spec chain.Spec, homeDir string) { t.Helper() // Create a Cosmos SDK client context with the provided home directory and chain ID. clientCtx := client.Context{}. WithHomeDir(homeDir). WithChainID(TestnetBeaconChainID) // Ensure necessary directories exist. err := os.MkdirAll(path.Join(homeDir, "config"), 0700) require.NoError(t, err, "failed to create config directory") err = os.MkdirAll(path.Join(homeDir, "data"), 0700) require.NoError(t, err, "failed to create data directory") // Initialize the command to set up the home directory. initCMD := initialize.InitCmd(func(_ types.AppOptions) (chain.Spec, error) { return spec, nil }, &cometbft.Service{}) initCMD.SetArgs([]string{"test-moniker"}) // Set the command context; required to work around a Cosmos SDK issue. initCMD.SetContext(context.Background()) err = client.SetCmdClientContextHandler(clientCtx, initCMD) require.NoError(t, err, "failed to set client context handler") // Allow unknown flags to enable running tests from IDEs without extra configuration. initCMD.FParseErrWhitelist.UnknownFlags = true // Execute the initialization command. err = initCMD.Execute() require.NoError(t, err, "failed to execute init command") } // copyMissingFiles copies files that exist in srcDir but not in dstDir. func copyMissingFiles(t *testing.T, srcDir, dstDir string) { t.Helper() // Ensure destination directory exists. require.NoError(t, os.MkdirAll(dstDir, 0o700)) srcEntries, err := os.ReadDir(srcDir) require.NoError(t, err, "failed to read source directory: %s", srcDir) for _, e := range srcEntries { if e.IsDir() { continue } srcPath := filepath.Join(srcDir, e.Name()) dstPath := filepath.Join(dstDir, e.Name()) if _, err := os.Stat(dstPath); err == nil { // Already exists. continue } srcFile, err := os.Open(srcPath) require.NoError(t, err, "failed to open src file: %s", srcPath) defer srcFile.Close() dstFile, err := os.Create(dstPath) require.NoError(t, err, "failed to create dst file: %s", dstPath) _, err = io.Copy(dstFile, srcFile) require.NoError(t, err, "failed to copy to dst file: %s", dstPath) require.NoError(t, dstFile.Close()) } } ================================================ FILE: testing/simulated/malicious_consensus_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "math/big" "time" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/beacon/blockchain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/testing/simulated" "github.com/cometbft/cometbft/abci/types" gethcommon "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" ) // TestFinalizeBlock_BadBlock_Errors effectively serves as a test for how a valid node would react to // a malicious consensus majority agreeing to a block with an invalid EVM transaction. func (s *SimulatedSuite) TestFinalizeBlock_BadBlock_Errors() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens on Deneb, pre Deneb1 fork. startTime := time.Unix(0, 0) // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, proposalTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) // We expected this test to happen during Pre-Deneb1 fork. currentHeight := int64(blockHeight + coreLoopIterations) // Prepare a block proposal. proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: proposalTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(proposal) // Unmarshal the proposal block. proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( proposal.Txs, blockchain.BeaconBlockTxIndex, s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(proposalTime.Unix())), ) s.Require().NoError(err) // Sign a malicious transaction that is expected to fail. maliciousTx, err := gethtypes.SignNewTx( simulated.GetTestKey(s.T()), gethtypes.NewCancunSigner(big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID()))), &gethtypes.DynamicFeeTx{ Nonce: 0, To: &gethcommon.Address{1}, Value: big.NewInt(100000000000), Gas: 21000, GasTipCap: big.NewInt(10000000), GasFeeCap: big.NewInt(10000000), Data: []byte{}, }, ) s.Require().NoError(err, "failed to sign malicious transaction") // Initialize the slice with the malicious transaction. maliciousTxs := []*gethtypes.Transaction{maliciousTx} // Create a malicious block by injecting an invalid transaction. maliciousBlock := simulated.ComputeAndSetInvalidExecutionBlock( s.T(), proposedBlock.GetBeaconBlock(), s.TestNode.ChainSpec, maliciousTxs, nil, ) // Re-sign the block maliciousBlockSigned, err := ctypes.NewSignedBeaconBlock( maliciousBlock, &ctypes.ForkData{ CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(maliciousBlock.GetTimestamp()), GenesisValidatorsRoot: s.GenesisValidatorsRoot, }, s.TestNode.ChainSpec, blsSigner, ) s.Require().NoError(err) maliciousBlockBytes, err := maliciousBlockSigned.MarshalSSZ() s.Require().NoError(err) // Replace the valid block with the malicious block in the proposal. proposal.Txs[0] = maliciousBlockBytes // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() // Finalize the proposal containing the malicious block. finalizeResp, err := s.SimComet.Comet.FinalizeBlock(s.CtxComet, &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: proposalTime, }) s.Require().ErrorIs(err, errors.ErrInvalidPayloadStatus) s.Require().Nil(finalizeResp) s.Require().Contains(s.LogBuffer.String(), "max fee per gas less than block base fee: address 0x20f33CE90A13a4b5E7697E3544c3083B8F8A51D4, maxFeePerGas: 10000000, baseFee: 765625000") } ================================================ FILE: testing/simulated/malicious_proposer_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "math/big" "time" "github.com/berachain/beacon-kit/beacon/blockchain" payloadtime "github.com/berachain/beacon-kit/beacon/payload-time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" dablob "github.com/berachain/beacon-kit/da/blob" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/testing/simulated" "github.com/cometbft/cometbft/abci/types" gethcommon "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/holiman/uint256" "github.com/stretchr/testify/require" ) // TestProcessProposal_BadBlock_IsRejected effectively serves as a test for how a valid node would react to // a malicious proposer proposing a block with an invalid EVM transaction. func (s *SimulatedSuite) TestProcessProposal_BadBlock_IsRejected() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens on Deneb, pre Deneb1 fork. startTime := time.Unix(0, 0) // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, proposalTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) // We expected this test to happen during Pre-Deneb1 fork. currentHeight := int64(blockHeight + coreLoopIterations) // Prepare a block proposal. proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: proposalTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(proposal) // Unmarshal the proposal block. proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( proposal.Txs, blockchain.BeaconBlockTxIndex, s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(proposalTime.Unix())), ) s.Require().NoError(err) // Sign a malicious transaction that is expected to fail. recipientAddress := gethcommon.HexToAddress("0x56898d1aFb10cad584961eb96AcD476C6826e41E") maliciousTx, err := gethtypes.SignNewTx( simulated.GetTestKey(s.T()), gethtypes.NewCancunSigner(big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID()))), &gethtypes.DynamicFeeTx{ Nonce: 0, To: &recipientAddress, Value: big.NewInt(0), Gas: 21016, GasTipCap: big.NewInt(10000000), GasFeeCap: big.NewInt(10000000), Data: []byte{}, }, ) // Initialize the slice with the malicious transaction. maliciousTxs := []*gethtypes.Transaction{maliciousTx} // Create a malicious block by injecting an invalid transaction. maliciousBlock := simulated.ComputeAndSetInvalidExecutionBlock( s.T(), proposedBlock.GetBeaconBlock(), s.TestNode.ChainSpec, maliciousTxs, nil, ) // Re-sign the block maliciousBlockSigned, err := ctypes.NewSignedBeaconBlock( maliciousBlock, &ctypes.ForkData{ CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(maliciousBlock.GetTimestamp()), GenesisValidatorsRoot: s.GenesisValidatorsRoot, }, s.TestNode.ChainSpec, blsSigner, ) s.Require().NoError(err) maliciousBlockBytes, err := maliciousBlockSigned.MarshalSSZ() s.Require().NoError(err) // Replace the valid block with the malicious block in the proposal. proposal.Txs[0] = maliciousBlockBytes // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() // Process the proposal containing the malicious block. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: proposalTime, }) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) // Verify that the log contains the expected error message. s.Require().Contains(s.LogBuffer.String(), errors.ErrInvalidPayloadStatus.Error()) // Note this error message may change across execution clients. Base fee changes with number of core loop iterations. s.Require().Contains(s.LogBuffer.String(), "max fee per gas less than block base fee: address 0x20f33CE90A13a4b5E7697E3544c3083B8F8A51D4, maxFeePerGas: 10000000, baseFee: 765625000") } // TestProcessProposal_InvalidTimestamps_Errors effectively serves as a test for how a valid node would react to // a malicious proposer attempting to use a future timestamp in the block that does not match the consensus timestamp. func (s *SimulatedSuite) TestProcessProposal_InvalidTimestamps_Errors() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens post Deneb1 fork. startTime := time.Now() // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, correctConsensusTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) currentHeight := int64(blockHeight + coreLoopIterations) // Prepare a block proposal. This will create a valid payload due to optimistic payload building. // It is called to flush the payload cache. validProposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: correctConsensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(validProposal) // Build a block with a malicious proposal time maliciousPayloadTime := correctConsensusTime.Add(2 * time.Second) maliciousProposalTxs := testBuildInvalidBlock( s.Require(), s.SharedAccessors, &types.PrepareProposalRequest{ Txs: validProposal.Txs, Height: currentHeight, Time: correctConsensusTime, }, func(sb *ctypes.SignedBeaconBlock) { blk := sb.BeaconBlock blk.Body.ExecutionPayload.Timestamp = math.U64(maliciousPayloadTime.Unix()) }, ) // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() // Process the proposal containing the malicious block. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: maliciousProposalTxs, Height: currentHeight, ProposerAddress: nodeAddress, // Use the correct time as the actual consensus time, which mismatches the proposal time. Time: correctConsensusTime, }) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) s.Require().Contains(s.LogBuffer.String(), payloadtime.ErrTooFarInTheFuture.Error()) } // TestProcessProposal_InvalidBlobCommitment_Errors effectively serves as a test for a malicious blobs. // Specifically, to bypass the commitment count check, we put 2 commitments into 1 tx and leave the // other tx with zero commitments. This ultimately gets rejected by the execution client. func (s *SimulatedSuite) TestProcessProposal_InvalidBlobCommitment_Errors() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens on Deneb, pre Deneb1 fork. startTime := time.Unix(0, 0) // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, consensusTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) // We expected this test to happen during Pre-Deneb1 fork. currentHeight := int64(blockHeight + coreLoopIterations) // Prepare a block proposal. proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(proposal) // Unmarshal the proposal block. proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( proposal.Txs, blockchain.BeaconBlockTxIndex, s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())), ) s.Require().NoError(err) // Create the Blobs, with proofs and commitments // Each blob will go into 1 transaction. blobs := []*eip4844.Blob{{1, 2, 3}, {4, 5, 6}} proofs, commitments := simulated.GetProofAndCommitmentsForBlobs(require.New(s.T()), blobs, s.TestNode.KZGVerifier) s.Require().Len(proofs, len(blobs)) s.Require().Len(commitments, len(blobs)) // Here is where we act malicious. blobVersionedHash0 := commitments[0].ToVersionedHash() blobVersionedHash1 := commitments[1].ToVersionedHash() versionedHashesForBlob := [][]gethcommon.Hash{ {blobVersionedHash0, blobVersionedHash1}, // index 0 nil, // index 1 is nil } // Sign blob transactions blobTxs := make([]*gethtypes.Transaction, len(blobs)) for i := range blobs { blobCommitment := commitments[i] txSidecar := &gethtypes.BlobTxSidecar{ Blobs: []kzg4844.Blob{kzg4844.Blob(blobs[i][:])}, Commitments: []kzg4844.Commitment{kzg4844.Commitment(blobCommitment)}, Proofs: []kzg4844.Proof{kzg4844.Proof(proofs[i])}, } blobTx, err := gethtypes.SignNewTx( simulated.GetTestKey(s.T()), gethtypes.NewCancunSigner(big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID()))), &gethtypes.BlobTx{ Nonce: uint64(i), // Set to 875000000 as that is the tx base fee GasTipCap: uint256.NewInt(875000000), GasFeeCap: uint256.NewInt(875000000), // Set to 21000 for minimum intrinsic gas Gas: 210000, Value: uint256.NewInt(0), Data: []byte{}, AccessList: nil, BlobFeeCap: uint256.NewInt(10), // If we have 1 tx with multiple blobs, we must add the blob hashes here. BlobHashes: versionedHashesForBlob[i], // Sidecar must be set to nil here or Geth will error with "unexpected blob sidecar in transaction" Sidecar: nil, }, ) s.Require().NoError(err) // Once we've signed the Tx, we tag the blob with the tx purely for association between tx and sidecars. // In this case, each 1 tx has a sidecar with 1 blob, even though 1 tx could have more than 1 blob. blobTx = blobTx.WithBlobTxSidecar(txSidecar) blobTxs[i] = blobTx } proposedBlockMessage := simulated.ComputeAndSetValidExecutionBlock( s.T(), proposedBlock.GetBeaconBlock(), s.SimulationClient, s.TestNode.ChainSpec, blobTxs, ) proposedBlockMessage.GetBody().SetBlobKzgCommitments(commitments) // Finalize the block by applying the state transition to update its state root. queryCtx, err := s.SimComet.CreateQueryContext(currentHeight-1, false) s.Require().NoError(err) proposedBlockMessage, err = simulated.ComputeAndSetStateRoot(queryCtx, consensusTime, nodeAddress, s.TestNode.StateProcessor, s.TestNode.StorageBackend, proposedBlockMessage) s.Require().NoError(err) newSignedBlock, err := ctypes.NewSignedBeaconBlock( proposedBlockMessage, &ctypes.ForkData{ CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(proposedBlockMessage.GetTimestamp()), GenesisValidatorsRoot: s.GenesisValidatorsRoot, }, s.TestNode.ChainSpec, blsSigner, ) s.Require().NoError(err) // Inject the new block newSignedBlockBytes, err := newSignedBlock.MarshalSSZ() s.Require().NoError(err) proposal.Txs[0] = newSignedBlockBytes // Create the beaconBlock Header for the sidecar blockWithCommitmentsSignedHeader := ctypes.NewSignedBeaconBlockHeader( newSignedBlock.GetHeader(), newSignedBlock.GetSignature(), ) sidecarsSlice := make([]*datypes.BlobSidecar, len(blobs)) // Build Inclusion Proofs for Sidecars sidecarFactory := dablob.NewSidecarFactory(metrics.NewNoOpTelemetrySink()) for i := range blobs { inclusionProof, err := sidecarFactory.BuildKZGInclusionProof(proposedBlockMessage.GetBody(), math.U64(i)) s.Require().NoError(err) sidecar := datypes.BuildBlobSidecar( math.U64(i), blockWithCommitmentsSignedHeader, blobs[i], commitments[i], proofs[i], inclusionProof, ) sidecarsSlice[i] = sidecar } sidecars := datypes.BlobSidecars(sidecarsSlice) // Inject the sidecar sidecarBytes, err := sidecars.MarshalSSZ() s.Require().NoError(err) proposal.Txs[1] = sidecarBytes // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() // Process the proposal containing the block. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: consensusTime, }) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) s.Require().Contains(s.LogBuffer.String(), "could not apply tx 1 [0xdbbf691e9271a8bc3de5e64405337972fb4a5185cc3df160bac310c515f7d768]: blob transaction missing blob hashes") } // TestProcessProposal_InvalidBlobInclusionProof_Errors effectively serves as a test for a malicious blobs. // Specifically, we tweak the KZG commitment inclusion proof such that it is invalid and must be rejected. func (s *SimulatedSuite) TestProcessProposal_InvalidBlobInclusionProof_Errors() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens on Deneb, pre Deneb1 fork. startTime := time.Unix(0, 0) // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, consensusTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) // We expected this test to happen during Pre-Deneb1 fork. currentHeight := int64(blockHeight + coreLoopIterations) // Prepare a block proposal. proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(proposal) // Unmarshal the proposal block. proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( proposal.Txs, blockchain.BeaconBlockTxIndex, s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())), ) s.Require().NoError(err) // Create the Blobs, with proofs and commitments // Each blob will go into 1 transaction. blobs := []*eip4844.Blob{{1, 2, 3}, {4, 5, 6}} proofs, commitments := simulated.GetProofAndCommitmentsForBlobs(require.New(s.T()), blobs, s.TestNode.KZGVerifier) s.Require().Len(proofs, len(blobs)) s.Require().Len(commitments, len(blobs)) // Sign blob transactions blobTxs := make([]*gethtypes.Transaction, len(blobs)) for i := range blobs { blobCommitment := commitments[i] blobHash := blobCommitment.ToVersionedHash() txSidecar := &gethtypes.BlobTxSidecar{ Blobs: []kzg4844.Blob{kzg4844.Blob(blobs[i][:])}, Commitments: []kzg4844.Commitment{kzg4844.Commitment(blobCommitment)}, Proofs: []kzg4844.Proof{kzg4844.Proof(proofs[i])}, } blobTx, err := gethtypes.SignNewTx( simulated.GetTestKey(s.T()), gethtypes.NewCancunSigner(big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID()))), &gethtypes.BlobTx{ Nonce: uint64(i), // Set to 875000000 as that is the tx base fee GasTipCap: uint256.NewInt(875000000), GasFeeCap: uint256.NewInt(875000000), // Set to 21000 for minimum intrinsic gas Gas: 210000, Value: uint256.NewInt(0), Data: []byte{}, AccessList: nil, BlobFeeCap: uint256.NewInt(10), // If we have 1 tx with multiple blobs, we must add the blob hashes here. BlobHashes: []gethcommon.Hash{blobHash}, // Sidecar must be set to nil here or Geth will error with "unexpected blob sidecar in transaction" Sidecar: nil, }, ) s.Require().NoError(err) // Once we've signed the Tx, we tag the blob with the tx purely for association between tx and sidecars. // In this case, each 1 tx has a sidecar with 1 blob, even though 1 tx could have more than 1 blob. blobTx = blobTx.WithBlobTxSidecar(txSidecar) blobTxs[i] = blobTx } proposedBlockMessage := simulated.ComputeAndSetValidExecutionBlock( s.T(), proposedBlock.GetBeaconBlock(), s.SimulationClient, s.TestNode.ChainSpec, blobTxs, ) proposedBlockMessage.GetBody().SetBlobKzgCommitments(commitments) // Finalize the block by applying the state transition to update its state root. queryCtx, err := s.SimComet.CreateQueryContext(currentHeight-1, false) s.Require().NoError(err) proposedBlockMessage, err = simulated.ComputeAndSetStateRoot(queryCtx, consensusTime, nodeAddress, s.TestNode.StateProcessor, s.TestNode.StorageBackend, proposedBlockMessage) s.Require().NoError(err) newSignedBlock, err := ctypes.NewSignedBeaconBlock( proposedBlockMessage, &ctypes.ForkData{ CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(proposedBlockMessage.GetTimestamp()), GenesisValidatorsRoot: s.GenesisValidatorsRoot, }, s.TestNode.ChainSpec, blsSigner, ) s.Require().NoError(err) // Inject the new block newSignedBlockBytes, err := newSignedBlock.MarshalSSZ() s.Require().NoError(err) proposal.Txs[0] = newSignedBlockBytes // Create the beaconBlock Header for the sidecar blockWithCommitmentsSignedHeader := ctypes.NewSignedBeaconBlockHeader( newSignedBlock.GetHeader(), newSignedBlock.GetSignature(), ) sidecarsSlice := make([]*datypes.BlobSidecar, len(blobs)) // Build Inclusion Proofs for Sidecars sidecarFactory := dablob.NewSidecarFactory(metrics.NewNoOpTelemetrySink()) for i := range blobs { inclusionProof, err := sidecarFactory.BuildKZGInclusionProof(proposedBlockMessage.GetBody(), math.U64(i)) s.Require().NoError(err) // Malicious point: We tweak the inclusion proof inclusionProof[len(inclusionProof)-1] = common.Root{} sidecar := datypes.BuildBlobSidecar( math.U64(i), blockWithCommitmentsSignedHeader, blobs[i], commitments[i], proofs[i], inclusionProof, ) sidecarsSlice[i] = sidecar } sidecars := datypes.BlobSidecars(sidecarsSlice) // Inject theI sidecar sidecarBytes, err := sidecars.MarshalSSZ() s.Require().NoError(err) proposal.Txs[1] = sidecarBytes // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() // Process the proposal containing the block. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: consensusTime, }) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) s.Require().Contains(s.LogBuffer.String(), "invalid KZG commitment inclusion proof") } // testBuildInvalidBlock builds an invalid block, modifying it along what it is // specified in modifyBlock function. It is then properly resigned. func testBuildInvalidBlock( r *require.Assertions, builder simulated.SharedAccessors, PrepReq *types.PrepareProposalRequest, modifyBlock func(*ctypes.SignedBeaconBlock), ) [][]byte { blsSigner := simulated.GetBlsSigner(builder.HomeDir) pubkey, err := blsSigner.GetPubKey() r.NoError(err) signedBlk, sidecars, err := builder.SimComet.Comet.Blockchain.ParseBeaconBlock( &types.ProcessProposalRequest{ Txs: PrepReq.Txs, Height: PrepReq.Height, ProposerAddress: pubkey.Address(), Time: PrepReq.Time, }, ) r.NoError(err) modifyBlock(signedBlk) blk := signedBlk.BeaconBlock reSignedBlk, err := ctypes.NewSignedBeaconBlock( // resign to make sure signature checks pass blk, ctypes.NewForkData( builder.TestNode.ChainSpec.ActiveForkVersionForTimestamp(blk.GetTimestamp()), builder.GenesisValidatorsRoot, ), builder.TestNode.ChainSpec, blsSigner, ) r.NoError(err) signedBlkBytes, bbErr := reSignedBlk.MarshalSSZ() r.NoError(bbErr) res := make([][]byte, len(PrepReq.Txs)) res[0] = signedBlkBytes sidecarsBytes, scErr := sidecars.MarshalSSZ() r.NoError(scErr) res[1] = sidecarsBytes return res } ================================================ FILE: testing/simulated/orphaned_blobs_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/da/kzg" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/testing/simulated" "github.com/stretchr/testify/require" ) // TestOrphanedBlobCleanup tests that orphaned blob sidecars are properly cleaned up on node restart. // This simulates the scenario where sidecars are saved to disk but the block finalization fails. func (s *SimulatedSuite) TestOrphanedBlobCleanup() { // Initialize chain and move forward two blocks. s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) _, _, proposalTime := s.MoveChainToHeight(s.T(), 1, 2, nodeAddress, time.Now()) // Get the last committed block height. lastBlockHeight := s.SimComet.Comet.CommitMultiStore().LastCommitID().Version orphanedSlot := math.Slot(lastBlockHeight + 1) // Create and persist orphaned blob sidecars. // This simulates FinalizeSidecars succeeding but finalizeBeaconBlock failing. orphanedSidecars := createOrphanedSidecars(s.T(), orphanedSlot, s.TestNode.KZGVerifier) err = s.TestNode.StorageBackend.AvailabilityStore().Persist(orphanedSidecars) s.Require().NoError(err) // Verify orphaned blobs exist. sidecars, err := s.TestNode.StorageBackend.AvailabilityStore().GetBlobSidecars(orphanedSlot) s.Require().NoError(err) s.Require().Len(sidecars, 1) // Simulate node restart by calling PruneOrphanedBlobs. err = s.TestNode.Blockchain.PruneOrphanedBlobs(lastBlockHeight) s.Require().NoError(err) // Verify orphaned blobs were cleaned up. sidecars, err = s.TestNode.StorageBackend.AvailabilityStore().GetBlobSidecars(orphanedSlot) s.Require().NoError(err) s.Require().Empty(sidecars) // Verify chain continues normally. proposals, _, _ := s.MoveChainToHeight(s.T(), 3, 1, nodeAddress, proposalTime) s.Require().Len(proposals, 1) } // createOrphanedSidecars creates fake blob sidecars for testing orphaned blob cleanup. func createOrphanedSidecars( t require.TestingT, slot math.Slot, verifier kzg.BlobProofVerifier, ) datypes.BlobSidecars { blobs := []*eip4844.Blob{{1, 2, 3}} proofs, commitments := simulated.GetProofAndCommitmentsForBlobs(require.New(t), blobs, verifier) sidecars := make(datypes.BlobSidecars, len(blobs)) for i := range blobs { sidecars[i] = datypes.BuildBlobSidecar( math.U64(i), &ctypes.SignedBeaconBlockHeader{ Header: &ctypes.BeaconBlockHeader{Slot: slot}, Signature: crypto.BLSSignature{}, }, blobs[i], commitments[i], proofs[i], make([]common.Root, ctypes.KZGInclusionProofDepth), ) } return sidecars } ================================================ FILE: testing/simulated/payload_cache_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "context" "math/big" "path" "strings" "testing" "time" "github.com/berachain/beacon-kit/beacon/blockchain" svcencoding "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/net/url" "github.com/berachain/beacon-kit/testing/simulated" "github.com/berachain/beacon-kit/testing/simulated/execution" "github.com/cometbft/cometbft/abci/types" cmtcfg "github.com/cometbft/cometbft/config" gethcommon "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/holiman/uint256" "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) // PayloadCacheSuite defines our test suite for Pectra related work using simulated Comet component. type PayloadCacheSuite struct { suite.Suite Geth simulated.SharedAccessors Reth simulated.SharedAccessors Reth2 simulated.SharedAccessors } // TestPayloadCacheSuite runs the test suite. func TestPayloadCacheSuite(t *testing.T) { suite.Run(t, new(PayloadCacheSuite)) } // SetupTest initializes the test environment. func (s *PayloadCacheSuite) SetupTest() { testName := s.T().Name() useThirdValidatorSetup := strings.Contains( testName, "TestReth_MisorderedBlobSidecarsCachedEnvelope_IsSuccessful", ) // Create a cancellable context for the duration of the test. s.Geth.CtxApp, s.Geth.CtxAppCancelFn = context.WithCancel(context.Background()) s.Reth.CtxApp, s.Reth.CtxAppCancelFn = context.WithCancel(context.Background()) if useThirdValidatorSetup { s.Reth2.CtxApp, s.Reth2.CtxAppCancelFn = context.WithCancel(context.Background()) } // CometBFT uses context.TODO() for all ABCI calls, so we replicate that. s.Geth.CtxComet = context.TODO() s.Geth.HomeDir = s.T().TempDir() s.Reth.CtxComet = context.TODO() s.Reth.HomeDir = s.T().TempDir() if useThirdValidatorSetup { s.Reth2.CtxComet = context.TODO() s.Reth2.HomeDir = s.T().TempDir() } // Initialize the home directory, Comet configuration, and genesis info. const elGenesisPath = "./el-genesis-files/pectra-fork-genesis.json" chainSpecFunc := simulated.ProvidePectraForkTestChainSpec // Create the chainSpec. chainSpec, err := chainSpecFunc() s.Require().NoError(err) var ( gethCmtCfg *cmtcfg.Config rethCmtCfg *cmtcfg.Config reth2CmtCfg *cmtcfg.Config ) if useThirdValidatorSetup { configs, root := simulated.InitializeHomeDirs( s.T(), chainSpec, elGenesisPath, s.Geth.HomeDir, s.Reth.HomeDir, s.Reth2.HomeDir, ) gethCmtCfg, rethCmtCfg, reth2CmtCfg = configs[0], configs[1], configs[2] s.Geth.GenesisValidatorsRoot = root s.Reth.GenesisValidatorsRoot = root s.Reth2.GenesisValidatorsRoot = root } else { configs, root := simulated.InitializeHomeDirs( s.T(), chainSpec, elGenesisPath, s.Geth.HomeDir, s.Reth.HomeDir, ) gethCmtCfg, rethCmtCfg = configs[0], configs[1] s.Geth.GenesisValidatorsRoot = root s.Reth.GenesisValidatorsRoot = root } // Start the EL (execution layer) Geth node. gethNode := execution.NewGethNode(s.Geth.HomeDir, execution.ValidGethImage()) elHandle, authRPC, elRPC := gethNode.Start(s.T(), path.Base(elGenesisPath)) s.Geth.ElHandle = elHandle // Choose the reth node to run. 2 specific tests require the engine api override flag. var ( rethNode *execution.ExecNode reth2Node *execution.ExecNode ) if strings.Contains(testName, "TestReth_MustRebuildPostForkPayload_IsSuccessful") || strings.Contains(testName, "TestReth_MustRebuildPreForkPayload_IsSuccessful") { rethNode = execution.NewRethNodeWithEngineOverride(s.Reth.HomeDir, execution.ValidRethImage()) if useThirdValidatorSetup { reth2Node = execution.NewRethNodeWithEngineOverride(s.Reth2.HomeDir, execution.ValidRethImage()) } } else { rethNode = execution.NewRethNode(s.Reth.HomeDir, execution.ValidRethImage()) if useThirdValidatorSetup { reth2Node = execution.NewRethNode(s.Reth2.HomeDir, execution.ValidRethImage()) } } rethHandle, rethAuthRPC, rethRPC := rethNode.Start(s.T(), path.Base(elGenesisPath)) s.Reth.ElHandle = rethHandle var ( reth2Handle *execution.Resource reth2AuthRPC *url.ConnectionURL reth2RPC *url.ConnectionURL ) if useThirdValidatorSetup { reth2Handle, reth2AuthRPC, reth2RPC = reth2Node.Start(s.T(), path.Base(elGenesisPath)) s.Reth2.ElHandle = reth2Handle } // Prepare a logger backed by a buffer to capture logs for assertions. s.Geth.LogBuffer = &simulated.SyncBuffer{} logger := phuslu.NewLogger(s.Geth.LogBuffer, nil) s.Reth.LogBuffer = &simulated.SyncBuffer{} rethLogger := phuslu.NewLogger(s.Reth.LogBuffer, nil) var reth2Logger *phuslu.Logger if useThirdValidatorSetup { s.Reth2.LogBuffer = &simulated.SyncBuffer{} reth2Logger = phuslu.NewLogger(s.Reth2.LogBuffer, nil) } // Build the Beacon node with the simulated Comet component and electra genesis chain spec components := simulated.FixedComponents(s.T()) components = append(components, simulated.ProvideSimComet) components = append(components, chainSpecFunc) s.Geth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.Geth.HomeDir, CometConfig: gethCmtCfg, AuthRPC: authRPC, ClientRPC: elRPC, Logger: logger, AppOpts: viper.New(), Components: components, }) s.Geth.SimComet = s.Geth.TestNode.SimComet nodeAddress, err := s.Geth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) s.Reth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.Reth.HomeDir, CometConfig: rethCmtCfg, AuthRPC: rethAuthRPC, ClientRPC: rethRPC, Logger: rethLogger, AppOpts: viper.New(), Components: components, }) s.Reth.SimComet = s.Reth.TestNode.SimComet nodeAddress, err = s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth.SimComet.Comet.SetNodeAddress(nodeAddress) if useThirdValidatorSetup { s.Reth2.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.Reth2.HomeDir, CometConfig: reth2CmtCfg, AuthRPC: reth2AuthRPC, ClientRPC: reth2RPC, Logger: reth2Logger, AppOpts: viper.New(), Components: components, }) s.Reth2.SimComet = s.Reth2.TestNode.SimComet nodeAddress, err = s.Reth2.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth2.SimComet.Comet.SetNodeAddress(nodeAddress) } // Start the Beacon node in a separate goroutine. go func() { _ = s.Geth.TestNode.Start(s.Geth.CtxApp) }() // Start the Beacon node in a separate goroutine. go func() { _ = s.Reth.TestNode.Start(s.Reth.CtxApp) }() if useThirdValidatorSetup { go func() { _ = s.Reth2.TestNode.Start(s.Reth2.CtxApp) }() } s.Geth.SimulationClient = execution.NewSimulationClient(s.Geth.TestNode.EngineClient) // Reth does not have a simulation API timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.Geth.LogBuffer, timeOut, interval) s.Require().NoError(err) err = simulated.WaitTillServicesStarted(s.Reth.LogBuffer, timeOut, interval) s.Require().NoError(err) if useThirdValidatorSetup { err = simulated.WaitTillServicesStarted(s.Reth2.LogBuffer, timeOut, interval) s.Require().NoError(err) } } // TearDownTest cleans up the test environment. func (s *PayloadCacheSuite) TearDownTest() { s.Geth.CleanupTestWithLabel(s.T(), "GETH") s.Reth.CleanupTestWithLabel(s.T(), "RETH") s.Reth2.CleanupTestWithLabel(s.T(), "RETH2") } // This tests a reth validator proposing a block. It then accepts the proposal in // process proposal. But the block is not finalized by consensus. Then this // validator is chosen to propose at a subsequent round. It should just get the old // payload from its cache. func (s *PayloadCacheSuite) TestReth_ReusePayload_IsSuccessful() { // Initialize the chain state. s.Reth.InitializeChain(s.T(), 2) // 1 reth validator nodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth.SimComet.Comet.SetNodeAddress(nodeAddress) // Next block is height 1. nextBlockHeight := int64(1) consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) { // Prepare the proposal. proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // This will trigger a optimistic payload build for block height 2. processResp, respErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) } // For some reason, the supermajority does not finalize the block. // Next round is height 1, but simulating consensus time is 1 second after previous round. time.Sleep(200 * time.Millisecond) // This lets the optimistic build complete. consensusTime = time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime())+1, 0) { // Prepare the proposal. Bkit cached the payload ID, so we just get the old one from reth. proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // Process the proposal. processResp, processErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Now the block is finalized and committed. finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, } _, finalizeErr := s.Reth.SimComet.Comet.FinalizeBlock(s.Reth.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) _, commitErr := s.Reth.SimComet.Comet.Commit(s.Reth.CtxComet, &types.CommitRequest{}) s.Require().NoError(commitErr) } } // This tests a geth validator proposing a block. It then accepts the proposal in // process proposal. But the block is not finalized by consensus. Then this // validator is chosen to propose at a subsequent round. It should just get the old // payload from its cache. func (s *PayloadCacheSuite) TestGeth_ReusePayload_IsSuccessful() { // Initialize the chain state. s.Geth.InitializeChain(s.T(), 2) // 1 geth validator nodeAddress, err := s.Geth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) // Next block is height 1. nextBlockHeight := int64(1) consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) { // Prepare the proposal. proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // This will trigger a optimistic payload build for block height 2. processResp, respErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) } // For some reason, the supermajority does not finalize the block. // Next round is height 1, but simulating consensus time is 1 second after previous round. time.Sleep(200 * time.Millisecond) // This lets the optimistic build complete. consensusTime = time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime())+1, 0) { // Prepare the proposal. Bkit cached the payload ID, so we just get the old one from geth. proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // Process the proposal. processResp, processErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Now the block is finalized and committed. finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, } _, finalizeErr := s.Geth.SimComet.Comet.FinalizeBlock(s.Geth.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) _, commitErr := s.Geth.SimComet.Comet.Commit(s.Geth.CtxComet, &types.CommitRequest{}) s.Require().NoError(commitErr) } } // This tests a reth validator proposing a invalid block. The proposal is rejected. Then this // validator is chosen to propose at a subsequent round. It should now be forced to // rebuild a new payload (and not reuse the old one from its cache). func (s *PayloadCacheSuite) TestReth_RebuildPayload_IsSuccessful() { // Initialize the chain state. s.Reth.InitializeChain(s.T(), 2) // 1 reth validator nodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth.SimComet.Comet.SetNodeAddress(nodeAddress) // Next block is height 1. nextBlockHeight := int64(1) consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) { // Prepare an invalid proposal. faultyConsensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime())-1, 0) proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: faultyConsensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // As we reject our own built proposal, bkit should evict this payload from its cache. processResp, respErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) s.Require().Contains( s.Reth.LogBuffer.String(), "failed decoding *types.SignedBeaconBlock: ssz: offset smaller than previous", ) } // Subsequent round where we are selected to propose again. { // Prepare the valid proposal. This should now request the EL for a new payload. proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // Process the proposal. processResp, processErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Now the block is finalized and committed. finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, } _, finalizeErr := s.Reth.SimComet.Comet.FinalizeBlock(s.Reth.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) _, commitErr := s.Reth.SimComet.Comet.Commit(s.Reth.CtxComet, &types.CommitRequest{}) s.Require().NoError(commitErr) } } // This tests a geth validator proposing a invalid block. The proposal is rejected. Then this // validator is chosen to propose at a subsequent round. It should now be forced to // rebuild a new payload (and not reuse the old one from its cache). func (s *PayloadCacheSuite) TestGeth_RebuildPayload_IsSuccessful() { // Initialize the chain state. s.Geth.InitializeChain(s.T(), 2) // 1 geth validator nodeAddress, err := s.Geth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) // Next block is height 1. nextBlockHeight := int64(1) consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) { // Prepare an invalid proposal. faultyConsensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime())-1, 0) proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: faultyConsensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // As we reject our own built proposal, bkit should evict this payload from its cache. processResp, respErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) s.Require().Contains( s.Geth.LogBuffer.String(), "failed decoding *types.SignedBeaconBlock: ssz: offset smaller than previous", ) } // Subsequent round where we are selected to propose again. { // Prepare the valid proposal. This should now request the EL for a new payload. proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // Process the proposal. processResp, processErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Now the block is finalized and committed. finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, } _, finalizeErr := s.Geth.SimComet.Comet.FinalizeBlock(s.Geth.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) _, commitErr := s.Geth.SimComet.Comet.Commit(s.Geth.CtxComet, &types.CommitRequest{}) s.Require().NoError(commitErr) } } // Test a scenario where the first proposed block is pre-fork and accepted initially but never // finalized by the network (which triggeres optimistic builds). The subsequent rounds are now // post-fork. Only reth with the flag can force rebuild a payload. // // NOTE: this test requires reth with the --engine.always-process-payload-attributes-on-canonical-head flag. func (s *PayloadCacheSuite) TestReth_MustRebuildPostForkPayload_IsSuccessful() { // Initialize the chain state. s.Geth.InitializeChain(s.T(), 2) // 1 geth validator gethNodeAddress, err := s.Geth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Geth.SimComet.Comet.SetNodeAddress(gethNodeAddress) s.Reth.InitializeChain(s.T(), 2) // 1 reth validator rethNodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth.SimComet.Comet.SetNodeAddress(rethNodeAddress) // Next block is height 1. nextBlockHeight := int64(1) consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()-1), 0) { // Prepare the proposal. proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: gethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal, with no payload eviction from bkit cache. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: gethNodeAddress, Time: consensusTime, NextProposerAddress: gethNodeAddress, } // This will trigger a optimistic payload build for block height 2. processResp, respErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Reth also prepares proposal. proposal, prepareErr = s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: rethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal, with no payload eviction from bkit cache. processRequest = &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: rethNodeAddress, Time: consensusTime, NextProposerAddress: rethNodeAddress, } // This will trigger a optimistic payload build for block height 2. processResp, respErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) } // For some reason, the supermajority does not finalize the block. // We are now crossing over into post-fork time. // Next round is height 1, but simulating consensus time is 1 second after previous round. time.Sleep(10 * time.Millisecond) // Next round. { // Try to build a new (pre-fork) payload from geth EL. // NOTE: this will fail because geth does not allow re-building a payload for a height // that has already been marked safe/finalized consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: gethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 0) // Geth returns an empty proposal. } time.Sleep(10 * time.Millisecond) // Next round. { // Try to build a new post-fork payload from reth EL. This works because the reth flag // allows us to rebuild a payload that has already been marked safe/finalized. consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: rethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: rethNodeAddress, Time: consensusTime, NextProposerAddress: rethNodeAddress, } processResp, respErr := s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) processResp, respErr = s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) } } // Test a scenario where the first proposed block is post-fork and accepted initially but never // finalized by the network (which triggeres optimistic builds). The subsequent rounds are actually // pre-fork. Only reth with the flag can force rebuild a payload. // // NOTE: this test requires reth with the --engine.always-process-payload-attributes-on-canonical-head flag // to propose the valid pre-fork block. func (s *PayloadCacheSuite) TestReth_MustRebuildPreForkPayload_IsSuccessful() { // Initialize the chain state. s.Geth.InitializeChain(s.T(), 2) gethNodeAddress, err := s.Geth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth.InitializeChain(s.T(), 2) rethNodeAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) nextBlockHeight := int64(1) // Both reth and geth prepare and propose a post-fork block without finalizing. { consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) // Geth builds. proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: gethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Geth processes the proposal. No bkit payload eviction here. // Optimistically build the next height's payload. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: gethNodeAddress, Time: consensusTime, NextProposerAddress: gethNodeAddress, } s.Geth.LogBuffer.Reset() processResp, respErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) // Reth also builds. proposal, prepareErr = s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: rethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Reth processes the proposal. No bkit payload eviction here. // Optimistically build the next height's payload. processRequest = &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: rethNodeAddress, Time: consensusTime, NextProposerAddress: rethNodeAddress, } s.Reth.LogBuffer.Reset() processResp, respErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) } time.Sleep(100 * time.Millisecond) // Next round. // The previous payload in cache has been evicted. The optimistic builds for next height // should have completed by now. { // Try to build a new (pre-fork) payload from geth EL. // NOTE: this will fail because geth does not allow re-building a payload for a height // that has already been marked safe/finalized consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime())-2, 0) prepareReq := &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: gethNodeAddress, } proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, prepareReq) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 0) // Geth returns an empty proposal. } time.Sleep(10 * time.Millisecond) // Next round. // The next block the proposer proposes with a pre-fork timestamp will actually have a pre-fork time // Since the previous payload in cache has been evicted, a new payload is built and retrieved. { // Force build a new (pre-fork) payload from reth EL. // NOTE: this requires --engine.always-process-payload-attributes-on-canonical-head. consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime())-1, 0) proposal, prepareErr := s.Reth.SimComet.Comet.PrepareProposal(s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: rethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: rethNodeAddress, Time: consensusTime, NextProposerAddress: gethNodeAddress, } // Process the proposal. No bkit payload eviction here from cache. Also trigger an optimistic // build for next height. s.Geth.LogBuffer.Reset() processResp, processErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) // Reth also process proposal and does not evict payload from bkit cache. s.Reth.LogBuffer.Reset() processResp, processErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Finalize the block. Evict bkit payload here because finalize is accepted. finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: rethNodeAddress, Time: consensusTime, } _, finalizeErr := s.Geth.SimComet.Comet.FinalizeBlock(s.Geth.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) _, finalizeErr = s.Reth.SimComet.Comet.FinalizeBlock(s.Reth.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) // Commit the block. _, err := s.Geth.SimComet.Comet.Commit(s.Geth.CtxComet, &types.CommitRequest{}) s.Require().NoError(err) s.Geth.LogBuffer.Reset() _, err = s.Reth.SimComet.Comet.Commit(s.Reth.CtxComet, &types.CommitRequest{}) s.Require().NoError(err) s.Reth.LogBuffer.Reset() } // Finally, we cross the fork and show no issues. Geth uses the optimistic build which has the // correct payload time and consequently is built correctly for post-fork. nextBlockHeight++ time.Sleep(100 * time.Millisecond) // The optimistic build for next height should have completed by now. { consensusTime := time.Unix(int64(s.Geth.TestNode.ChainSpec.ElectraForkTime()), 0) proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: gethNodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: gethNodeAddress, Time: consensusTime, } // Process the proposal. processResp, processErr := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) s.Require().Contains(s.Geth.LogBuffer.String(), "Processing execution requests") processResp, processErr = s.Reth.SimComet.Comet.ProcessProposal(s.Reth.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) s.Require().Contains(s.Reth.LogBuffer.String(), "Processing execution requests") } } // This tests a malicious proposer that reorders blob sidecars in a proposal. // Another validator accepts and caches the payload envelope without finalizing. // In a subsequent round at the same height, the caching validator proposes again // from cache and a third validator accepts that proposal. func (s *PayloadCacheSuite) TestReth_MisorderedBlobSidecarsCachedEnvelope_IsSuccessful() { // Initialize chain state with 3 validators. s.Geth.InitializeChain(s.T(), 3) s.Reth.InitializeChain(s.T(), 3) s.Reth2.InitializeChain(s.T(), 3) // validator A: malicious proposer. maliciousProposerAddress, err := s.Geth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Geth.SimComet.Comet.SetNodeAddress(maliciousProposerAddress) // validator B: verifies malicious proposal and later proposes from cache. cachingValidatorAddress, err := s.Reth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth.SimComet.Comet.SetNodeAddress(cachingValidatorAddress) // validator C: verifies validator B's subsequent proposal. verifyingValidatorAddress, err := s.Reth2.SimComet.GetNodeAddress() s.Require().NoError(err) s.Reth2.SimComet.Comet.SetNodeAddress(verifyingValidatorAddress) nextBlockHeight := int64(1) consensusTime := time.Unix(int64(s.Reth.TestNode.ChainSpec.ElectraForkTime()), 0) // Seed proposer A's EL with blob txs so the proposal has reorderable sidecars. s.submitBlobTransactions(s.Geth, 2) var ( proposal *types.PrepareProposalResponse reorderedTx bool ) for i := 0; i < 10; i++ { proposal, err = s.Geth.SimComet.Comet.PrepareProposal( s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: maliciousProposerAddress, }, ) s.Require().NoError(err) s.Require().Len(proposal.Txs, 2) sidecars, scErr := svcencoding.UnmarshalBlobSidecarsFromABCIRequest( proposal.Txs, blockchain.BlobSidecarsTxIndex, ) s.Require().NoError(scErr) if len(sidecars) < 2 { time.Sleep(200 * time.Millisecond) continue // NOTE: we retry at most 10 times, with 200ms delay between retries. } // Maliciously reorder two sidecars in the proposal. sidecars[0], sidecars[1] = sidecars[1], sidecars[0] sidecarBytes, marshalErr := sidecars.MarshalSSZ() s.Require().NoError(marshalErr) proposal.Txs[blockchain.BlobSidecarsTxIndex] = sidecarBytes reorderedTx = true break } s.Require().True( reorderedTx, "expected at least 2 blob sidecars so the malicious proposer can reorder them", ) // validator B verifies and accepts the maliciously-ordered proposal. This caches the // payload envelope, but the block never finalizes. processResp, err := s.Reth.SimComet.Comet.ProcessProposal( s.Reth.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: maliciousProposerAddress, Time: consensusTime, NextProposerAddress: cachingValidatorAddress, }, ) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Next round at same height; validator B now proposes from cached envelope. time.Sleep(200 * time.Millisecond) consensusTime = consensusTime.Add(time.Second) cachedProposal, err := s.Reth.SimComet.Comet.PrepareProposal( s.Reth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: cachingValidatorAddress, }, ) s.Require().NoError(err) s.Require().Len(cachedProposal.Txs, 2) // Ensure the proposal from cache carries sidecars in canonical index order. cachedSidecars, err := svcencoding.UnmarshalBlobSidecarsFromABCIRequest( cachedProposal.Txs, blockchain.BlobSidecarsTxIndex, ) s.Require().NoError(err) s.Require().GreaterOrEqual(len(cachedSidecars), 2) for i := 1; i < len(cachedSidecars); i++ { s.Require().GreaterOrEqual( cachedSidecars[i].GetIndex(), cachedSidecars[i-1].GetIndex(), ) } // validator C verifies the cached proposal and accepts it. processResp, err = s.Reth2.SimComet.Comet.ProcessProposal( s.Reth2.CtxComet, &types.ProcessProposalRequest{ Txs: cachedProposal.Txs, Height: nextBlockHeight, ProposerAddress: cachingValidatorAddress, Time: consensusTime, NextProposerAddress: verifyingValidatorAddress, }, ) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) } func (s *PayloadCacheSuite) submitBlobTransactions(node simulated.SharedAccessors, numBlobs int) { s.T().Helper() s.Require().GreaterOrEqual(numBlobs, 2) blobs := make([]*eip4844.Blob, numBlobs) for i := range blobs { blob := &eip4844.Blob{} blob[0] = byte(i + 1) blob[1] = byte(i + 2) blobs[i] = blob } proofs, commitments := simulated.GetProofAndCommitmentsForBlobs( require.New(s.T()), blobs, node.TestNode.KZGVerifier, ) testKey := simulated.GetTestKey(s.T()) chainID := node.TestNode.ChainSpec.DepositEth1ChainID() signer := gethtypes.NewCancunSigner(big.NewInt(int64(chainID))) senderAddress := crypto.PubkeyToAddress(testKey.PublicKey) recipientAddress := gethcommon.HexToAddress(simulated.WithdrawalExecutionAddress) nextNonce, err := node.TestNode.ContractBackend.PendingNonceAt(node.CtxApp, senderAddress) s.Require().NoError(err) for i := 0; i < numBlobs; i++ { txSidecar := &gethtypes.BlobTxSidecar{ Blobs: []kzg4844.Blob{kzg4844.Blob(blobs[i][:])}, Commitments: []kzg4844.Commitment{kzg4844.Commitment(commitments[i])}, Proofs: []kzg4844.Proof{kzg4844.Proof(proofs[i])}, } blobHash := commitments[i].ToVersionedHash() blobTx, signErr := gethtypes.SignNewTx( testKey, signer, &gethtypes.BlobTx{ ChainID: uint256.NewInt(chainID), Nonce: nextNonce + uint64(i), GasTipCap: uint256.NewInt(10_000_000_000), GasFeeCap: uint256.NewInt(10_000_000_000), Gas: 210000, To: recipientAddress, Value: uint256.NewInt(0), Data: []byte{}, AccessList: nil, BlobFeeCap: uint256.NewInt(10_000_000_000), BlobHashes: []gethcommon.Hash{blobHash}, // Sidecar must be nil on signing; we attach it immediately after. Sidecar: nil, }, ) s.Require().NoError(signErr) blobTx = blobTx.WithBlobTxSidecar(txSidecar) sendErr := node.TestNode.ContractBackend.SendTransaction(node.CtxApp, blobTx) s.Require().NoError(sendErr) } for i := 0; i < 10; i++ { pendingNonce, nonceErr := node.TestNode.ContractBackend.PendingNonceAt(node.CtxApp, senderAddress) s.Require().NoError(nonceErr) if pendingNonce >= nextNonce+uint64(numBlobs) { return } time.Sleep(100 * time.Millisecond) } s.T().Fatalf("blob transactions did not enter txpool in time") } ================================================ FILE: testing/simulated/pectra_fork_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "context" "math/big" "path" "testing" "time" "github.com/berachain/beacon-kit/beacon/blockchain" payloadtime "github.com/berachain/beacon-kit/beacon/payload-time" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" "github.com/berachain/beacon-kit/execution/requests/eip7251" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/testing/simulated" "github.com/berachain/beacon-kit/testing/simulated/execution" "github.com/cometbft/cometbft/abci/types" "github.com/ethereum/go-ethereum/common/hexutil" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) // PectraForkSuite defines our test suite for Pectra related work using simulated Comet component. type PectraForkSuite struct { suite.Suite Geth simulated.SharedAccessors Reth simulated.SharedAccessors } // TestPectraForkSuite runs the test suite. func TestPectraForkSuite(t *testing.T) { suite.Run(t, new(PectraForkSuite)) } // SetupTest initializes the test environment. func (s *PectraForkSuite) SetupTest() { // Create a cancellable context for the duration of the test. s.Geth.CtxApp, s.Geth.CtxAppCancelFn = context.WithCancel(context.Background()) s.Reth.CtxApp, s.Reth.CtxAppCancelFn = context.WithCancel(context.Background()) // CometBFT uses context.TODO() for all ABCI calls, so we replicate that. s.Geth.CtxComet = context.TODO() s.Geth.HomeDir = s.T().TempDir() s.Reth.CtxComet = context.TODO() s.Reth.HomeDir = s.T().TempDir() // Initialize the home directory, Comet configuration, and genesis info. const elGenesisPath = "./el-genesis-files/pectra-fork-genesis.json" chainSpecFunc := simulated.ProvidePectraForkTestChainSpec // Create the chainSpec. chainSpec, err := chainSpecFunc() s.Require().NoError(err) configs, genesisValidatorsRoot := simulated.InitializeHomeDirs(s.T(), chainSpec, elGenesisPath, s.Geth.HomeDir) cometConfig := configs[0] s.Geth.GenesisValidatorsRoot = genesisValidatorsRoot s.Reth.GenesisValidatorsRoot = genesisValidatorsRoot // Copy the home dir for the Reth Node simulated.CopyHomeDir(s.T(), s.Geth.HomeDir, s.Reth.HomeDir) // Start the EL (execution layer) Geth node. gethNode := execution.NewGethNode(s.Geth.HomeDir, execution.ValidGethImage()) elHandle, authRPC, elRPC := gethNode.Start(s.T(), path.Base(elGenesisPath)) s.Geth.ElHandle = elHandle rethNode := execution.NewRethNode(s.Reth.HomeDir, execution.ValidRethImage()) rethHandle, rethAuthRPC, elRPC := rethNode.Start(s.T(), path.Base(elGenesisPath)) s.Reth.ElHandle = rethHandle // Prepare a logger backed by a buffer to capture logs for assertions. s.Geth.LogBuffer = &simulated.SyncBuffer{} logger := phuslu.NewLogger(s.Geth.LogBuffer, nil) s.Reth.LogBuffer = &simulated.SyncBuffer{} rethLogger := phuslu.NewLogger(s.Reth.LogBuffer, nil) // Build the Beacon node with the simulated Comet component and electra genesis chain spec components := simulated.FixedComponents(s.T()) components = append(components, simulated.ProvideSimComet) components = append(components, chainSpecFunc) s.Geth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.Geth.HomeDir, CometConfig: cometConfig, AuthRPC: authRPC, ClientRPC: elRPC, Logger: logger, AppOpts: viper.New(), Components: components, }) s.Geth.SimComet = s.Geth.TestNode.SimComet s.Reth.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.Reth.HomeDir, CometConfig: cometConfig, AuthRPC: rethAuthRPC, ClientRPC: elRPC, Logger: rethLogger, AppOpts: viper.New(), Components: components, }) s.Reth.SimComet = s.Reth.TestNode.SimComet // Start the Beacon node in a separate goroutine. go func() { _ = s.Geth.TestNode.Start(s.Geth.CtxApp) }() // Start the Beacon node in a separate goroutine. go func() { _ = s.Reth.TestNode.Start(s.Reth.CtxApp) }() s.Geth.SimulationClient = execution.NewSimulationClient(s.Geth.TestNode.EngineClient) // Reth does not have a simulation API timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.Geth.LogBuffer, timeOut, interval) s.Require().NoError(err) err = simulated.WaitTillServicesStarted(s.Reth.LogBuffer, timeOut, interval) s.Require().NoError(err) } // TearDownTest cleans up the test environment. func (s *PectraForkSuite) TearDownTest() { s.Geth.CleanupTestWithLabel(s.T(), "GETH") s.Reth.CleanupTestWithLabel(s.T(), "RETH") } // TestTimestampFork_ELAndCLInSync_IsSuccessful tests that we can fork successfully if EL and CL have synced timestamps // The forks timestamp at Unix 0, as the genesis at Unix 0, Cancun is at 10 and Prague is at 20. // The Geth Node will be the block producer but the Reth node is treated as a full node, i.e. doesn't produce blocks. func (s *PectraForkSuite) TestTimestampFork_ELAndCLInSync_IsSuccessful() { // Initialize the geth chain state. s.Geth.InitializeChain(s.T(), 1) // Initialize the reth chain state. s.Reth.InitializeChain(s.T(), 1) nodeAddress, err := s.Geth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) expectedMessages := []string{ "Processing block with fork version service=blockchain\u001B[0m block=1\u001B[0m fork=0x04010000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=2\u001B[0m fork=0x04010000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=3\u001B[0m fork=0x04010000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=4\u001B[0m fork=0x04010000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=5\u001B[0m fork=0x04010000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=6\u001B[0m fork=0x04010000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=7\u001B[0m fork=0x04010000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=8\u001B[0m fork=0x04010000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=9\u001B[0m fork=0x05000000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=10\u001B[0m fork=0x05000000\u001B[0m", "Processing block with fork version service=blockchain\u001B[0m block=11\u001B[0m fork=0x05000000\u001B[0m", } var ( startHeight = int64(1) iterations = int64(len(expectedMessages)) expectedMessagesIdx = 0 submitTxNonce = uint64(0) consensusTime = time.Unix(startHeight*2, 0) ) for currentHeight := startHeight; currentHeight < startHeight+iterations; currentHeight++ { submitTxNonce = s.submitTransactions(submitTxNonce, 100) proposal, err := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: consensusTime, } expectedMessage := expectedMessages[expectedMessagesIdx] processFinalizeCommit(s.T(), s.Geth, processRequest, finalizeRequest, expectedMessage) processFinalizeCommit(s.T(), s.Reth, processRequest, finalizeRequest, expectedMessage) expectedMessagesIdx++ // set consensus time for the next block to match // the timestamp of the payload built optimistically. forkVersion := s.Geth.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())) //#nosec: G115 blk, _, err := encoding.ExtractBlobsAndBlockFromRequest( processRequest, blockchain.BeaconBlockTxIndex, blockchain.BlobSidecarsTxIndex, forkVersion, ) s.Require().NoError(err) consensusTime = time.Unix( int64(payloadtime.Next(blk.GetTimestamp(), blk.GetTimestamp(), true)), 0, ) } } // A user makes a consolidation request on our chain which isn't supported. func (s *PectraForkSuite) TestMaliciousUser_MakesConsolidationRequest_IsIgnored() { // Initialize the chain state. s.Geth.InitializeChain(s.T(), 1) s.Reth.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.Geth.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) nextBlockHeight := int64(1) // We must first move the chain to the fork height, then an extra block // such that the consolidation contract has an updated `EXCESS_INHIBITOR`. // We set the timestamp such that the fork has occurred (i.e., time.Now) { for i := 0; i < 2; i++ { consensusTime := time.Now() proposal, err := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, } expectedMsg := "fork=0x05000000" processFinalizeCommit(s.T(), s.Geth, processRequest, finalizeRequest, expectedMsg) processFinalizeCommit(s.T(), s.Reth, processRequest, finalizeRequest, expectedMsg) nextBlockHeight++ } } // Next we submit the Consolidation request transaction { // corresponds with the funded address in genesis senderKey, err := crypto.HexToECDSA("fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306") s.Require().NoError(err) elChainID := big.NewInt(int64(s.Geth.TestNode.ChainSpec.DepositEth1ChainID())) signer := gethtypes.NewPragueSigner(elChainID) fee, feeErr := eip7251.GetConsolidationFee(s.Geth.CtxApp, s.Geth.TestNode.EngineClient) s.Require().NoError(feeErr) // The inputs to the request do not necessarily matter, as long as they pass EL validation consolidationTxData, requestErr := eip7251.CreateConsolidationRequestData(blsSigner.PublicKey(), blsSigner.PublicKey()) s.Require().NoError(requestErr) consolidationTx := gethtypes.MustSignNewTx(senderKey, signer, &gethtypes.DynamicFeeTx{ ChainID: elChainID, Nonce: 0, To: ¶ms.ConsolidationQueueAddress, Gas: 500_000, GasFeeCap: big.NewInt(1000000000), GasTipCap: big.NewInt(1000000000), Value: fee, Data: consolidationTxData, }) txBytes, marshalErr := consolidationTx.MarshalBinary() s.Require().NoError(marshalErr) var result interface{} err = s.Geth.TestNode.EngineClient.Call(s.Geth.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) s.Require().NoError(err) time.Sleep(time.Second) // give it time to allow the tx to be included in the next block } // Move the chain so that tx is included and progresses correctly afterward. { for i := 0; i < 5; i++ { consensusTime := time.Now() proposal, err := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, } var expectedMsg string if i == 0 { // The first block since tx submission will have the consolidation propagated to the CL. expectedMsg = "consolidations=1" } processFinalizeCommit(s.T(), s.Geth, processRequest, finalizeRequest, expectedMsg) processFinalizeCommit(s.T(), s.Reth, processRequest, finalizeRequest, expectedMsg) nextBlockHeight++ } } } // This test will have a proposer propose a valid post-fork block, but one that is not finalized. // The next round will propose a valid pre-fork block that gets finalized due to deviance in the consensus timestamp. // The proposer will then propose a valid post-fork block that is correctly finalized. func (s *PectraForkSuite) TestValidProposer_ProposesPostForkBlockIsNotFinalized_IsSuccessful() { client := s.Geth helper := s.Reth // Initialize the chain state. client.InitializeChain(s.T(), 1) helper.InitializeChain(s.T(), 1) // helper to build "invalid" blocks nodeAddress, err := client.SimComet.GetNodeAddress() s.Require().NoError(err) client.SimComet.Comet.SetNodeAddress(nodeAddress) nextBlockHeight := int64(1) var proposal *types.PrepareProposalResponse // 1 - Build a block whose consensus and payloadTimestamp are both post-fork. // Check that it verifies, but do not finalize it { consensusTime := time.Unix(int64(client.TestNode.ChainSpec.ElectraForkTime()), 0) prepareReq := &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, } proposal, err = helper.SimComet.Comet.PrepareProposal(helper.CtxComet, prepareReq) s.Require().NoError(err) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // Process the proposal client.LogBuffer.Reset() processResp, respErr := client.SimComet.Comet.ProcessProposal(client.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) } // 2 - Build a block whose consensus timestamp is pre-fork, while the payload is post fork. // Check that it does not verifies. // Note: to build the invalid block we reuse the beaconBlock from point 1 and just change CometBFT timestamp { maliciouConsensusTime := time.Unix(int64(client.TestNode.ChainSpec.ElectraForkTime())-2, 0) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: maliciouConsensusTime, NextProposerAddress: nodeAddress, } // Process the proposal client.LogBuffer.Reset() processResp, processErr := client.SimComet.Comet.ProcessProposal(client.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT.String(), processResp.Status.String()) s.Require().Contains( client.LogBuffer.String(), "failed decoding *types.SignedBeaconBlock: ssz: offset smaller than previous", ) } // 3 - Build a block whose consensus and payload timestamp are pre-fork. // Check that it does verify (even if we already validated a post fork block). // Note: to build the block we reuse the beaconBlock from point 1 and just change CometBFT timestamp { consensusTime := time.Unix(int64(client.TestNode.ChainSpec.ElectraForkTime())-2, 0) prepareReq := &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, } proposal, prepareErr := helper.SimComet.Comet.PrepareProposal(helper.CtxComet, prepareReq) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // Process the proposal client.LogBuffer.Reset() processResp, processErr := client.SimComet.Comet.ProcessProposal(client.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) } // The next block the proposer proposes with a pre-fork timestamp will actually have a pre-fork time // Since the previous payload in cache has been evicted and a new payload is retrieved. { consensusTime := time.Unix(int64(client.TestNode.ChainSpec.ElectraForkTime())-2, 0) prepareReq := &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, } proposal, prepareErr := helper.SimComet.Comet.PrepareProposal(helper.CtxComet, prepareReq) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // Process the proposal client.LogBuffer.Reset() processResp, processErr := client.SimComet.Comet.ProcessProposal(client.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) // Finalize the block finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, } _, finalizeErr := client.SimComet.Comet.FinalizeBlock(client.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) // Commit the block. _, err = client.SimComet.Comet.Commit(client.CtxComet, &types.CommitRequest{}) s.Require().NoError(err) nextBlockHeight++ } // Finally, we cross the fork and show no issues { consensusTime := time.Unix(int64(client.TestNode.ChainSpec.ElectraForkTime())+2, 0) prepareReq := &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, } proposal, prepareErr := client.SimComet.Comet.PrepareProposal(client.CtxComet, prepareReq) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } // Process the proposal client.LogBuffer.Reset() processResp, processErr := client.SimComet.Comet.ProcessProposal(client.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) s.Require().Contains(client.LogBuffer.String(), "Processing execution requests") } } // The proposer prepares a proposal with a pre-fork timestamp, but a post-fork process proposal consensus time. // This will be rejected and is expected to occur around the fork for 1 or 2 rounds. func (s *PectraForkSuite) TestValidProposer_ProposesPreForkBlockWithPostForkConsensusTimestamp_IsRejected() { // Initialize the chain state. s.Geth.InitializeChain(s.T(), 1) nodeAddress, err := s.Geth.SimComet.GetNodeAddress() s.Require().NoError(err) s.Geth.SimComet.Comet.SetNodeAddress(nodeAddress) nextBlockHeight := int64(1) // The proposer prepares a proposal with a pre-fork timestamp, but a post-fork process proposal consensus time. { // a pre-fork time. consensusTime := time.Unix(2, 0) proposal, prepareErr := s.Geth.SimComet.Comet.PrepareProposal(s.Geth.CtxComet, &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: time.Now(), NextProposerAddress: nodeAddress, } // Process the proposal, expect a reject { s.Geth.LogBuffer.Reset() processResp, err := s.Geth.SimComet.Comet.ProcessProposal(s.Geth.CtxComet, processRequest) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) s.Require().Contains( s.Geth.LogBuffer.String(), "failed decoding *types.SignedBeaconBlock: ssz: offset smaller than previous: decoded 392, previous was 396", ) } } } // This test will show that an optimistically building a payload across the fork boundary // correctly invokes `ProcessFork` on the state processor. func (s *PectraForkSuite) Test_OptimisticBuildAtFork_IsSuccessful() { // Initialize the chain state. client := s.Geth client.InitializeChain(s.T(), 1) // init the validator // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(client.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) // setup first payload and consensus timestamps so that // - it would be pre Electra fork // - the second block, built optimistically would be at the electra fork. specs := client.TestNode.ChainSpec firstBlkConsensusTime := specs.ElectraForkTime() - 1 // before fork firstBlkPayloadTime := firstBlkConsensusTime secondBlkConsensusTime := specs.ElectraForkTime() secondBlkPayloadTime := payloadtime.Next( math.U64(secondBlkConsensusTime), math.U64(firstBlkPayloadTime), true, // this is the formula used while setting second block timestamp optimistically ) s.Require().GreaterOrEqual(secondBlkPayloadTime, math.U64(specs.ElectraForkTime())) // post fork nextBlockHeight := int64(1) { // 1- Build pre-fork block prepareRequest := &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: time.Unix(int64(firstBlkConsensusTime), 0), ProposerAddress: pubkey.Address(), } proposal, prepareErr := client.SimComet.Comet.PrepareProposal(client.CtxComet, prepareRequest) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // 2- Process the proposal. This will trigger am optimistic payload build for block height 2. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: pubkey.Address(), Time: time.Unix(int64(firstBlkConsensusTime), 0), } processResp, respErr := client.SimComet.Comet.ProcessProposal(client.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) // 3- finalize and commit the first block finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: pubkey.Address(), Time: time.Unix(int64(firstBlkConsensusTime), 0), } _, finalizeErr := client.SimComet.Comet.FinalizeBlock(client.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) _, commitErr := client.SimComet.Comet.Commit(client.CtxComet, &types.CommitRequest{}) s.Require().NoError(commitErr) } // Now build the next block nextBlockHeight++ { // 4- Build post-fork block. Make sure that the fork transition happens prepareRequest := &types.PrepareProposalRequest{ Height: nextBlockHeight, Time: time.Unix(int64(secondBlkConsensusTime), 0), ProposerAddress: pubkey.Address(), } proposal, prepareErr := client.SimComet.Comet.PrepareProposal(client.CtxComet, prepareRequest) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) s.Require().Contains(client.LogBuffer.String(), "✅ welcome to the") // 5- Process the proposal. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: pubkey.Address(), Time: time.Unix(int64(secondBlkConsensusTime), 0), } processResp, respErr := client.SimComet.Comet.ProcessProposal(client.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) // 6- finalize and commit the second block finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: pubkey.Address(), Time: time.Unix(int64(secondBlkConsensusTime), 0), } _, finalizeErr := client.SimComet.Comet.FinalizeBlock(client.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) _, commitErr := client.SimComet.Comet.Commit(client.CtxComet, &types.CommitRequest{}) s.Require().NoError(commitErr) } } // Test a scenario where reth must rebuild a payload for a failed state transition. func (s *PectraForkSuite) TestReth_MustRebuildForFailedStateTransition_IsSuccessful() { // Initialize the chain state. testEL := s.Reth helpBuilder := s.Geth testEL.InitializeChain(s.T(), 1) helpBuilder.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(testEL.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() testEL.SimComet.Comet.SetNodeAddress(nodeAddress) const blkHeight = int64(1) var ( specs = testEL.TestNode.ChainSpec consensusTime = time.Unix(int64(specs.ElectraForkTime()), 0) validTxsHeight1 [][]byte ) { // 1- Build a valid block at height 1, via the helpBuilder prepareRequest := &types.PrepareProposalRequest{ Height: blkHeight, Time: consensusTime, ProposerAddress: nodeAddress, } proposal, prepareErr := helpBuilder.SimComet.Comet.PrepareProposal(helpBuilder.CtxComet, prepareRequest) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) validTxsHeight1 = proposal.Txs // 2- Process the block via testEL node. The proposal is expected // to pass and start building payload for height 2, optimistically. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: blkHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } processResp, respErr := testEL.SimComet.Comet.ProcessProposal(testEL.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) } // For some reason, the supermajority does not finalize the block. // Another block comes, still at height 1, this time *invalid*. This would force // the node to rebuild height 1, which the EL cannot do since it has already received // an FCU(head == block_at_height_2) { invalidTxs := testBuildInvalidBlock( s.Require(), helpBuilder, &types.PrepareProposalRequest{ Txs: validTxsHeight1, Height: blkHeight, Time: consensusTime, ProposerAddress: pubkey.Address(), }, func(sbb *ctypes.SignedBeaconBlock) { sbb.Body.RandaoReveal = [96]byte{'t', 'e', 's', 't'} // this makes the block invalid }, ) // 3- Process the invalid proposal proposal. It will be rejected // and attempt to build optimistically a block at height 1. processRequest := &types.ProcessProposalRequest{ Txs: invalidTxs, Height: blkHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } processResp, processErr := testEL.SimComet.Comet.ProcessProposal(testEL.CtxComet, processRequest) s.Require().NoError(processErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_REJECT.String(), processResp.Status.String()) } { // 4- Finally let reth node build block at height 1, process and finalize it prepareRequest := &types.PrepareProposalRequest{ Height: blkHeight, Time: consensusTime, ProposerAddress: pubkey.Address(), } proposal, prepareErr := testEL.SimComet.Comet.PrepareProposal(testEL.CtxComet, prepareRequest) s.Require().NoError(prepareErr) s.Require().Len(proposal.Txs, 2) // Process the proposal via testEL node. The proposal is expected // to pass and start building payload for height 2, optimistically. processRequest := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: blkHeight, ProposerAddress: nodeAddress, Time: consensusTime, NextProposerAddress: nodeAddress, } processResp, respErr := testEL.SimComet.Comet.ProcessProposal(testEL.CtxComet, processRequest) s.Require().NoError(respErr) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) finalizeRequest := &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: blkHeight, ProposerAddress: pubkey.Address(), Time: consensusTime, } _, finalizeErr := testEL.SimComet.Comet.FinalizeBlock(testEL.CtxComet, finalizeRequest) s.Require().NoError(finalizeErr) _, commitErr := testEL.SimComet.Comet.Commit(testEL.CtxComet, &types.CommitRequest{}) s.Require().NoError(commitErr) } } func processFinalizeCommit( t *testing.T, node simulated.SharedAccessors, processRequest *types.ProcessProposalRequest, finalizeRequest *types.FinalizeBlockRequest, expectedMessage string, ) { // Process the proposal node.LogBuffer.Reset() processResp, err := node.SimComet.Comet.ProcessProposal(node.CtxComet, processRequest) require.NoError(t, err) require.Equal(t, types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) require.Contains(t, node.LogBuffer.String(), expectedMessage) // Finalize the block finalizeResp, err := node.SimComet.Comet.FinalizeBlock(node.CtxComet, finalizeRequest) require.NoError(t, err) require.NotEmpty(t, finalizeResp) // Commit the block. _, err = node.SimComet.Comet.Commit(node.CtxComet, &types.CommitRequest{}) require.NoError(t, err) } func (s *PectraForkSuite) submitTransactions(startNonce uint64, numTransactions uint64) uint64 { // corresponds with funded address in genesis 0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4 senderKey, err := crypto.HexToECDSA("fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306") s.Require().NoError(err) elChainID := big.NewInt(int64(s.Geth.TestNode.ChainSpec.DepositEth1ChainID())) signer := gethtypes.NewPragueSigner(elChainID) for i := startNonce; i < startNonce+numTransactions; i++ { transaction := gethtypes.MustSignNewTx(senderKey, signer, &gethtypes.DynamicFeeTx{ ChainID: elChainID, Nonce: i, To: ¶ms.BeaconRootsAddress, // any address Gas: 500_000, GasFeeCap: big.NewInt(1000000000), GasTipCap: big.NewInt(1000000000), Value: big.NewInt(0), Data: nil, }) txBytes, marshalErr := transaction.MarshalBinary() s.Require().NoError(marshalErr) var result interface{} err = s.Geth.TestNode.EngineClient.Call(s.Geth.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) s.Require().NoError(err) } return startNonce + numTransactions } ================================================ FILE: testing/simulated/pectra_genesis_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "context" "math/big" "path" "testing" "time" "github.com/berachain/beacon-kit/beacon/blockchain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" "github.com/berachain/beacon-kit/engine-primitives/errors" "github.com/berachain/beacon-kit/execution/requests/eip7002" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/primitives/encoding/hex" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/testing/simulated" "github.com/berachain/beacon-kit/testing/simulated/execution" v1 "github.com/cometbft/cometbft/api/cometbft/abci/v1" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/spf13/viper" "github.com/stretchr/testify/suite" ) // PectraGenesisSuite defines our test suite for Pectra related work using simulated Comet component. type PectraGenesisSuite struct { suite.Suite // Embedded shared accessors for convenience. simulated.SharedAccessors } // TestPectraSuite runs the test suite. func TestPectraSuite(t *testing.T) { suite.Run(t, new(PectraGenesisSuite)) } // SetupTest initializes the test environment. func (s *PectraGenesisSuite) SetupTest() { // Create a cancellable context for the duration of the test. s.CtxApp, s.CtxAppCancelFn = context.WithCancel(context.Background()) // CometBFT uses context.TODO() for all ABCI calls, so we replicate that. s.CtxComet = context.TODO() s.HomeDir = s.T().TempDir() // Initialize the home directory, Comet configuration, and genesis info. const elGenesisPath = "./el-genesis-files/pectra-eth-genesis.json" chainSpecFunc := simulated.ProvideElectraGenesisChainSpec // Create the chainSpec. chainSpec, err := chainSpecFunc() s.Require().NoError(err) configs, genesisValidatorsRoot := simulated.InitializeHomeDirs(s.T(), chainSpec, elGenesisPath, s.HomeDir) cometConfig := configs[0] s.GenesisValidatorsRoot = genesisValidatorsRoot // Start the EL (execution layer) Geth node. elNode := execution.NewGethNode(s.HomeDir, execution.ValidGethImage()) elHandle, authRPC, elRPC := elNode.Start(s.T(), path.Base(elGenesisPath)) s.ElHandle = elHandle // Prepare a logger backed by a buffer to capture logs for assertions. s.LogBuffer = &simulated.SyncBuffer{} logger := phuslu.NewLogger(s.LogBuffer, nil) // Build the Beacon node with the simulated Comet component and electra genesis chain spec components := simulated.FixedComponents(s.T()) components = append(components, simulated.ProvideSimComet) components = append(components, chainSpecFunc) s.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.HomeDir, CometConfig: cometConfig, AuthRPC: authRPC, ClientRPC: elRPC, Logger: logger, AppOpts: viper.New(), Components: components, }) s.SimComet = s.TestNode.SimComet // Start the Beacon node in a separate goroutine. go func() { _ = s.TestNode.Start(s.CtxApp) }() s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) s.Require().NoError(err) } // TearDownTest cleans up the test environment. func (s *PectraGenesisSuite) TearDownTest() { s.CleanupTest(s.T()) } func (s *PectraGenesisSuite) TestFullLifecycle_WithoutRequests_IsSuccessful() { const blockHeight = 1 const coreLoopIterations = 10 // Initialize the chain state. s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens post Electra fork. startTime := time.Now() // Go through iterations of the core loop. proposals, _, _ := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) } func (s *PectraGenesisSuite) TestFullLifecycle_WithPartialWithdrawalRequests_IsSuccessful() { // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) nextBlockHeight := int64(1) // We must first move the chain by 1 height such that the withdrawal contract has an updated `EXCESS_INHIBITOR`. { proposals, _, _ := s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) s.Require().Len(proposals, 1) nextBlockHeight++ } // create and submit the withdrawal request totalWithdrawalAmount := 3456 { // corresponds with the funded address in genesis `simulated.WithdrawalExecutionAddress` senderKey, err := crypto.HexToECDSA("fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306") s.Require().NoError(err) elChainID := big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID())) signer := types.NewPragueSigner(elChainID) fee, err := eip7002.GetWithdrawalFee(s.CtxApp, s.TestNode.EngineClient) s.Require().NoError(err) totalTxs := 2 amountPerTx := totalWithdrawalAmount / totalTxs withdrawalTxData, err := eip7002.CreateWithdrawalRequestData(blsSigner.PublicKey(), math.Gwei(amountPerTx)) s.Require().NoError(err) // submit 2 txs for i := 0; i < totalTxs; i++ { withdrawalTx := types.MustSignNewTx(senderKey, signer, &types.DynamicFeeTx{ ChainID: elChainID, Nonce: uint64(i), To: ¶ms.WithdrawalQueueAddress, Gas: 500_000, GasFeeCap: big.NewInt(1000000000), GasTipCap: big.NewInt(1000000000), Value: fee, Data: withdrawalTxData, }) var balance hexutil.Big err = s.TestNode.EngineClient.Call(s.CtxApp, &balance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.T().Logf("Balance before withdrawal request sent: %s", balance.ToInt().String()) var txBytes []byte txBytes, err = withdrawalTx.MarshalBinary() s.Require().NoError(err) var result interface{} err = s.TestNode.EngineClient.Call(s.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) s.Require().NoError(err) time.Sleep(time.Second) // give it time to allow the tx to be included in the next block } } // Go through 1 iteration of the core loop so that both withdrawal txs is included var afterRequestBalance hexutil.Big { s.LogBuffer.Reset() proposals, _, _ := s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) s.Require().Len(proposals, 1) // Log contains 2 withdrawals s.Require().Contains(s.LogBuffer.String(), "Processing execution requests service=state-processor\u001B[0m deposits=0\u001B[0m withdrawals=2\u001B[0m consolidations=0\u001B[0m") s.LogBuffer.Reset() err := s.TestNode.EngineClient.Call(s.CtxApp, &afterRequestBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.Require().NoError(err) s.T().Logf("Balance after withdrawal request included in block: %s", afterRequestBalance.ToInt().String()) nextBlockHeight++ } // We must progress to Epoch `nextEpoch + MinValidatorWithdrawabilityDelay` before the balance will be removed. // IterationsToTurn will get us to the slot before the turn of the target var beforeWithdrawalBalance hexutil.Big { prevBlockHeight := nextBlockHeight - 1 epochOfWithdrawalRequest := s.TestNode.ChainSpec.SlotToEpoch(math.Slot(prevBlockHeight)) nextEpoch := epochOfWithdrawalRequest + 1 targetEpoch := nextEpoch + s.TestNode.ChainSpec.MinValidatorWithdrawabilityDelay() iterationsToTurn := (s.TestNode.ChainSpec.SlotsPerEpoch() * uint64(targetEpoch)) - uint64(prevBlockHeight) - 1 s.MoveChainToHeight(s.T(), nextBlockHeight, int64(iterationsToTurn), nodeAddress, time.Now()) s.LogBuffer.Reset() err := s.TestNode.EngineClient.Call(s.CtxApp, &beforeWithdrawalBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.Require().NoError(err) s.T().Logf("Balance before withdrawal processed: %s", beforeWithdrawalBalance.ToInt().String()) // Balance should not have changed yet s.Require().Equal(afterRequestBalance.ToInt().String(), beforeWithdrawalBalance.ToInt().String()) nextBlockHeight = nextBlockHeight + int64(iterationsToTurn) } // The next block will be the turn of the Epoch, and the balance will change { s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) var afterWithdrawalBalance hexutil.Big err := s.TestNode.EngineClient.Call(s.CtxApp, &afterWithdrawalBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.Require().NoError(err) s.T().Logf("Balance after withdrawal processed: %s", afterWithdrawalBalance.ToInt().String()) withdrawalAmountWei := new(big.Int).Mul(big.NewInt(int64(totalWithdrawalAmount)), big.NewInt(params.GWei)) // Expected balance is balance before withdrawal + totalWithdrawalAmount expectedBalance := new(big.Int).Add(beforeWithdrawalBalance.ToInt(), withdrawalAmountWei) // The new balance of the validator is updated s.Require().Equal(expectedBalance.String(), afterWithdrawalBalance.ToInt().String()) } } func (s *PectraGenesisSuite) TestFullLifecycle_WithFullWithdrawalRequest_IsSuccessful() { // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() nextBlockHeight := int64(1) // We must first move the chain by 1 height such that the withdrawal contract has an updated `EXCESS_INHIBITOR`. { proposals, _, _ := s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) s.Require().Len(proposals, 1) nextBlockHeight = nextBlockHeight + 1 } // create a withdrawal request and submit { // corresponds with the funded address in genesis `simulated.WithdrawalExecutionAddress` senderKey, err := crypto.HexToECDSA("fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306") s.Require().NoError(err) elChainID := big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID())) signer := types.NewPragueSigner(elChainID) fee, err := eip7002.GetWithdrawalFee(s.CtxApp, s.TestNode.EngineClient) s.Require().NoError(err) // 0 amount will correspond with a full withdrawal request. withdrawalAmount := 0 withdrawalTxData, err := eip7002.CreateWithdrawalRequestData(blsSigner.PublicKey(), math.Gwei(withdrawalAmount)) s.Require().NoError(err) withdrawalTx := types.MustSignNewTx(senderKey, signer, &types.DynamicFeeTx{ ChainID: elChainID, Nonce: 0, To: ¶ms.WithdrawalQueueAddress, Gas: 500_000, GasFeeCap: big.NewInt(1000000000), GasTipCap: big.NewInt(1000000000), Value: fee, Data: withdrawalTxData, }) var balance hexutil.Big err = s.TestNode.EngineClient.Call(s.CtxApp, &balance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.T().Logf("Balance before withdrawal request sent: %s", balance.ToInt().String()) txBytes, err := withdrawalTx.MarshalBinary() s.Require().NoError(err) var result interface{} err = s.TestNode.EngineClient.Call(s.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) s.Require().NoError(err) time.Sleep(time.Second) // give it time to allow the tx to be included in the next block } // Go through 1 iteration of the core loop so that the withdrawal tx is included var afterRequestBalance hexutil.Big { proposals, finalizeBlockResponses, _ := s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) s.Require().Len(proposals, 1) // Log contains 1 withdrawal s.Require().Contains(s.LogBuffer.String(), "Processing execution requests service=state-processor\u001B[0m deposits=0\u001B[0m withdrawals=1\u001B[0m consolidations=0\u001B[0m") s.Require().Len(finalizeBlockResponses, 1) // No validator updates yet s.Require().Len(finalizeBlockResponses[0].GetValidatorUpdates(), 0) err := s.TestNode.EngineClient.Call(s.CtxApp, &afterRequestBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.Require().NoError(err) s.T().Logf("Balance after withdrawal request included in block: %s", afterRequestBalance.ToInt().String()) nextBlockHeight++ } // Once a validator's full withdrawal request has been included in a block, it's exit epoch will be set to the next epoch. // We enforce that it is exited by checking that FinalizeBlock returns the updated validator set without the validator. var exitEpoch math.Epoch { s.LogBuffer.Reset() prevBlockHeight := nextBlockHeight - 1 epochOfWithdrawalRequest := s.TestNode.ChainSpec.SlotToEpoch(math.Slot(prevBlockHeight)) nextEpoch := epochOfWithdrawalRequest + 1 exitEpoch = nextEpoch iterationsToExitEpoch := (s.TestNode.ChainSpec.SlotsPerEpoch() * uint64(exitEpoch)) - uint64(prevBlockHeight) _, finalizeBlockResponses, _ := s.MoveChainToHeight(s.T(), nextBlockHeight, int64(iterationsToExitEpoch), nodeAddress, time.Now()) s.Require().Len(finalizeBlockResponses, int(iterationsToExitEpoch)) lastBlockIdx := len(finalizeBlockResponses) - 1 // We expect the validator to be kicked out now, with power 0 s.Require().Len(finalizeBlockResponses[lastBlockIdx].GetValidatorUpdates(), 1) ejectedValidator := finalizeBlockResponses[lastBlockIdx].GetValidatorUpdates()[0] s.Require().Equal(int64(0), ejectedValidator.GetPower()) s.Require().Equal(blsSigner.PublicKey().String(), hex.EncodeBytes(ejectedValidator.GetPubKeyBytes())) nextBlockHeight = nextBlockHeight + int64(iterationsToExitEpoch) } // We must progress to Epoch `exitEpoch + MinValidatorWithdrawabilityDelay` before the balance will be removed. // We progress to the slot before the turn of the target epoch to enforce the balance has not changed. var beforeWithdrawalBalance hexutil.Big { // IterationsToTurn will get us to the slot before the turn of the target targetEpoch := exitEpoch + s.TestNode.ChainSpec.MinValidatorWithdrawabilityDelay() iterationsToTurn := (s.TestNode.ChainSpec.SlotsPerEpoch() * uint64(targetEpoch)) - uint64(nextBlockHeight) s.MoveChainToHeight(s.T(), nextBlockHeight, int64(iterationsToTurn), nodeAddress, time.Now()) s.LogBuffer.Reset() err := s.TestNode.EngineClient.Call(s.CtxApp, &beforeWithdrawalBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.Require().NoError(err) s.T().Logf("Balance before withdrawal processed: %s", beforeWithdrawalBalance.ToInt().String()) // Balance should not have changed yet s.Require().Equal(afterRequestBalance.ToInt().String(), beforeWithdrawalBalance.ToInt().String()) nextBlockHeight = nextBlockHeight + int64(iterationsToTurn) } // The next block will be the turn of the Epoch, and the balance will change { s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) var afterWithdrawalBalance hexutil.Big err := s.TestNode.EngineClient.Call(s.CtxApp, &afterWithdrawalBalance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.Require().NoError(err) s.T().Logf("Balance after withdrawal processed: %s", afterWithdrawalBalance.ToInt().String()) // Since this is a full withdrawal, the full balance will be withdrawn. // The validator started with a balance equal to math.Gwei(chainSpec.MaxEffectiveBalance()) withdrawalAmountWei := new(big.Int).Mul(big.NewInt(int64(s.TestNode.ChainSpec.MaxEffectiveBalance())), big.NewInt(params.GWei)) // Expected balance is balance before withdrawal + withdrawalAmount expectedBalance := new(big.Int).Add(beforeWithdrawalBalance.ToInt(), withdrawalAmountWei) // The new balance of the validator is updated s.Require().Equal(expectedBalance.String(), afterWithdrawalBalance.ToInt().String()) } } // TestMaliciousProposer_AddInvalidExecutionRequests_IsRejected a malicious proposer adds execution requests // that were not actually requested. func (s *PectraGenesisSuite) TestMaliciousProposer_AddInvalidExecutionRequests_IsRejected() { // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) nextBlockHeight := int64(1) // We must first move the chain by 1 height such that the withdrawal contract has an updated `EXCESS_INHIBITOR`. { proposals, _, _ := s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) s.Require().Len(proposals, 1) nextBlockHeight++ } // Create a signed block with invalid execution requests. var maliciousSignedBlock *ctypes.SignedBeaconBlock var proposal *v1.PrepareProposalResponse proposalTime := time.Now() { s.LogBuffer.Reset() proposal, err = s.SimComet.Comet.PrepareProposal(s.CtxComet, &v1.PrepareProposalRequest{ Height: nextBlockHeight, Time: time.Now(), ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().Len(proposal.Txs, 2) // Unmarshal the proposal block. proposedBlock, unmarshalErr := encoding.UnmarshalBeaconBlockFromABCIRequest( proposal.Txs, blockchain.BeaconBlockTxIndex, s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(proposalTime.Unix())), ) s.Require().NoError(unmarshalErr) // Invalid Execution Request invalidExecutionRequests := &ctypes.ExecutionRequests{ Deposits: []*ctypes.DepositRequest{ { Pubkey: [48]byte{0, 1, 2}, Credentials: [32]byte{0, 3, 2}, Amount: 10000000, Signature: [96]byte{5, 6, 7}, Index: 5, }, }, Withdrawals: nil, Consolidations: nil, } // Create a malicious block by injecting an invalid Execution Request. maliciousBlock := simulated.ComputeAndSetInvalidExecutionBlock( s.T(), proposedBlock.GetBeaconBlock(), s.TestNode.ChainSpec, nil, invalidExecutionRequests, ) // Re-sign the block maliciousSignedBlock, err = ctypes.NewSignedBeaconBlock( maliciousBlock, &ctypes.ForkData{ CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(maliciousBlock.GetTimestamp()), GenesisValidatorsRoot: s.GenesisValidatorsRoot, }, s.TestNode.ChainSpec, blsSigner, ) s.Require().NoError(err) // Check that the block contains the invalid execution request. requests, getErr := maliciousSignedBlock.GetBeaconBlock().GetBody().GetExecutionRequests() s.Require().NoError(getErr) s.Require().Len(requests.Deposits, 1) } // Propose the invalid block { maliciousBlockBytes, sszErr := maliciousSignedBlock.MarshalSSZ() s.Require().NoError(sszErr) // Replace the valid block with the malicious block in the proposal. proposal.Txs[0] = maliciousBlockBytes // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() // Process the proposal containing the malicious block. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &v1.ProcessProposalRequest{ Txs: proposal.Txs, Height: nextBlockHeight, ProposerAddress: nodeAddress, Time: proposalTime, }) s.Require().NoError(err) s.Require().Equal(v1.PROCESS_PROPOSAL_STATUS_REJECT, processResp.Status) // Verify that the log contains the expected error message. s.Require().Contains(s.LogBuffer.String(), errors.ErrInvalidPayloadStatus.Error()) s.Require().Contains(s.LogBuffer.String(), "invalid requests hash (remote: 33ba74e937423115e3abf4250db02588388b4b3a7918950ed44a28e4bf3428d2 local: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855)") } } ================================================ FILE: testing/simulated/pectra_withdrawal_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "context" "math/big" "path" "testing" "time" depositcli "github.com/berachain/beacon-kit/cli/commands/deposit" consensustypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/execution/requests/eip7002" "github.com/berachain/beacon-kit/gethlib/deposit" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/common" beaconmath "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/testing/simulated" "github.com/berachain/beacon-kit/testing/simulated/execution" "github.com/cometbft/cometbft/crypto/bls12381" "github.com/cometbft/cometbft/types" "github.com/ethereum/go-ethereum/accounts/abi/bind" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" gethcore "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/prysmaticlabs/prysm/v5/consensus-types/validator" "github.com/spf13/viper" "github.com/stretchr/testify/suite" ) // testPkey corresponds to address 0x56898d1aFb10cad584961eb96AcD476C6826e41E which is prefunded in genesis const testPkey2 = "9b9bc88a144fff869ae2f4ea8e252f2494d9b52ea1008d0b3537dad27ab489d5" // PectraWithdrawalSuite defines our test suite for Pectra related work using simulated Comet component. type PectraWithdrawalSuite struct { suite.Suite // Embedded shared accessors for convenience. simulated.SharedAccessors } // TestPectraWithdrawalSuite runs the test suite. func TestPectraWithdrawalSuite(t *testing.T) { suite.Run(t, new(PectraWithdrawalSuite)) } // SetupTest initializes the test environment. func (s *PectraWithdrawalSuite) SetupTest() { // Create a cancellable context for the duration of the test. s.CtxApp, s.CtxAppCancelFn = context.WithCancel(context.Background()) // CometBFT uses context.TODO() for all ABCI calls, so we replicate that. s.CtxComet = context.TODO() s.HomeDir = s.T().TempDir() // Initialize the home directory, Comet configuration, and genesis info. const elGenesisPath = "./el-genesis-files/pectra-fork-genesis.json" chainSpecFunc := simulated.ProvidePectraWithdrawalTestChainSpec // Create the chainSpec. chainSpec, err := chainSpecFunc() s.Require().NoError(err) configs, genesisValidatorsRoot := simulated.InitializeHomeDirs(s.T(), chainSpec, elGenesisPath, s.HomeDir) cometConfig := configs[0] s.GenesisValidatorsRoot = genesisValidatorsRoot // Start the EL (execution layer) Geth node. elNode := execution.NewGethNode(s.HomeDir, execution.ValidGethImage()) elHandle, authRPC, elRPC := elNode.Start(s.T(), path.Base(elGenesisPath)) s.ElHandle = elHandle // Prepare a logger backed by a buffer to capture logs for assertions. s.LogBuffer = &simulated.SyncBuffer{} logger := phuslu.NewLogger(s.LogBuffer, nil) // Build the Beacon node with the simulated Comet component and electra genesis chain spec components := simulated.FixedComponents(s.T()) components = append(components, simulated.ProvideSimComet) components = append(components, chainSpecFunc) s.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.HomeDir, CometConfig: cometConfig, AuthRPC: authRPC, ClientRPC: elRPC, Logger: logger, AppOpts: viper.New(), Components: components, }) s.SimComet = s.TestNode.SimComet // Start the Beacon node in a separate goroutine. go func() { _ = s.TestNode.Start(s.CtxApp) }() s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) s.Require().NoError(err) } // TearDownTest cleans up the test environment. func (s *PectraWithdrawalSuite) TearDownTest() { s.CleanupTest(s.T()) } // TestExcessValidatorBeforeFork_CorrectlyEvicted verifies that when a validator’s deposit // exceeds the validator set cap before the Electra fork, it is evicted correctly. The set // cap is 1. // // Scenario timeline: // Epoch 1: Move chain by 1 block to include the deposit (deposit store len == 1). // Epoch 2: Move chain by 1 block to enqueue the deposit (deposit store len == 2). // Epoch 3: Move chain by 1 block → validator status becomes PendingInitialized. // Epoch 4: Move chain by 1 block → validator status becomes PendingQueued. // Epoch 5: Move chain by 1 block → validator status becomes ExitedUnslashed; withdrawableEpoch is set to 6. // —— Electra fork —— // Epoch 6: Move chain by 1 block → status is WithdrawalPossible and EL balance is returned immediately. // Epoch 7: Move chain by 1 block → status is WithdrawalDone (effective balance = 0). func (s *PectraWithdrawalSuite) TestExcessValidatorBeforeFork_CorrectlyEvicted() { // Initialize the chain state. s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) // Send the Deposit var senderAddress gethcommon.Address depositAmount := beaconmath.Gwei(500_000 * 1e9) // 500K Bera { depositContractAddress := gethcommon.Address(s.TestNode.ChainSpec.DepositContractAddress()) depositClient, err := deposit.NewDepositContract(depositContractAddress, s.TestNode.ContractBackend) s.Require().NoError(err) depositCount, err := depositClient.DepositCount(&bind.CallOpts{ BlockNumber: big.NewInt(0), }) s.Require().NoError(err) s.Require().Equal(uint64(1), depositCount) var credAddress common.ExecutionAddress credAddress, err = common.NewExecutionAddressFromHex("0x56898d1aFb10cad584961eb96AcD476C6826e41E") s.Require().NoError(err) creds := consensustypes.NewCredentialsFromExecutionAddress(credAddress) newDepositor := &signer.BLSSigner{PrivValidator: types.NewMockPVWithKeyType(bls12381.KeyType)} depositMsg, blsSig, err := depositcli.CreateDepositMessage( s.TestNode.ChainSpec, newDepositor, s.GenesisValidatorsRoot, creds, depositAmount, ) s.Require().NoError(err) err = depositcli.ValidateDeposit( s.TestNode.ChainSpec, depositMsg.Pubkey, depositMsg.Credentials, depositMsg.Amount, s.GenesisValidatorsRoot, blsSig, ) s.Require().NoError(err) elChainID := big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID())) senderKey, err := crypto.HexToECDSA(testPkey2) senderAddress = gethcommon.HexToAddress(credAddress.String()) s.Require().NoError(err) _, err = depositClient.Deposit(&bind.TransactOpts{ From: senderAddress, Signer: func(_ gethcommon.Address, tx *gethcore.Transaction) (*gethcore.Transaction, error) { return gethcore.SignTx( tx, gethcore.LatestSignerForChainID(elChainID), senderKey, ) }, Value: big.NewInt(0).Mul(big.NewInt(int64(depositAmount)), big.NewInt(1e9)), }, depositMsg.Pubkey[:], depositMsg.Credentials[:], blsSig[:], senderAddress) s.Require().NoError(err) } // Hard fork occurs at t=10, so we start at t=5 // This accounts for optimistic block building pushing payloadTime // ahead of 1 second per block nextBlockTime := time.Unix(5, 0) nextBlockHeight := int64(1) // [Slot/Epoch 1] Move the chain by 1 block to include the deposit { s.LogBuffer.Reset() _, _, nextBlockTime = s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, nextBlockTime) s.Require().Equal(time.Unix(6, 0), nextBlockTime) ds := s.TestNode.StorageBackend.DepositStore() deposits, _, err := ds.GetDepositsByIndex(s.CtxApp, 0, uint64(nextBlockHeight)*s.TestNode.ChainSpec.MaxDepositsPerBlock()) s.Require().NoError(err) // There should only be 1 deposit in the deposit store from genesis s.Require().Len(deposits, 1) nextBlockHeight++ } // [Slot/Epoch 2] Move the chain by 1 block to Enqueue the deposit { s.LogBuffer.Reset() _, _, nextBlockTime = s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, nextBlockTime) s.Require().Equal(time.Unix(7, 0), nextBlockTime) ds := s.TestNode.StorageBackend.DepositStore() deposits, _, err := ds.GetDepositsByIndex(s.CtxApp, 0, uint64(nextBlockHeight)*s.TestNode.ChainSpec.MaxDepositsPerBlock()) s.Require().NoError(err) // There should be 2 deposits in the deposit store s.Require().Len(deposits, 2) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 1) nextBlockHeight++ } // [Slot/Epoch 3] Move the chain by 1 block make the validator pending initialized { s.LogBuffer.Reset() _, _, nextBlockTime = s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, nextBlockTime) s.Require().Equal(time.Unix(8, 0), nextBlockTime) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 2) s.Require().Equal(validator.PendingInitialized.String(), validators[1].Status) nextBlockHeight++ } // [Slot/Epoch 4] Move the chain by 1 block make the validator pending queued { s.LogBuffer.Reset() _, _, nextBlockTime = s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, nextBlockTime) s.Require().Equal(time.Unix(9, 0), nextBlockTime) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 2) s.Require().Equal(validator.PendingQueued.String(), validators[1].Status) nextBlockHeight++ } // [Slot/Epoch 5] Move the chain by 1 block mark the validator as exited { s.LogBuffer.Reset() _, _, nextBlockTime = s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, nextBlockTime) s.Require().Equal(time.Unix(10, 0), nextBlockTime) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 2) s.Require().Equal(validator.ExitedUnslashed.String(), validators[1].Status) // The validator should withdrawable at Epoch 6 since hard fork has not occurred. s.Require().Equal("6", validators[1].Validator.WithdrawableEpoch) nextBlockHeight++ } // [Slot/Epoch 6] Move the chain by 1. This block activates the hard fork. No withdrawal delay is expected. { s.LogBuffer.Reset() _, _, nextBlockTime = s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, nextBlockTime) s.Require().Equal(time.Unix(11, 0), nextBlockTime) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 2) s.Require().Equal(validator.WithdrawalPossible.String(), validators[1].Status) // The validator should withdrawable at Epoch 6 since hard fork has not occurred. s.Require().Equal("6", validators[1].Validator.WithdrawableEpoch) // Confirm the fork was activated s.Require().Contains(s.LogBuffer.String(), "✅ welcome to the electra (0x05000000) fork! 🎉") // Confirm the balance change on EL previousBlockBalance, err := s.TestNode.ContractBackend.BalanceAt(s.CtxApp, senderAddress, big.NewInt(nextBlockHeight-1)) s.Require().NoError(err) currentBalance, err := s.TestNode.ContractBackend.BalanceAt(s.CtxApp, senderAddress, big.NewInt(nextBlockHeight)) s.Require().NoError(err) depositAmountWei := big.NewInt(0).Mul(big.NewInt(int64(depositAmount)), big.NewInt(1e9)) expectedBalance := big.NewInt(0).Add(previousBlockBalance, depositAmountWei) s.Require().Equal(expectedBalance, currentBalance) nextBlockHeight++ } // [Slot/Epoch 7] Move the chain by 1. The effective balance is now 0 and the withdrawal is complete { s.LogBuffer.Reset() _, _, nextBlockTime = s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, nextBlockTime) s.Require().Equal(time.Unix(12, 0), nextBlockTime) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 2) s.Require().Equal(validator.WithdrawalDone.String(), validators[1].Status) nextBlockHeight++ } } // Verifies that excess balance is not withdrawn accidentally if a validator has multiple sources of withdrawals. // Both the partial withdrawal and the excess balance withdrawal will occur simultaneously in a block. // Multiple deposits are sent so that Consensus Layer has a higher balance when the withdrawal request is processed. // This also served as a PoC for a now patched bug (see https://github.com/berachain/beacon-kit/pull/2723). func (s *PectraWithdrawalSuite) TestWithdrawalFromExcessStake_WithPartialWithdrawal_CorrectAmountWithdrawn() { // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) credAddress, err := common.NewExecutionAddressFromHex(simulated.WithdrawalExecutionAddress) s.Require().NoError(err) creds := consensustypes.NewCredentialsFromExecutionAddress(credAddress) senderAddress := gethcommon.HexToAddress(credAddress.String()) // Hard fork occurs at t=10, so we move passed the pectra hard fork nextBlockHeight := int64(1) { s.LogBuffer.Reset() s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) nextBlockHeight++ } // 10 million bera on EL at the start. expectedStartBalance, isValid := big.NewInt(0).SetString("10000000000000000000000000", 10) s.Require().True(isValid) // Confirm the validator's expected start balance in Wei { startBalance, err := s.TestNode.ContractBackend.BalanceAt(s.CtxApp, senderAddress, big.NewInt(nextBlockHeight-1)) s.Require().NoError(err) s.Require().Equal(expectedStartBalance, startBalance) s.T().Logf("balance at start: %s wei", startBalance.String()) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight-1, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 1) s.T().Logf("staked validator balance at start: %v gwei", validators[0].Validator.EffectiveBalance) // Starts with 10000000000000000 gwei / 10 million BERA staked. s.Require().Equal("10000000000000000", validators[0].Validator.EffectiveBalance) } // Send the Deposit and progress 1 block so that the deposit is included in the next block depositAmount := beaconmath.Gwei(1_000_000 * 1e9) // 1 million Bera { // Send Deposit Request iterations := int64(2) s.defaultDeposit(blsSigner, creds, depositAmount, true) time.Sleep(time.Second) // give it time to allow the tx to be included in the next block s.MoveChainToHeight(s.T(), nextBlockHeight, iterations, nodeAddress, time.Now()) nextBlockHeight += iterations } // Create the Partial Withdrawal Request for a large amount above the MaxEffectiveBalance. // It will be reduced to the maximum possible amount above the MinActivationBalance as part of the processing logic. totalWithdrawalAmount := beaconmath.Gwei(15_000_000 * 1e9) { // corresponds with the funded address in genesis `simulated.WithdrawalExecutionAddress` senderKey := simulated.GetTestKey(s.T()) elChainID := big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID())) pragueSigner := gethcore.NewPragueSigner(elChainID) fee, err := eip7002.GetWithdrawalFee(s.CtxApp, s.TestNode.EngineClient) s.Require().NoError(err) withdrawalTxData, err := eip7002.CreateWithdrawalRequestData(blsSigner.PublicKey(), totalWithdrawalAmount) s.Require().NoError(err) withdrawalTx := gethcore.MustSignNewTx(senderKey, pragueSigner, &gethcore.DynamicFeeTx{ ChainID: elChainID, Nonce: 1, To: ¶ms.WithdrawalQueueAddress, Gas: 500_000, GasFeeCap: big.NewInt(1000000000), GasTipCap: big.NewInt(1000000000), Value: fee, Data: withdrawalTxData, }) var balance hexutil.Big err = s.TestNode.EngineClient.Call(s.CtxApp, &balance, "eth_getBalance", simulated.WithdrawalExecutionAddress, "latest") s.T().Logf("Balance before withdrawal request sent: %s", balance.ToInt().String()) var txBytes []byte txBytes, err = withdrawalTx.MarshalBinary() s.Require().NoError(err) var result interface{} err = s.TestNode.EngineClient.Call(s.CtxApp, &result, "eth_sendRawTransaction", hexutil.Encode(txBytes)) s.Require().NoError(err) time.Sleep(time.Second) // give it time to allow the tx to be included in the next block } // Move forward two blocks to include in the chain { s.LogBuffer.Reset() s.MoveChainToHeight(s.T(), nextBlockHeight, 2, nodeAddress, time.Now()) nextBlockHeight += 2 } // Send another deposit { s.defaultDeposit(blsSigner, creds, depositAmount, false) time.Sleep(time.Second) // give it time to allow the tx to be included in the next block } // Move the chain by 1 block to include the deposit var balanceAfterDepositTxIncluded *big.Int { s.LogBuffer.Reset() s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) ds := s.TestNode.StorageBackend.DepositStore() deposits, _, err := ds.GetDepositsByIndex(s.CtxApp, 0, uint64(nextBlockHeight)*s.TestNode.ChainSpec.MaxDepositsPerBlock()) s.Require().NoError(err) // There should be 2 deposits in the store s.Require().Len(deposits, 2) balanceAfterDepositTxIncluded, err = s.TestNode.ContractBackend.BalanceAt(s.CtxApp, senderAddress, big.NewInt(nextBlockHeight)) s.Require().NoError(err) nextBlockHeight++ } // Move the chain by 1 block to Enqueue the deposit { s.LogBuffer.Reset() s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) ds := s.TestNode.StorageBackend.DepositStore() deposits, _, err := ds.GetDepositsByIndex(s.CtxApp, 0, uint64(nextBlockHeight)*s.TestNode.ChainSpec.MaxDepositsPerBlock()) s.Require().NoError(err) // There should be 3 deposits in the deposit store s.Require().Len(deposits, 3) // Only 1 active validator validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 1) s.T().Logf("staked validator balance: %v gwei", validators[0].Validator.EffectiveBalance) nextBlockHeight++ } // Move the chain by 1 block trigger the withdrawal. { s.LogBuffer.Reset() s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) balance, err := s.TestNode.ContractBackend.BalanceAt(s.CtxApp, senderAddress, big.NewInt(nextBlockHeight)) s.Require().NoError(err) s.Require().Equal(balanceAfterDepositTxIncluded, balance) // The validator's balance should not have changed yet nextBlockHeight++ } // The next block will have the partial withdrawal, but not the excess balance withdrawal and increase the validator's EL balance // Before the fix, it would also have the excess balance withdrawal. { s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) nextBlockHeight++ } { iterations := int64(4) s.MoveChainToHeight(s.T(), nextBlockHeight, iterations, nodeAddress, time.Now()) nextBlockHeight += iterations finalBalance, err := s.TestNode.ContractBackend.BalanceAt(s.CtxApp, senderAddress, big.NewInt(nextBlockHeight-1)) s.Require().NoError(err) s.T().Logf("balance at end: %s wei", finalBalance.String()) finalBalanceGwei, convertErr := beaconmath.GweiFromWei(finalBalance) s.Require().NoError(convertErr) expectedStartBalanceGwei, convertErr := beaconmath.GweiFromWei(expectedStartBalance) s.Require().NoError(convertErr) s.Require().InDelta( uint64(expectedStartBalanceGwei)+ uint64( s.TestNode.ChainSpec.MaxEffectiveBalance()- s.TestNode.ChainSpec.MinActivationBalance(), ), uint64(finalBalanceGwei), 500_000, // maximum 0.0005 BERA or 500000 Gwei delta ) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight-1, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 1) s.T().Logf("staked validator balance at end: %v gwei", validators[0].Validator.EffectiveBalance) s.Require().Equal(s.TestNode.ChainSpec.MinActivationBalance().Base10(), validators[0].Validator.EffectiveBalance) } } func (s *PectraWithdrawalSuite) TestWithdrawalFromExcessStake_HasCorrectWithdrawalAmount() { // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) credAddress, err := common.NewExecutionAddressFromHex(simulated.WithdrawalExecutionAddress) s.Require().NoError(err) creds := consensustypes.NewCredentialsFromExecutionAddress(credAddress) senderAddress := gethcommon.HexToAddress(credAddress.String()) // Hard fork occurs at t=10, so we move passed the pectra hard fork nextBlockHeight := int64(1) { s.LogBuffer.Reset() s.MoveChainToHeight(s.T(), nextBlockHeight, 1, nodeAddress, time.Now()) nextBlockHeight++ } // 10 million bera on EL at the start. expectedStartBalance, isValid := big.NewInt(0).SetString("10000000000000000000000000", 10) s.Require().True(isValid) // Confirm the validator's expected start balance in Wei { startBalance, err := s.TestNode.ContractBackend.BalanceAt(s.CtxApp, senderAddress, big.NewInt(nextBlockHeight-1)) s.Require().NoError(err) s.Require().Equal(expectedStartBalance, startBalance) validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight-1, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 1) // Starts with 10000000000000000 gwei / 10 million BERA staked. s.Require().Equal("10000000000000000", validators[0].Validator.EffectiveBalance) } // Send the Deposit and progress 1 block so that the deposit is included in the next block depositAmount := beaconmath.Gwei(10_000 * 1e9) // 10K BERA { // Send Deposit Requests iterations := int64(10) s.defaultDepositWithNonce(blsSigner, creds, depositAmount, true, big.NewInt(0)) for i := 1; i < 30; i++ { s.defaultDepositWithNonce(blsSigner, creds, depositAmount, false, big.NewInt(int64(i))) } s.LogBuffer.Reset() s.MoveChainToHeight(s.T(), nextBlockHeight, iterations, nodeAddress, time.Now()) nextBlockHeight += iterations // We expect that withdrawals due to excess balance were created s.Require().Contains(s.LogBuffer.String(), "expectedWithdrawals: validator withdrawal due to excess balance") deposits, _, err := s.TestNode.StorageBackend.DepositStore().GetDepositsByIndex( s.CtxApp, 0, uint64(nextBlockHeight)*s.TestNode.ChainSpec.MaxDepositsPerBlock(), ) s.Require().Len(deposits, 31) s.Require().NoError(err) } // Confirm the validator's end balance on EL is similar to the start balance on EL // Confirm the validator's end balance on CL is still at the cap, i.e., 10 Mil BERA. { endBalance, err := s.TestNode.ContractBackend.BalanceAt(s.CtxApp, senderAddress, big.NewInt(nextBlockHeight-1)) s.Require().NoError(err) finalBalanceGwei, convertErr := beaconmath.GweiFromWei(endBalance) s.Require().NoError(convertErr) expectedStartBalanceGwei, convertErr := beaconmath.GweiFromWei(expectedStartBalance) s.Require().NoError(convertErr) s.Require().InDelta(finalBalanceGwei.Unwrap(), expectedStartBalanceGwei.Unwrap(), 2_000_000) // maximum 2_000_000 Gwei delta validators, err := s.TestNode.APIBackend.FilterValidators(nextBlockHeight-1, nil, nil) s.Require().NoError(err) s.Require().Len(validators, 1) // Ends with 10000000000000000 gwei / 10 million BERA staked. s.Require().Equal("10000000000000000", validators[0].Validator.EffectiveBalance) } } func (s *PectraWithdrawalSuite) defaultDepositWithNonce( blsSigner *signer.BLSSigner, creds consensustypes.WithdrawalCredentials, depositAmount beaconmath.Gwei, setOperator bool, nonce *big.Int) { depositContractAddress := gethcommon.Address(s.TestNode.ChainSpec.DepositContractAddress()) depositClient, err := deposit.NewDepositContract(depositContractAddress, s.TestNode.ContractBackend) s.Require().NoError(err) depositMsg, blsSig, err := depositcli.CreateDepositMessage( s.TestNode.ChainSpec, blsSigner, s.GenesisValidatorsRoot, creds, depositAmount, ) s.Require().NoError(err) err = depositcli.ValidateDeposit( s.TestNode.ChainSpec, depositMsg.Pubkey, depositMsg.Credentials, depositMsg.Amount, s.GenesisValidatorsRoot, blsSig, ) s.Require().NoError(err) elChainID := big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID())) senderKey := simulated.GetTestKey(s.T()) senderAddress := gethcommon.HexToAddress(creds.String()) s.Require().NoError(err) operator := senderAddress if !setOperator { operator = gethcommon.HexToAddress("0x0000000000000000000000000000000000000000") } txOpts := &bind.TransactOpts{ From: senderAddress, Signer: func(_ gethcommon.Address, tx *gethcore.Transaction) (*gethcore.Transaction, error) { return gethcore.SignTx( tx, gethcore.LatestSignerForChainID(elChainID), senderKey, ) }, GasLimit: 200_000, Value: big.NewInt(0).Mul(big.NewInt(int64(depositAmount)), big.NewInt(1e9)), } if nonce != nil { txOpts.Nonce = nonce } _, err = depositClient.Deposit(txOpts, depositMsg.Pubkey[:], depositMsg.Credentials[:], blsSig[:], operator) s.Require().NoError(err) } func (s *PectraWithdrawalSuite) defaultDeposit(blsSigner *signer.BLSSigner, creds consensustypes.WithdrawalCredentials, depositAmount beaconmath.Gwei, setOperator bool) { s.defaultDepositWithNonce(blsSigner, creds, depositAmount, setOperator, nil) } ================================================ FILE: testing/simulated/rpc_errors_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "net/http/httptest" "path" "sync/atomic" "testing" "time" "github.com/berachain/beacon-kit/execution/client/ethclient" "github.com/berachain/beacon-kit/log/phuslu" jsonrpc "github.com/berachain/beacon-kit/primitives/net/json-rpc" "github.com/berachain/beacon-kit/primitives/net/url" "github.com/berachain/beacon-kit/testing/simulated" "github.com/berachain/beacon-kit/testing/simulated/execution" "github.com/cometbft/cometbft/abci/types" "github.com/spf13/viper" "github.com/stretchr/testify/suite" ) // HTTP proxy in between beacon node and execution client. When active, // replaces responses with specified JSON-RPC error. type rpcErrorProxy struct { targetURL string active atomic.Bool errorCode int errorMsg string httpClient *http.Client } func newRPCErrorProxy(targetURL string) *rpcErrorProxy { return &rpcErrorProxy{ targetURL: targetURL, httpClient: &http.Client{Timeout: 30 * time.Second}, } } func (p *rpcErrorProxy) activate(code int, msg string) { p.errorCode = code p.errorMsg = msg p.active.Store(true) } func (p *rpcErrorProxy) deactivate() { p.active.Store(false) } func (p *rpcErrorProxy) getErr(reqId json.RawMessage) string { return fmt.Sprintf( `{"jsonrpc":"2.0","id":%s,"error":{"code":%d,"message":"%s"}}`, string(reqId), p.errorCode, p.errorMsg, ) } func (p *rpcErrorProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { bodyBytes, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "proxy read error", http.StatusInternalServerError) return } defer r.Body.Close() // Check if need interceptor. if p.active.Load() { var req struct { ID json.RawMessage `json:"id"` Method string `json:"method"` } if json.Unmarshal(bodyBytes, &req) == nil { // Intercept targeted methods. if isTargetedEngineMethod(req.Method) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte(p.getErr(req.ID))) return } } } // Forward original request. proxyReq, err := http.NewRequestWithContext( r.Context(), r.Method, p.targetURL, bytes.NewReader(bodyBytes), ) if err != nil { http.Error(w, "proxy forward error", http.StatusInternalServerError) return } proxyReq.Header = r.Header.Clone() resp, err := p.httpClient.Do(proxyReq) if err != nil { http.Error(w, "proxy upstream error", http.StatusBadGateway) return } defer resp.Body.Close() for k, vv := range resp.Header { for _, v := range vv { w.Header().Add(k, v) } } w.WriteHeader(resp.StatusCode) _, _ = io.Copy(w, resp.Body) } func isTargetedEngineMethod(method string) bool { switch method { case ethclient.NewPayloadMethodV3, ethclient.NewPayloadMethodV4, ethclient.NewPayloadMethodV4P11, ethclient.ForkchoiceUpdatedMethodV3, ethclient.ForkchoiceUpdatedMethodV3P11: return true } return false } type RPCErrorProxySuite struct { suite.Suite simulated.SharedAccessors errProxy *rpcErrorProxy errProxyServer *httptest.Server } func TestRPCErrorProxySuite(t *testing.T) { suite.Run(t, new(RPCErrorProxySuite)) } // SetupTest inserts a proxy in between the node and execution client, // to enable injection and testing of JSON-RPC errors. func (s *RPCErrorProxySuite) SetupTest() { s.CtxApp, s.CtxAppCancelFn = context.WithCancel(context.Background()) s.CtxComet = context.TODO() s.HomeDir = s.T().TempDir() const elGenesisPath = "./el-genesis-files/eth-genesis.json" chainSpecFunc := simulated.ProvideSimulationChainSpec chainSpec, err := chainSpecFunc() s.Require().NoError(err) configs, genesisValidatorsRoot := simulated.InitializeHomeDirs(s.T(), chainSpec, elGenesisPath, s.HomeDir) cometConfig := configs[0] s.GenesisValidatorsRoot = genesisValidatorsRoot // Start Geth. elNode := execution.NewGethNode(s.HomeDir, execution.ValidGethImage()) elHandle, authRPC, elRPC := elNode.Start(s.T(), path.Base(elGenesisPath)) s.ElHandle = elHandle // Create the error proxy for AuthRPC. s.errProxy = newRPCErrorProxy(authRPC.String()) s.errProxyServer = httptest.NewServer(s.errProxy) // Create a ConnectionURL pointing to the proxy instead of Geth. proxyURL, err := url.NewFromRaw(s.errProxyServer.URL) s.Require().NoError(err) s.LogBuffer = &simulated.SyncBuffer{} logger := phuslu.NewLogger(s.LogBuffer, nil) components := simulated.FixedComponents(s.T()) components = append(components, simulated.ProvideSimComet) components = append(components, chainSpecFunc) // Use proxy connection URL as AuthRPC s.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.HomeDir, CometConfig: cometConfig, AuthRPC: proxyURL, ClientRPC: elRPC, Logger: logger, AppOpts: viper.New(), Components: components, }) s.SimComet = s.TestNode.SimComet go func() { _ = s.TestNode.Start(s.CtxApp) }() s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) s.Require().NoError(err) } func (s *RPCErrorProxySuite) TearDownTest() { s.errProxyServer.Close() s.CleanupTest(s.T()) } // preparedProposal holds the state needed to call FinalizeBlock. type preparedProposal struct { txs [][]byte height int64 proposerAddress []byte proposalTime time.Time } // prepareForFinalize advances the chain and prepares a proposal, returning // the data needed to call FinalizeBlock. func (s *RPCErrorProxySuite) prepareForFinalize() preparedProposal { s.T().Helper() const blockHeight = 1 const coreLoopIterations = 1 s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) startTime := time.Now() proposals, _, proposalTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) currentHeight := int64(blockHeight + coreLoopIterations) proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: proposalTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(proposal) s.LogBuffer.Reset() return preparedProposal{ txs: proposal.Txs, height: currentHeight, proposerAddress: nodeAddress, proposalTime: proposalTime, } } // TestFinalizeBlock_FatalRPCError shows that when exec client returns a // JSON-RPC error (e.g. -32700 parse error) during FinalizeBlock, the error is // correctly identified and returned. func (s *RPCErrorProxySuite) TestFinalizeBlock_HandleRPCError() { pp := s.prepareForFinalize() // Activate the error proxy with an RPC error code (-32700 parse error). s.errProxy.activate(-32700, "Parse Error") finalizeResp, err := s.SimComet.Comet.FinalizeBlock(s.CtxComet, &types.FinalizeBlockRequest{ Txs: pp.txs, Height: pp.height, ProposerAddress: pp.proposerAddress, Time: pp.proposalTime, }) s.Require().Error(err, "FinalizeBlock should fail on fatal RPC error") s.Require().Nil(finalizeResp) s.Require().ErrorIs(err, jsonrpc.ErrParse, "Error should be correctly classified") } ================================================ FILE: testing/simulated/simcomet.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated import ( "context" "github.com/berachain/beacon-kit/beacon/blockchain" "github.com/berachain/beacon-kit/beacon/validator" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/config" cometbft "github.com/berachain/beacon-kit/consensus/cometbft/service" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-core/builder" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/node-core/types" cmtcfg "github.com/cometbft/cometbft/config" cmtcrypto "github.com/cometbft/cometbft/crypto" pvm "github.com/cometbft/cometbft/privval" cmttypes "github.com/cometbft/cometbft/types" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" ) var _ types.ConsensusService = (*SimComet)(nil) // SimComet is normal Comet under the hood, but we override the Start method to avoid starting the actual // CometBFT core loop so that we can orchestrate it ourselves. type SimComet struct { // We are forced to stutter here as we want to override the implementations of the original comet service. Comet *cometbft.Service // Used to initialize the node address. cmtCfg *cmtcfg.Config } func ProvideSimComet( logger *phuslu.Logger, blockchain blockchain.BlockchainI, blockBuilder validator.BlockBuilderI, db dbm.DB, cs chain.Spec, cmtCfg *cmtcfg.Config, appOpts config.AppOptions, telemetrySink *metrics.TelemetrySink) *SimComet { return &SimComet{ Comet: cometbft.NewService( logger, db, blockchain, blockBuilder, cs, cmtCfg, telemetrySink, builder.DefaultServiceOptions(appOpts)..., ), cmtCfg: cmtCfg, } } // Start sets the ctx and the node address for the SimComet service. func (s *SimComet) Start(ctx context.Context) error { s.Comet.ResetAppCtx(ctx) return nil } // GetNodeAddress returns the node address for the SimComet service. func (s *SimComet) GetNodeAddress() (cmtcrypto.Address, error) { privVal, err := pvm.LoadOrGenFilePV( s.cmtCfg.PrivValidatorKeyFile(), s.cmtCfg.PrivValidatorStateFile(), nil, ) if err != nil { return nil, err } pubKey, err := privVal.GetPubKey() if err != nil { return nil, err } return pubKey.Address(), nil } func (s *SimComet) Stop() error { return nil } func (s *SimComet) Name() string { return s.Comet.Name() } func (s *SimComet) IsAppReady() error { return s.Comet.IsAppReady() } func (s *SimComet) CreateQueryContext(height int64, prove bool) (sdk.Context, error) { return s.Comet.CreateQueryContext(height, prove) } func (s *SimComet) GetSyncData() (int64, int64) { panic("unimplemented") } func (s *SimComet) GetBlock(height int64) *cmttypes.Block { return s.Comet.GetBlock(height) } func (s *SimComet) GetSignedHeader(height int64) *cmttypes.SignedHeader { return s.Comet.GetSignedHeader(height) } ================================================ FILE: testing/simulated/simulated_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "context" "path" "testing" "time" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/testing/simulated" "github.com/berachain/beacon-kit/testing/simulated/execution" "github.com/spf13/viper" "github.com/stretchr/testify/suite" ) // SimulatedSuite defines our test suite for the simulated Comet component. type SimulatedSuite struct { suite.Suite // Embedded shared accessors for convenience. simulated.SharedAccessors } // TestSimulatedCometComponent runs the test suite. func TestSimulatedCometComponent(t *testing.T) { suite.Run(t, new(SimulatedSuite)) } // SetupTest initializes the test environment. func (s *SimulatedSuite) SetupTest() { // Create a cancellable context for the duration of the test. s.CtxApp, s.CtxAppCancelFn = context.WithCancel(context.Background()) // CometBFT uses context.TODO() for all ABCI calls, so we replicate that. s.CtxComet = context.TODO() s.HomeDir = s.T().TempDir() // Initialize the home directory, Comet configuration, and genesis info. const elGenesisPath = "./el-genesis-files/eth-genesis.json" chainSpecFunc := simulated.ProvideSimulationChainSpec // Create the chainSpec. chainSpec, err := chainSpecFunc() s.Require().NoError(err) configs, genesisValidatorsRoot := simulated.InitializeHomeDirs(s.T(), chainSpec, elGenesisPath, s.HomeDir) cometConfig := configs[0] s.GenesisValidatorsRoot = genesisValidatorsRoot // Start the EL (execution layer) Geth node. elNode := execution.NewGethNode(s.HomeDir, execution.ValidGethImage()) elHandle, authRPC, elRPC := elNode.Start(s.T(), path.Base(elGenesisPath)) s.ElHandle = elHandle // Prepare a logger backed by a buffer to capture logs for assertions. s.LogBuffer = &simulated.SyncBuffer{} logger := phuslu.NewLogger(s.LogBuffer, nil) // Build the Beacon node with the simulated Comet component. components := simulated.FixedComponents(s.T()) components = append(components, simulated.ProvideSimComet) components = append(components, chainSpecFunc) s.TestNode = simulated.NewTestNode(s.T(), simulated.TestNodeInput{ TempHomeDir: s.HomeDir, CometConfig: cometConfig, AuthRPC: authRPC, ClientRPC: elRPC, Logger: logger, AppOpts: viper.New(), Components: components, }) s.SimComet = s.TestNode.SimComet // Start the Beacon node in a separate goroutine. go func() { _ = s.TestNode.Start(s.CtxApp) }() s.SimulationClient = execution.NewSimulationClient(s.TestNode.EngineClient) timeOut := 10 * time.Second interval := 50 * time.Millisecond err = simulated.WaitTillServicesStarted(s.LogBuffer, timeOut, interval) s.Require().NoError(err) } // TearDownTest cleans up the test environment. func (s *SimulatedSuite) TearDownTest() { s.CleanupTest(s.T()) } ================================================ FILE: testing/simulated/testnode.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated import ( "io" "os" "path/filepath" "testing" "cosmossdk.io/depinject" "github.com/berachain/beacon-kit/beacon/blockchain" "github.com/berachain/beacon-kit/chain" servertypes "github.com/berachain/beacon-kit/cli/commands/server/types" "github.com/berachain/beacon-kit/cli/flags" "github.com/berachain/beacon-kit/config" "github.com/berachain/beacon-kit/da/kzg" "github.com/berachain/beacon-kit/execution/client" "github.com/berachain/beacon-kit/log/phuslu" "github.com/berachain/beacon-kit/node-api/handlers/beacon/types" "github.com/berachain/beacon-kit/node-api/server" service "github.com/berachain/beacon-kit/node-core/services/registry" nodetypes "github.com/berachain/beacon-kit/node-core/types" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/net/url" "github.com/berachain/beacon-kit/state-transition/core" "github.com/berachain/beacon-kit/storage/db" cmtcfg "github.com/cometbft/cometbft/config" dbm "github.com/cosmos/cosmos-db" "github.com/ethereum/go-ethereum/ethclient" "github.com/spf13/viper" "github.com/stretchr/testify/require" ) // TestNodeInput takes the input for building and starting a node type TestNodeInput struct { TempHomeDir string CometConfig *cmtcfg.Config AuthRPC *url.ConnectionURL ClientRPC *url.ConnectionURL Logger *phuslu.Logger AppOpts *viper.Viper Components []any } type ValidatorAPI interface { FilterValidators(height int64, ids []string, statuses []string) ([]*types.ValidatorData, error) } type TestNode struct { nodetypes.Node StorageBackend blockchain.StorageBackend Blockchain *blockchain.Service ChainSpec chain.Spec APIBackend ValidatorAPI SimComet *SimComet EngineClient *client.EngineClient StateProcessor *core.StateProcessor ServiceRegistry *service.Registry KZGVerifier kzg.BlobProofVerifier ContractBackend *ethclient.Client } // NewTestNode Uses the testnet chainspec. func NewTestNode( t *testing.T, input TestNodeInput, ) TestNode { t.Helper() require.NotNil(t, input.AuthRPC) require.NotNil(t, input.ClientRPC) beaconKitConfig := createBeaconKitConfig(t) beaconKitConfig.Engine.RPCDialURL = input.AuthRPC appOpts := getAppOptions(t, input.AppOpts, beaconKitConfig, input.TempHomeDir) // Create a database database, err := db.OpenDB(input.TempHomeDir, dbm.PebbleDBBackend) require.NoError(t, err) // Build a node node := buildNode( input.Logger, database, os.Stdout, // or some other writer input.CometConfig, appOpts, input.Components, ) contractBackend, err := ethclient.Dial(input.ClientRPC.String()) require.NoError(t, err) node.ContractBackend = contractBackend return node } // buildNode run the same logic as primary build, but it returns the components allowing us to query them. func buildNode( logger *phuslu.Logger, db dbm.DB, _ io.Writer, cmtCfg *cmtcfg.Config, appOpts servertypes.AppOptions, components []any, ) TestNode { // variables to hold the components needed to set up BeaconApp var ( apiServer *server.Server beaconNode nodetypes.Node simComet *SimComet config *config.Config storageBackend blockchain.StorageBackend blockchain *blockchain.Service chainSpec chain.Spec engineClient *client.EngineClient stateProcessor *core.StateProcessor serviceRegistry *service.Registry kzgVerifier kzg.BlobProofVerifier ) // build all node components using depinject if err := depinject.Inject( depinject.Configs( depinject.Provide( components..., ), depinject.Supply( appOpts, logger, db, cmtCfg, ), ), &apiServer, &beaconNode, &simComet, &config, &storageBackend, &blockchain, &chainSpec, &engineClient, &stateProcessor, &serviceRegistry, &kzgVerifier, ); err != nil { panic(err) } if config == nil { panic("config is nil") } if apiServer == nil { panic("api server is nil") } logger.WithConfig(config.GetLogger()) return TestNode{ Node: beaconNode, StorageBackend: storageBackend, Blockchain: blockchain, ChainSpec: chainSpec, APIBackend: apiServer.GetBeaconHandler(), SimComet: simComet, EngineClient: engineClient, StateProcessor: stateProcessor, ServiceRegistry: serviceRegistry, KZGVerifier: kzgVerifier, } } // getAppOptions returns the Application Options we need to set for the Node Builder. // Ideally we can avoid having to set the flags like this and just directly modify a config type. func getAppOptions(t *testing.T, appOpts *viper.Viper, beaconKitConfig *config.Config, tempHomeDir string) *viper.Viper { t.Helper() // Execution Client Config relativePathJwt := "../files/jwt.hex" jwtPath, err := filepath.Abs(relativePathJwt) require.NoError(t, err) appOpts.Set(flags.JWTSecretPath, jwtPath) appOpts.Set(flags.RPCJWTRefreshInterval, beaconKitConfig.GetEngine().RPCJWTRefreshInterval.String()) appOpts.Set(flags.RPCStartupCheckInterval, beaconKitConfig.GetEngine().RPCStartupCheckInterval.String()) appOpts.Set(flags.RPCDialURL, beaconKitConfig.GetEngine().RPCDialURL.String()) appOpts.Set(flags.RPCTimeout, beaconKitConfig.GetEngine().RPCTimeout.String()) appOpts.Set(flags.LogLevel, "debug") // BLS Config appOpts.Set(flags.PrivValidatorKeyFile, "./config/priv_validator_key.json") appOpts.Set(flags.PrivValidatorStateFile, "./data/priv_validator_state.json") // Beacon Config appOpts.Set(flags.BlockStoreServiceAvailabilityWindow, beaconKitConfig.GetBlockStoreService().AvailabilityWindow) appOpts.Set(flags.KZGTrustedSetupPath, "../files/kzg-trusted-setup.json") appOpts.Set(flags.KZGImplementation, kzg.DefaultConfig().Implementation) // Payload Builder Config beaconKitConfig.GetPayloadBuilder().SuggestedFeeRecipient, err = common.NewExecutionAddressFromHex( "0x981114102592310C347E61368342DDA67017bf84", ) require.NoError(t, err, "failed to create suggested fee recipient") appOpts.Set(flags.BuilderEnabled, beaconKitConfig.GetPayloadBuilder().Enabled) appOpts.Set(flags.BuildPayloadTimeout, beaconKitConfig.GetPayloadBuilder().PayloadTimeout) appOpts.Set(flags.SuggestedFeeRecipient, beaconKitConfig.GetPayloadBuilder().SuggestedFeeRecipient) // TODO: Cleanup this Set appOpts.Set("pruning", "default") appOpts.Set("home", tempHomeDir) return appOpts } func createBeaconKitConfig(_ *testing.T) *config.Config { return config.DefaultConfig() } ================================================ FILE: testing/simulated/transformers.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated import ( "fmt" "math/big" "unsafe" ctypes "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/testing/simulated/execution" gethengine "github.com/ethereum/go-ethereum/beacon/engine" gethcommon "github.com/ethereum/go-ethereum/common" coretypes "github.com/ethereum/go-ethereum/core/types" gethtypes "github.com/ethereum/go-ethereum/core/types" gethtrie "github.com/ethereum/go-ethereum/trie" ) // transformSimulatedBlockToGethBlock converts a simulated execution block into a Geth-style block. // It uses the provided transactions and parent beacon root to construct a new execution block header. func transformSimulatedBlockToGethBlock( simBlock *execution.SimulatedBlock, txs []*gethtypes.Transaction, parentBeaconRoot common.Root, ) *gethtypes.Block { // Convert numeric fields. excessBlobGas := simBlock.ExcessBlobGas.ToInt().Uint64() blobGasUsed := simBlock.BlobGasUsed.ToInt().Uint64() baseFeePerGas := simBlock.BaseFeePerGas.ToInt() // Compute the withdrawals hash from the simulated block's withdrawals. withdrawalsHash := gethtypes.DeriveSha(simBlock.Withdrawals, gethtrie.NewStackTrie(nil)) // Create a new header using values from the simulated block. header := &gethtypes.Header{ ParentHash: simBlock.ParentHash, UncleHash: gethtypes.EmptyUncleHash, Coinbase: simBlock.Miner, Root: simBlock.StateRoot, // TxHash is computed from the provided transactions since simulation does not have signatures // which is required for correct hash calculation. TxHash: gethtypes.DeriveSha(gethtypes.Transactions(txs), gethtrie.NewStackTrie(nil)), ReceiptHash: simBlock.ReceiptsRoot, Bloom: gethtypes.Bloom(simBlock.LogsBloom), Difficulty: big.NewInt(0), Number: (*big.Int)(simBlock.Number), GasLimit: (uint64)(*simBlock.GasLimit), GasUsed: (uint64)(*simBlock.GasUsed), Time: (uint64)(*simBlock.Timestamp), BaseFee: baseFeePerGas, Extra: simBlock.ExtraData, MixDigest: simBlock.MixHash, WithdrawalsHash: &withdrawalsHash, ExcessBlobGas: &excessBlobGas, BlobGasUsed: &blobGasUsed, ParentBeaconRoot: (*gethcommon.Hash)(&parentBeaconRoot), } // Create the block body using the transactions and withdrawals from the simulation. body := gethtypes.Body{ Transactions: txs, Uncles: nil, Withdrawals: simBlock.Withdrawals, } return gethtypes.NewBlockWithHeader(header).WithBody(body) } // transformExecutableDataToExecutionPayload converts Ethereum executable data into a beacon execution payload. // This function supports fork versions prior to Deneb1. For unsupported fork versions, it returns an error. func transformExecutableDataToExecutionPayload( forkVersion common.Version, data *gethengine.ExecutableData, ) (*ctypes.ExecutionPayload, error) { // Check that the fork version is supported if version.IsAfter(forkVersion, version.Electra()) { return nil, ctypes.ErrForkVersionNotSupported } // Convert withdrawals withdrawals := *(*engineprimitives.Withdrawals)(unsafe.Pointer(&data.Withdrawals)) // Truncate ExtraData if it exceeds the allowed length. if len(data.ExtraData) > constants.ExtraDataLength { data.ExtraData = data.ExtraData[:constants.ExtraDataLength] } // Safely dereference optional fields. var blobGasUsed, excessBlobGas uint64 if data.BlobGasUsed != nil { blobGasUsed = *data.BlobGasUsed } if data.ExcessBlobGas != nil { excessBlobGas = *data.ExcessBlobGas } // Convert BaseFeePerGas into a U256 value. baseFeePerGas, err := math.NewU256FromBigInt(data.BaseFeePerGas) if err != nil { return nil, fmt.Errorf("failed baseFeePerGas conversion: %w", err) } // Construct the execution payload. executionPayload := &ctypes.ExecutionPayload{ Versionable: ctypes.NewVersionable(forkVersion), ParentHash: common.ExecutionHash(data.ParentHash), FeeRecipient: common.ExecutionAddress(data.FeeRecipient), StateRoot: common.Bytes32(data.StateRoot), ReceiptsRoot: common.Bytes32(data.ReceiptsRoot), LogsBloom: [256]byte(data.LogsBloom), Random: common.Bytes32(data.Random), Number: math.U64(data.Number), GasLimit: math.U64(data.GasLimit), GasUsed: math.U64(data.GasUsed), Timestamp: math.U64(data.Timestamp), Withdrawals: withdrawals, ExtraData: data.ExtraData, BaseFeePerGas: baseFeePerGas, BlockHash: common.ExecutionHash(data.BlockHash), Transactions: data.Transactions, BlobGasUsed: math.U64(blobGasUsed), ExcessBlobGas: math.U64(excessBlobGas), } return executionPayload, nil } // splitTxs separates transactions into two slices: // 1. Transactions with blob sidecars removed. // 2. The extracted blob sidecars, if any. func splitTxs(txs []*coretypes.Transaction) (txsWithoutSidecars []*coretypes.Transaction, txSidecars []*coretypes.BlobTxSidecar) { txsWithoutSidecars = make([]*coretypes.Transaction, 0, len(txs)) txSidecars = make([]*coretypes.BlobTxSidecar, 0, len(txs)) for _, tx := range txs { // Append the transaction with its blob sidecar removed. txsWithoutSidecars = append(txsWithoutSidecars, tx.WithoutBlobTxSidecar()) // If a blob sidecar exists, collect it. if sidecar := tx.BlobTxSidecar(); sidecar != nil { txSidecars = append(txSidecars, sidecar) } } return } ================================================ FILE: testing/simulated/utils.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated import ( "bytes" "context" "crypto/ecdsa" "fmt" "path/filepath" "sync" "testing" "time" "unsafe" "github.com/berachain/beacon-kit/beacon/blockchain" payloadtime "github.com/berachain/beacon-kit/beacon/payload-time" "github.com/berachain/beacon-kit/chain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" "github.com/berachain/beacon-kit/da/kzg" "github.com/berachain/beacon-kit/da/kzg/gokzg" "github.com/berachain/beacon-kit/errors" gethtypes "github.com/berachain/beacon-kit/gethlib/types" "github.com/berachain/beacon-kit/node-core/components/signer" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/constants" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/primitives/version" "github.com/berachain/beacon-kit/state-transition/core" "github.com/berachain/beacon-kit/testing/simulated/execution" "github.com/cometbft/cometbft/abci/types" cmtcrypto "github.com/cometbft/cometbft/crypto" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" gokzg4844 "github.com/crate-crypto/go-kzg-4844" "github.com/ethereum/go-ethereum/beacon/engine" gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" coretypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" ) // testPkey corresponds to address 0x20f33ce90a13a4b5e7697e3544c3083b8f8a51d4 which is prefunded in genesis const testPkey = "fffdbb37105441e14b0ee6330d855d8504ff39e705c3afa8f859ac9865f99306" // SyncBuffer is a thread-safe wrapper around bytes.Buffer. type SyncBuffer struct { mu sync.RWMutex buf bytes.Buffer } func (sb *SyncBuffer) Write(p []byte) (int, error) { sb.mu.Lock() defer sb.mu.Unlock() return sb.buf.Write(p) } func (sb *SyncBuffer) String() string { sb.mu.RLock() defer sb.mu.RUnlock() return sb.buf.String() } func (sb *SyncBuffer) Reset() { sb.mu.Lock() defer sb.mu.Unlock() sb.buf.Reset() } func (sb *SyncBuffer) Contains(substr []byte) bool { sb.mu.RLock() defer sb.mu.RUnlock() return bytes.Contains(sb.buf.Bytes(), substr) } // SharedAccessors holds references to common utilities required in tests. type SharedAccessors struct { CtxApp context.Context CtxAppCancelFn context.CancelFunc CtxComet context.Context HomeDir string TestNode TestNode SimComet *SimComet LogBuffer *SyncBuffer GenesisValidatorsRoot common.Root SimulationClient *execution.SimulationClient // ElHandle is a dockertest resource handle that should be closed in teardown. ElHandle *execution.Resource } // CleanupTest performs common cleanup operations for test suites. // Call this from TearDownTest to ensure proper cleanup even when setup fails. func (s *SharedAccessors) CleanupTest(t *testing.T) { s.CleanupTestWithLabel(t, "") } // CleanupTestWithLabel performs common cleanup operations with an optional label for logs. // Use this when managing multiple execution clients (e.g., "GETH", "RETH"). func (s *SharedAccessors) CleanupTestWithLabel(t *testing.T, label string) { t.Helper() // If the test has failed, log additional information. if t.Failed() && s.LogBuffer != nil { if label != "" { t.Logf("%s CL LOGS:", label) } t.Log(s.LogBuffer.String()) } // Close execution layer handle if it exists. if s.ElHandle != nil { if err := s.ElHandle.Close(); err != nil { if label != "" { t.Errorf("Error closing %s EL handle: %v", label, err) } else { t.Errorf("Error closing EL handle: %v", err) } } } // Cancel the application context if it exists. if s.CtxAppCancelFn != nil { s.CtxAppCancelFn() } // Stop all services if the service registry exists. if s.TestNode.ServiceRegistry != nil { s.TestNode.ServiceRegistry.StopAll() } } // InitializeChain sets up the chain using the genesis file and verifies the // expected number of validators and deposits are present. func (s *SharedAccessors) InitializeChain(t *testing.T, numValidators int) { t.Helper() appGenesis, err := genutiltypes.AppGenesisFromFile(s.HomeDir + "/config/genesis.json") require.NoError(t, err) initResp, err := s.SimComet.Comet.InitChain(s.CtxComet, &types.InitChainRequest{ ChainId: TestnetBeaconChainID, AppStateBytes: appGenesis.AppState, }) require.NoError(t, err) require.Len(t, initResp.Validators, numValidators, fmt.Sprintf("Expected %d validator(s)", numValidators)) deposits, _, err := s.TestNode.StorageBackend.DepositStore().GetDepositsByIndex( s.CtxApp, constants.FirstDepositIndex, constants.FirstDepositIndex+s.TestNode.ChainSpec.MaxDepositsPerBlock(), ) require.NoError(t, err) require.Len(t, deposits, numValidators, fmt.Sprintf("Expected %d deposit(s)", numValidators)) } // MoveChainToHeight will iterate through the core loop `iterations` times, i.e. Propose, Process, Finalize and Commit. // Returns the list of proposed comet blocks. func (s *SharedAccessors) MoveChainToHeight( t *testing.T, startHeight, iterations int64, nodeAddress cmtcrypto.Address, startTime time.Time, ) ([]*types.PrepareProposalResponse, []*types.FinalizeBlockResponse, time.Time) { // Prepare a block proposal. var proposedCometBlocks []*types.PrepareProposalResponse var finalizedResponses []*types.FinalizeBlockResponse proposalTime := startTime for currentHeight := startHeight; currentHeight < startHeight+iterations; currentHeight++ { proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: proposalTime, ProposerAddress: nodeAddress, }) require.NoError(t, err) require.Len(t, proposal.Txs, 2) // Process the proposal. processReq := &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: proposalTime, NextProposerAddress: nodeAddress, // Trigger an optimistic build for the next height. } processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, processReq) require.NoError(t, err) require.Equal(t, types.PROCESS_PROPOSAL_STATUS_ACCEPT.String(), processResp.Status.String()) // Finalize the block. finalizeResp, err := s.SimComet.Comet.FinalizeBlock(s.CtxComet, &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: proposalTime, }) require.NoError(t, err) require.NotEmpty(t, finalizeResp) // Commit the block. _, err = s.SimComet.Comet.Commit(s.CtxComet, &types.CommitRequest{}) require.NoError(t, err) // Record the Commit Block proposedCometBlocks = append(proposedCometBlocks, proposal) finalizedResponses = append(finalizedResponses, finalizeResp) // set consensus time for the next block to match // the timestamp of the payload built optimistically. forkVersion := s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(proposalTime.Unix())) //#nosec: G115 blk, _, err := encoding.ExtractBlobsAndBlockFromRequest( processReq, blockchain.BeaconBlockTxIndex, blockchain.BlobSidecarsTxIndex, forkVersion, ) require.NoError(t, err) proposalTime = time.Unix( int64(payloadtime.Next(blk.GetTimestamp(), blk.GetTimestamp(), true)), 0, ) } return proposedCometBlocks, finalizedResponses, proposalTime } // WaitTillServicesStarted waits until the log buffer contains "All services started". // It checks periodically with a timeout to prevent indefinite waiting. // If there is a better way to determine the services have started, e.g. readiness probe, replace this. func WaitTillServicesStarted(logBuffer *SyncBuffer, timeout, interval time.Duration) error { deadline := time.After(timeout) ticker := time.NewTicker(interval) defer ticker.Stop() for { select { case <-deadline: return errors.New("timeout waiting for services to start") case <-ticker.C: if logBuffer.Contains([]byte("All services started")) { return nil } } } } func GetTestKey(t *testing.T) *ecdsa.PrivateKey { t.Helper() // Create a test key - copied from go-ethereum. testKey, err := crypto.HexToECDSA(testPkey) require.NoError(t, err, "failed to create test key for malicious transaction") return testKey } // GetBlsSigner returns a new BLSSigner using the configuration files in the provided home directory. func GetBlsSigner(tempHomeDir string) *signer.BLSSigner { privValKeyFile := filepath.Join(tempHomeDir, "config", "priv_validator_key.json") privValStateFile := filepath.Join(tempHomeDir, "data", "priv_validator_state.json") return signer.NewBLSSigner(privValKeyFile, privValStateFile) } func DefaultSimulationInput( t *testing.T, chainSpec chain.Spec, origBlock *ctypes.BeaconBlock, txs []*coretypes.Transaction, ) *execution.SimOpts { t.Helper() overrideTime := hexutil.Uint64(origBlock.GetTimestamp().Unwrap()) overrideGasLimit := hexutil.Uint64(30000000) overrideFeeRecipient := origBlock.GetBody().GetExecutionPayload().GetFeeRecipient() overridePrevRandao := gethcommon.Hash(origBlock.GetBody().GetExecutionPayload().GetPrevRandao()) overrideBaseFeePerGas := origBlock.GetBody().GetExecutionPayload().GetBaseFeePerGas().ToBig() overrideBeaconRoot := gethcommon.HexToHash(origBlock.GetParentBlockRoot().Hex()) origWithdrawls := origBlock.GetBody().GetExecutionPayload().GetWithdrawals() overrideWithdrawals := *(*coretypes.Withdrawals)(unsafe.Pointer(&origWithdrawls)) calls, err := execution.TxsToTransactionArgs(chainSpec.DepositEth1ChainID(), txs) require.NoError(t, err) simulationInput := &execution.SimOpts{ BlockStateCalls: []*execution.SimBlock{ { Calls: calls, BlockOverrides: &execution.BlockOverrides{ Time: &overrideTime, GasLimit: &overrideGasLimit, FeeRecipient: (*gethcommon.Address)(&overrideFeeRecipient), PrevRandao: &overridePrevRandao, BaseFeePerGas: (*hexutil.Big)(overrideBaseFeePerGas), BeaconRoot: &overrideBeaconRoot, Withdrawals: overrideWithdrawals, // TODO: Do we need to override blob base fee? }, }, }, Validation: true, TraceTransfers: false, } return simulationInput } // ComputeAndSetInvalidExecutionBlock transforms the current execution payload of latestBlock // into a new payload (using the invalid transformation) and updates latestBlock with it. // This will make sure all the fields validated by the CL, i.e. Execution Block Hash, are valid, but does not set // correct values for fields like the Execution Block StateRoot and ReceiptsRoot as that requires simulation and // is not validated in the CL. func ComputeAndSetInvalidExecutionBlock( t *testing.T, latestBlock *ctypes.BeaconBlock, chainSpec chain.Spec, txs []*coretypes.Transaction, executionRequests *ctypes.ExecutionRequests, ) *ctypes.BeaconBlock { t.Helper() forkVersion := chainSpec.ActiveForkVersionForTimestamp(latestBlock.GetTimestamp()) _, sidecars := splitTxs(txs) // Use the current execution payload (e.g. for an invalid block, no simulation is done). executionPayload := latestBlock.GetBody().GetExecutionPayload() // Transform the payload into a Geth block. txsBytesArray := make([][]byte, len(txs)) for i, tx := range txs { txBytes, err := tx.MarshalBinary() require.NoError(t, err) txsBytesArray[i] = txBytes } executionPayload.Transactions = txsBytesArray parentBlockRoot := latestBlock.GetParentBlockRoot() var ( execBlock *gethtypes.Block encodedExecRequests []ctypes.EncodedExecutionRequest err error ) if version.EqualsOrIsAfter(forkVersion, version.Electra()) { encodedExecRequests, err = ctypes.GetExecutionRequestsList(executionRequests) require.NoError(t, err) } execBlock, _, err = ctypes.MakeEthBlock(executionPayload, parentBlockRoot, encodedExecRequests, nil) require.NoError(t, err) return updateBeaconBlockBody(t, latestBlock, forkVersion, execBlock, sidecars, executionRequests) } // ComputeAndSetValidExecutionBlock simulates a new execution payload based on the provided transactions, // transforms the simulated block into a Geth-style execution block, and updates the given beacon block // with the new execution payload. This will correctly set the Execution Block State and Receipts Root using simulation. // Note: The returned block's state root is not finalized and must be updated via a state transition (see ComputeAndSetStateRoot). func ComputeAndSetValidExecutionBlock( t *testing.T, latestBlock *ctypes.BeaconBlock, simClient *execution.SimulationClient, chainSpec chain.Spec, txs []*coretypes.Transaction, ) *ctypes.BeaconBlock { t.Helper() // Check that the fork version is supported if version.IsAfter(latestBlock.GetForkVersion(), version.Deneb1()) { t.Fatalf("fork version %s is not supported by this function", latestBlock.GetForkVersion()) } // Run simulation to get a simulated block. baseHeight := int64(latestBlock.GetSlot().Unwrap()) - 1 simInput := DefaultSimulationInput(t, chainSpec, latestBlock, txs) simulatedBlocks, err := simClient.Simulate(context.TODO(), baseHeight, simInput) require.NoError(t, err) require.Len(t, simulatedBlocks, 1) simBlock := simulatedBlocks[0] forkVersion := chainSpec.ActiveForkVersionForTimestamp(latestBlock.GetTimestamp()) txsNoSidecar, sidecars := splitTxs(txs) origParent := latestBlock.GetParentBlockRoot() // Transform the simulated block into a Geth block. execBlock := transformSimulatedBlockToGethBlock(simBlock, txsNoSidecar, origParent) // TODO: Add support for execution requests before allowing electra return updateBeaconBlockBody(t, latestBlock, forkVersion, execBlock, sidecars, nil) } // ComputeAndSetStateRoot applies a state transition to the given beacon block. // It creates a copy of the current state (from the provided storage backend and query context), // constructs a transition context using the consensus time and proposer address, // runs the state transition, and then updates the block’s state root based on the new state. // Returns the updated block or an error. // This should only be used if you know the block is valid. Otherwise use ComputeAndSetInvalidExecutionBlock. // TODO: Can we use a mocked execution client for the StateProcessor to avoid doing an unnecessary NewPayload? func ComputeAndSetStateRoot( queryCtx context.Context, consensusTime time.Time, proposerAddress []byte, stateProcessor *core.StateProcessor, storageBackend blockchain.StorageBackend, block *ctypes.BeaconBlock, ) (*ctypes.BeaconBlock, error) { // Copy the current state from the storage backend. stateDBCopy := storageBackend.StateFromContext(queryCtx).Protect(queryCtx) // Create a transition context with the provided consensus time and proposer address. txCtx := transition.NewTransitionCtx( queryCtx, math.U64(consensusTime.Unix()), proposerAddress, ).WithVerifyPayload(false). WithVerifyRandao(false). WithVerifyResult(false). WithMeterGas(false) // Run the state transition. _, err := stateProcessor.Transition(txCtx, stateDBCopy, block) if err != nil { return nil, fmt.Errorf("state transition failed: %w", err) } // Compute the new state root from the updated state. newStateRoot := stateDBCopy.HashTreeRoot() block.SetStateRoot(newStateRoot) return block, nil } // GetProofAndCommitmentsForBlobs will create a commitment and proof for each blob. Technically func GetProofAndCommitmentsForBlobs( t *require.Assertions, blobs []*eip4844.Blob, verifier kzg.BlobProofVerifier, ) ([]eip4844.KZGProof, []eip4844.KZGCommitment) { if verifier.GetImplementation() != gokzg.Implementation { t.Fail("test expects gokzg implementation") } gokzgVerifier, ok := verifier.(*gokzg.Verifier) if !ok { t.Fail("verifier is not of type *gokzg.Verifier") } commitments := make([]eip4844.KZGCommitment, len(blobs)) proofs := make([]eip4844.KZGProof, len(blobs)) for i, blob := range blobs { kzgBlob := (*gokzg4844.Blob)(blob) commitment, err := gokzgVerifier.BlobToKZGCommitment(kzgBlob, 1) t.NoError(err) proof, err := gokzgVerifier.ComputeBlobKZGProof(kzgBlob, commitment, 1) t.NoError(err) commitments[i] = eip4844.KZGCommitment(commitment) proofs[i] = eip4844.KZGProof(proof) } return proofs, commitments } // updateBeaconBlockBody converts executable data into an ExecutionPayload using // the given fork version, and then sets that payload into latestBlock. It // returns the updated block. func updateBeaconBlockBody( t *testing.T, latestBlock *ctypes.BeaconBlock, forkVersion common.Version, execBlock any, sidecars []*coretypes.BlobTxSidecar, // adjust type as needed executionRequests *ctypes.ExecutionRequests, ) *ctypes.BeaconBlock { var erBytes [][]byte if version.EqualsOrIsAfter(forkVersion, version.Electra()) { encodedExecRequests, err := ctypes.GetExecutionRequestsList(executionRequests) require.NoError(t, err) for _, er := range encodedExecRequests { erBytes = append(erBytes, er) } } var execData *engine.ExecutionPayloadEnvelope switch execBlock := execBlock.(type) { case *gethtypes.Block: execData = gethtypes.BlockToExecutableData(execBlock, nil, sidecars, erBytes) case *coretypes.Block: execData = engine.BlockToExecutableData(execBlock, nil, sidecars, erBytes) default: t.Fatalf("unsupported block type: %T", execBlock) return nil } // Convert the ExecutableData into our internal ExecutionPayload type. execPayload, err := transformExecutableDataToExecutionPayload(forkVersion, execData.ExecutionPayload) require.NoError(t, err, "failed to convert executable data") // Update the beacon block with the new execution payload. latestBlock.GetBody().SetExecutionPayload(execPayload) if version.EqualsOrIsAfter(forkVersion, version.Electra()) { err = latestBlock.GetBody().SetExecutionRequests(executionRequests) require.NoError(t, err) } return latestBlock } ================================================ FILE: testing/simulated/valid_chain_test.go ================================================ //go:build simulated // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. package simulated_test import ( "math/big" "time" "github.com/berachain/beacon-kit/beacon/blockchain" ctypes "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/consensus/cometbft/service/encoding" dablob "github.com/berachain/beacon-kit/da/blob" datypes "github.com/berachain/beacon-kit/da/types" "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/testing/simulated" "github.com/cometbft/cometbft/abci/types" gethcommon "github.com/ethereum/go-ethereum/common" gethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/holiman/uint256" "github.com/stretchr/testify/require" ) // TestFullLifecycle_ValidBlock_IsSuccessful tests that a valid block proposal is processed, finalized, and committed. // It loops through this core process `coreLoopIterations` times. func (s *SimulatedSuite) TestFullLifecycle_ValidBlock_IsSuccessful() { const blockHeight = 1 const coreLoopIterations = 10 // Initialize the chain state. s.InitializeChain(s.T(), 1) nodeAddress, err := s.SimComet.GetNodeAddress() s.Require().NoError(err) s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens post Deneb1 fork. startTime := time.Now() // iterate through the core loop `coreLoopIterations` times, i.e. Propose, Process, Finalize and Commit. proposals, _, _ := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) // We expect that the number of proposals that were finalized should be `coreLoopIterations`. s.Require().Len(proposals, coreLoopIterations) currentHeight := int64(blockHeight + coreLoopIterations) // Validate post-commit state. queryCtx, err := s.SimComet.CreateQueryContext(currentHeight-1, false) s.Require().NoError(err) stateDB := s.TestNode.StorageBackend.StateFromContext(queryCtx) slot, err := stateDB.GetSlot() s.Require().NoError(err) s.Require().Equal(math.U64(currentHeight-1), slot) stateHeader, err := stateDB.GetLatestBlockHeader() s.Require().NoError(err) lph, err := stateDB.GetLatestExecutionPayloadHeader() s.Require().NoError(err) // Unmarshal the beacon block from the ABCI request. proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( proposals[len(proposals)-1].Txs, blockchain.BeaconBlockTxIndex, s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(lph.GetTimestamp()), ) s.Require().NoError(err) s.Require().Equal(proposedBlock.GetHeader().GetBodyRoot(), stateHeader.GetBodyRoot()) } // TestFullLifecycle_ValidBlockWithInjectedTransaction_IsSuccessful effectively serves as a demonstration for how one can // inject custom transactions and state transitions into the core loop. func (s *SimulatedSuite) TestFullLifecycle_ValidBlockWithInjectedTransaction_IsSuccessful() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens on Deneb, pre Deneb1 fork. startTime := time.Unix(0, 0) // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, consensusTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) // We expected this test to happen during Pre-Deneb1 fork. currentHeight := int64(blockHeight + coreLoopIterations) // Prepare a valid block proposal. proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(proposal) // Unmarshal the proposal block. proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( proposal.Txs, blockchain.BeaconBlockTxIndex, s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())), ) s.Require().NoError(err) // Sign a valid transaction that is expected to pass recipientAddress := gethcommon.HexToAddress("0x56898d1aFb10cad584961eb96AcD476C6826e41E") validTx, err := gethtypes.SignNewTx( simulated.GetTestKey(s.T()), gethtypes.NewCancunSigner(big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID()))), &gethtypes.DynamicFeeTx{ Nonce: 0, To: &recipientAddress, Value: big.NewInt(0), Gas: 21016, GasTipCap: big.NewInt(765625000), GasFeeCap: big.NewInt(765625000), Data: []byte{}, }, ) validTxs := []*gethtypes.Transaction{validTx} // Create a new beacon block with the valid transaction. // Note: The beacon block returned here has an incorrect beacon state root, which is fixed in `ComputeAndSetStateRoot`. unsignedBlock := simulated.ComputeAndSetValidExecutionBlock(s.T(), proposedBlock.GetBeaconBlock(), s.SimulationClient, s.TestNode.ChainSpec, validTxs) // Finalize the block by applying the state transition to update its state root. queryCtx, err := s.SimComet.CreateQueryContext(currentHeight-1, false) s.Require().NoError(err) finalBlock, err := simulated.ComputeAndSetStateRoot(queryCtx, consensusTime, nodeAddress, s.TestNode.StateProcessor, s.TestNode.StorageBackend, unsignedBlock) s.Require().NoError(err) newSignedBlock, err := ctypes.NewSignedBeaconBlock( finalBlock, &ctypes.ForkData{ CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(unsignedBlock.GetTimestamp()), GenesisValidatorsRoot: s.GenesisValidatorsRoot, }, s.TestNode.ChainSpec, blsSigner, ) s.Require().NoError(err) newBlockBytes, err := newSignedBlock.MarshalSSZ() s.Require().NoError(err) // Replace the old block with the new block in the proposal. proposal.Txs[0] = newBlockBytes // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() // Process the proposal containing the valid block. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: consensusTime, }) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Finalize the block. finalizeResp, err := s.SimComet.Comet.FinalizeBlock(s.CtxComet, &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: consensusTime, }) s.Require().NoError(err) s.Require().NotEmpty(finalizeResp) // Commit the block. _, err = s.SimComet.Comet.Commit(s.CtxComet, &types.CommitRequest{}) s.Require().NoError(err) } // TestFullLifecycle_ValidBlockAndInjectedBlob_IsSuccessful tests that a valid block and blob and proposal is processed, finalized, and committed. func (s *SimulatedSuite) TestFullLifecycle_ValidBlockAndInjectedBlob_IsSuccessful() { const blockHeight = 1 const coreLoopIterations = 1 // Initialize the chain state. s.InitializeChain(s.T(), 1) // Retrieve the BLS signer and proposer address. blsSigner := simulated.GetBlsSigner(s.HomeDir) pubkey, err := blsSigner.GetPubKey() s.Require().NoError(err) nodeAddress := pubkey.Address() s.SimComet.Comet.SetNodeAddress(nodeAddress) // Test happens on Deneb, pre Deneb1 fork. startTime := time.Unix(0, 0) // Go through 1 iteration of the core loop to bypass any startup specific edge cases such as sync head on startup. proposals, _, consensusTime := s.MoveChainToHeight(s.T(), blockHeight, coreLoopIterations, nodeAddress, startTime) s.Require().Len(proposals, coreLoopIterations) // We expected this test to happen during Pre-Deneb1 fork. currentHeight := int64(blockHeight + coreLoopIterations) // Prepare a valid block proposal. proposal, err := s.SimComet.Comet.PrepareProposal(s.CtxComet, &types.PrepareProposalRequest{ Height: currentHeight, Time: consensusTime, ProposerAddress: nodeAddress, }) s.Require().NoError(err) s.Require().NotEmpty(proposal) // Unmarshal the proposal block. proposedBlock, err := encoding.UnmarshalBeaconBlockFromABCIRequest( proposal.Txs, blockchain.BeaconBlockTxIndex, s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(math.U64(consensusTime.Unix())), ) s.Require().NoError(err) // Create the Blobs, with proofs and commitments // Each blob will go into 1 transaction. blobs := []*eip4844.Blob{{1, 2, 3}, {4, 5, 6}} proofs, commitments := simulated.GetProofAndCommitmentsForBlobs(require.New(s.T()), blobs, s.TestNode.KZGVerifier) s.Require().Len(proofs, len(blobs)) s.Require().Len(commitments, len(blobs)) // Sign blob transactions blobTxs := make([]*gethtypes.Transaction, len(blobs)) for i := range blobs { blobCommitment := commitments[i] blobHash := blobCommitment.ToVersionedHash() txSidecar := &gethtypes.BlobTxSidecar{ Blobs: []kzg4844.Blob{kzg4844.Blob(blobs[i][:])}, Commitments: []kzg4844.Commitment{kzg4844.Commitment(blobCommitment)}, Proofs: []kzg4844.Proof{kzg4844.Proof(proofs[i])}, } blobTx, err := gethtypes.SignNewTx( simulated.GetTestKey(s.T()), gethtypes.NewCancunSigner(big.NewInt(int64(s.TestNode.ChainSpec.DepositEth1ChainID()))), &gethtypes.BlobTx{ Nonce: uint64(i), // Set to 875000000 as that is the tx base fee GasTipCap: uint256.NewInt(875000000), GasFeeCap: uint256.NewInt(875000000), // Set to 21000 for minimum intrinsic gas Gas: 210000, Value: uint256.NewInt(0), Data: []byte{}, AccessList: nil, BlobFeeCap: uint256.NewInt(10), // If we have 1 tx with multiple blobs, we must add the blob hashes here. BlobHashes: []gethcommon.Hash{blobHash}, // Sidecar must be set to nil here or Geth will error with "unexpected blob sidecar in transaction" Sidecar: nil, }, ) s.Require().NoError(err) // Once we've signed the Tx, we tag the blob with the tx purely for association between tx and sidecars. // In this case, each 1 tx has a sidecar with 1 blob, even though 1 tx could have more than 1 blob. blobTx = blobTx.WithBlobTxSidecar(txSidecar) blobTxs[i] = blobTx } proposedBlockMessage := simulated.ComputeAndSetValidExecutionBlock( s.T(), proposedBlock.GetBeaconBlock(), s.SimulationClient, s.TestNode.ChainSpec, blobTxs, ) proposedBlockMessage.GetBody().SetBlobKzgCommitments(commitments) // Finalize the block by applying the state transition to update its state root. queryCtx, err := s.SimComet.CreateQueryContext(currentHeight-1, false) s.Require().NoError(err) proposedBlockMessage, err = simulated.ComputeAndSetStateRoot(queryCtx, consensusTime, nodeAddress, s.TestNode.StateProcessor, s.TestNode.StorageBackend, proposedBlockMessage) s.Require().NoError(err) newSignedBlock, err := ctypes.NewSignedBeaconBlock( proposedBlockMessage, &ctypes.ForkData{ CurrentVersion: s.TestNode.ChainSpec.ActiveForkVersionForTimestamp(proposedBlockMessage.GetTimestamp()), GenesisValidatorsRoot: s.GenesisValidatorsRoot, }, s.TestNode.ChainSpec, blsSigner, ) s.Require().NoError(err) // Inject the new block newSignedBlockBytes, err := newSignedBlock.MarshalSSZ() s.Require().NoError(err) proposal.Txs[0] = newSignedBlockBytes // Create the beaconBlock Header for the sidecar blockWithCommitmentsSignedHeader := ctypes.NewSignedBeaconBlockHeader( newSignedBlock.GetHeader(), newSignedBlock.GetSignature(), ) sidecarsSlice := make([]*datypes.BlobSidecar, len(blobs)) // Build Inclusion Proofs for Sidecars sidecarFactory := dablob.NewSidecarFactory(metrics.NewNoOpTelemetrySink()) for i := range blobs { inclusionProof, err := sidecarFactory.BuildKZGInclusionProof(proposedBlockMessage.GetBody(), math.U64(i)) s.Require().NoError(err) sidecar := datypes.BuildBlobSidecar( math.U64(i), blockWithCommitmentsSignedHeader, blobs[i], commitments[i], proofs[i], inclusionProof, ) sidecarsSlice[i] = sidecar } sidecars := datypes.BlobSidecars(sidecarsSlice) // Inject the valid sidecar sidecarBytes, err := sidecars.MarshalSSZ() s.Require().NoError(err) proposal.Txs[1] = sidecarBytes // Reset the log buffer to discard old logs we don't care about s.LogBuffer.Reset() // Process the proposal containing the valid block. processResp, err := s.SimComet.Comet.ProcessProposal(s.CtxComet, &types.ProcessProposalRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: consensusTime, }) s.Require().NoError(err) s.Require().Equal(types.PROCESS_PROPOSAL_STATUS_ACCEPT, processResp.Status) // Finalize the block. finalizeResp, err := s.SimComet.Comet.FinalizeBlock(s.CtxComet, &types.FinalizeBlockRequest{ Txs: proposal.Txs, Height: currentHeight, ProposerAddress: nodeAddress, Time: consensusTime, }) s.Require().NoError(err) s.Require().NotEmpty(finalizeResp) // Commit the block. _, err = s.SimComet.Comet.Commit(s.CtxComet, &types.CommitRequest{}) s.Require().NoError(err) } ================================================ FILE: testing/state-transition/README.md ================================================ # Testing state transitions This package, `statetransition`, contains code which is helpful to test state transitions. Specifically, it contains code to instantiate a test state processor with a mocked bls signer and its own state. This code can be reused across tests in multiple packages but **should not be used in production code**. ================================================ FILE: testing/state-transition/state-transition.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build test package statetransition import ( "context" "fmt" "testing" corestore "cosmossdk.io/core/store" "cosmossdk.io/log" "cosmossdk.io/store" "cosmossdk.io/store/metrics" storetypes "cosmossdk.io/store/types" "github.com/berachain/beacon-kit/chain" "github.com/berachain/beacon-kit/consensus-types/types" "github.com/berachain/beacon-kit/log/noop" nodemetrics "github.com/berachain/beacon-kit/node-core/components/metrics" "github.com/berachain/beacon-kit/primitives/bytes" cryptomocks "github.com/berachain/beacon-kit/primitives/crypto/mocks" "github.com/berachain/beacon-kit/primitives/transition" "github.com/berachain/beacon-kit/state-transition/core" "github.com/berachain/beacon-kit/state-transition/core/mocks" statedb "github.com/berachain/beacon-kit/state-transition/core/state" "github.com/berachain/beacon-kit/storage" "github.com/berachain/beacon-kit/storage/beacondb" "github.com/berachain/beacon-kit/storage/db" "github.com/berachain/beacon-kit/storage/deposit" dbm "github.com/cosmos/cosmos-db" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" ) type ( TestBeaconStateMarshallableT = types.BeaconState TestBeaconStateT = statedb.StateDB TestStateProcessorT = core.StateProcessor ) type testKVStoreService struct{} func (kvs *testKVStoreService) OpenKVStore(ctx context.Context) corestore.KVStore { store := sdk.UnwrapSDKContext(ctx).KVStore(testStoreKey) return storage.NewKVStore(store) } var ( //nolint:gochecknoglobals // unexported and used only in tests testStoreKey = storetypes.NewKVStoreKey("state-transition-tests") //nolint:gochecknoglobals // exported but used only in tests DummyProposerAddr = []byte{0xff} ) func BuildTestStores() ( storetypes.CommitMultiStore, *beacondb.KVStore, deposit.StoreManager, error, ) { appDB, err := db.OpenDB("app", dbm.MemDBBackend) if err != nil { return nil, nil, nil, fmt.Errorf("failed opening mem app db: %w", err) } depositsDB, err := db.OpenDB("deposits", dbm.MemDBBackend) if err != nil { return nil, nil, nil, fmt.Errorf("failed opening mem deposits db: %w", err) } var ( nopLog = log.NewNopLogger() nopMetrics = metrics.NewNoOpMetrics() ) cms := store.NewCommitMultiStore( appDB, nopLog, nopMetrics, ) cms.MountStoreWithDB(testStoreKey, storetypes.StoreTypeIAVL, nil) if err = cms.LoadLatestVersion(); err != nil { return nil, nil, nil, fmt.Errorf("failed to load latest version: %w", err) } depositStore := deposit.NewStore(depositsDB, nopLog) return cms, beacondb.New(&testKVStoreService{}), depositStore, nil } func SetupTestState(t *testing.T, cs chain.Spec) ( *TestStateProcessorT, *TestBeaconStateT, deposit.StoreManager, core.ReadOnlyContext, storetypes.CommitMultiStore, *mocks.ExecutionEngine, ) { t.Helper() execEngine := mocks.NewExecutionEngine(t) mocksSigner := &cryptomocks.Blssigner{} mocksSigner.On( "VerifySignature", mock.Anything, mock.Anything, mock.Anything, ).Return(nil) cms, kvStore, depositStore, err := BuildTestStores() require.NoError(t, err) sdkCtx := sdk.NewContext(cms.CacheMultiStore(), true, log.NewNopLogger()) beaconState := statedb.NewBeaconStateFromDB( kvStore.WithContext(sdkCtx), cs, sdkCtx.Logger(), nodemetrics.NewNoOpTelemetrySink(), ) sp := core.NewStateProcessor( noop.NewLogger[any](), cs, execEngine, depositStore, mocksSigner, func(bytes.B48) ([]byte, error) { return DummyProposerAddr, nil }, nodemetrics.NewNoOpTelemetrySink(), ) // by default we keep checks at minimum. It is up // to single tests to redefine the ctx along their needs. ctx := transition.NewTransitionCtx( sdkCtx, 0, // time DummyProposerAddr, ). WithVerifyPayload(false). WithVerifyRandao(false). WithVerifyResult(false). WithMeterGas(false) return sp, beaconState, depositStore, ctx, cms, execEngine } ================================================ FILE: testing/utils/.gitkeep ================================================ TODO: put general testing utilities in here. ================================================ FILE: testing/utils/generate.go ================================================ // SPDX-License-Identifier: BUSL-1.1 // // Copyright (C) 2025, Berachain Foundation. All rights reserved. // Use of this software is governed by the Business Source License included // in the LICENSE file of this repository and at www.mariadb.com/bsl11. // // ANY USE OF THE LICENSED WORK IN VIOLATION OF THIS LICENSE WILL AUTOMATICALLY // TERMINATE YOUR RIGHTS UNDER THIS LICENSE FOR THE CURRENT AND ALL OTHER // VERSIONS OF THE LICENSED WORK. // // THIS LICENSE DOES NOT GRANT YOU ANY RIGHT IN ANY TRADEMARK OR LOGO OF // LICENSOR OR ITS AFFILIATES (PROVIDED THAT YOU MAY USE A TRADEMARK OR LOGO OF // LICENSOR AS EXPRESSLY REQUIRED BY THIS LICENSE). // // TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON // AN “AS IS” BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, // EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND // TITLE. //go:build test package utils import ( "testing" "github.com/berachain/beacon-kit/consensus-types/types" engineprimitives "github.com/berachain/beacon-kit/engine-primitives/engine-primitives" "github.com/berachain/beacon-kit/primitives/bytes" "github.com/berachain/beacon-kit/primitives/common" "github.com/berachain/beacon-kit/primitives/crypto" "github.com/berachain/beacon-kit/primitives/eip4844" "github.com/berachain/beacon-kit/primitives/math" "github.com/berachain/beacon-kit/primitives/version" "github.com/stretchr/testify/require" ) // GenerateValidBeaconBlock generates a valid beacon block for the Deneb. func GenerateValidBeaconBlock(t *testing.T, forkVersion common.Version) *types.BeaconBlock { t.Helper() // Initialize your block here beaconBlock, err := types.NewBeaconBlockWithVersion( math.Slot(10), //nolint:mnd // dummy value math.ValidatorIndex(5), //nolint:mnd // dummy value common.Root{1, 2, 3, 4, 5}, // parent block root forkVersion, ) require.NoError(t, err) versionable := types.NewVersionable(forkVersion) beaconBlock.StateRoot = common.Root{5, 4, 3, 2, 1} beaconBlock.Body = &types.BeaconBlockBody{ Versionable: versionable, ExecutionPayload: &types.ExecutionPayload{ Versionable: versionable, Timestamp: 10, //nolint:mnd // dummy value ExtraData: []byte("dummy extra data for testing"), Transactions: [][]byte{ []byte("0x"), []byte("0x"), []byte("0x"), }, Withdrawals: engineprimitives.Withdrawals{ {Index: 0, Amount: 100}, //nolint:mnd // dummy value {Index: 1, Amount: 200}, //nolint:mnd // dummy value }, BaseFeePerGas: math.NewU256(0), }, Eth1Data: &types.Eth1Data{}, Deposits: []*types.Deposit{ { Index: 1, }, }, BlobKzgCommitments: []eip4844.KZGCommitment{ {1, 2, 3}, }, } body := beaconBlock.GetBody() body.SetProposerSlashings(types.ProposerSlashings{}) body.SetAttesterSlashings(types.AttesterSlashings{}) body.SetAttestations(types.Attestations{}) body.SetSyncAggregate(&types.SyncAggregate{}) body.SetVoluntaryExits(types.VoluntaryExits{}) body.SetBlsToExecutionChanges(types.BlsToExecutionChanges{}) if version.EqualsOrIsAfter(forkVersion, version.Electra()) { err = body.SetExecutionRequests(&types.ExecutionRequests{ Deposits: []*types.DepositRequest{ { Pubkey: crypto.BLSPubkey{1, 2, 3}, Credentials: types.WithdrawalCredentials(bytes.B32{4, 5, 6}), Amount: 100, //nolint:mnd // dummy value Signature: crypto.BLSSignature{1, 2, 3}, Index: 1, }, }, Withdrawals: []*types.WithdrawalRequest{ { SourceAddress: common.ExecutionAddress{0, 1, 2, 3, 4, 5}, ValidatorPubKey: crypto.BLSPubkey{4, 2, 0}, // Amount: 1000, // nolint:mnd // dummy value }, }, Consolidations: []*types.ConsolidationRequest{}, }) require.NoError(t, err) } return beaconBlock }